diff options
author | Kim Kibum <kb0929.kim@samsung.com> | 2012-04-29 16:59:19 +0900 |
---|---|---|
committer | Kim Kibum <kb0929.kim@samsung.com> | 2012-04-29 16:59:19 +0900 |
commit | c1775d1a93a77a57380a4ce87ac3a8f807c944b2 (patch) | |
tree | e1f233f2af38ee247a677082198dd3a69a12a5a1 /include/net | |
parent | 2c2dcd5ffef2e97176e6a55e45512177e55e6fb9 (diff) | |
download | linux-2.6.36-c1775d1a93a77a57380a4ce87ac3a8f807c944b2.tar.gz linux-2.6.36-c1775d1a93a77a57380a4ce87ac3a8f807c944b2.tar.bz2 linux-2.6.36-c1775d1a93a77a57380a4ce87ac3a8f807c944b2.zip |
Diffstat (limited to 'include/net')
238 files changed, 48239 insertions, 0 deletions
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h new file mode 100644 index 00000000..a8de812c --- /dev/null +++ b/include/net/9p/9p.h @@ -0,0 +1,672 @@ +/* + * include/net/9p/9p.h + * + * 9P protocol definitions. + * + * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net> + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#ifndef NET_9P_H +#define NET_9P_H + +/** + * enum p9_debug_flags - bits for mount time debug parameter + * @P9_DEBUG_ERROR: more verbose error messages including original error string + * @P9_DEBUG_9P: 9P protocol tracing + * @P9_DEBUG_VFS: VFS API tracing + * @P9_DEBUG_CONV: protocol conversion tracing + * @P9_DEBUG_MUX: trace management of concurrent transactions + * @P9_DEBUG_TRANS: transport tracing + * @P9_DEBUG_SLABS: memory management tracing + * @P9_DEBUG_FCALL: verbose dump of protocol messages + * @P9_DEBUG_FID: fid allocation/deallocation tracking + * @P9_DEBUG_PKT: packet marshalling/unmarshalling + * @P9_DEBUG_FSC: FS-cache tracing + * + * These flags are passed at mount time to turn on various levels of + * verbosity and tracing which will be output to the system logs. + */ + +enum p9_debug_flags { + P9_DEBUG_ERROR = (1<<0), + P9_DEBUG_9P = (1<<2), + P9_DEBUG_VFS = (1<<3), + P9_DEBUG_CONV = (1<<4), + P9_DEBUG_MUX = (1<<5), + P9_DEBUG_TRANS = (1<<6), + P9_DEBUG_SLABS = (1<<7), + P9_DEBUG_FCALL = (1<<8), + P9_DEBUG_FID = (1<<9), + P9_DEBUG_PKT = (1<<10), + P9_DEBUG_FSC = (1<<11), +}; + +#ifdef CONFIG_NET_9P_DEBUG +extern unsigned int p9_debug_level; + +#define P9_DPRINTK(level, format, arg...) \ +do { \ + if ((p9_debug_level & level) == level) {\ + if (level == P9_DEBUG_9P) \ + printk(KERN_NOTICE "(%8.8d) " \ + format , task_pid_nr(current) , ## arg); \ + else \ + printk(KERN_NOTICE "-- %s (%d): " \ + format , __func__, task_pid_nr(current) , ## arg); \ + } \ +} while (0) + +#else +#define P9_DPRINTK(level, format, arg...) do { } while (0) +#endif + +#define P9_EPRINTK(level, format, arg...) \ +do { \ + printk(level "9p: %s (%d): " \ + format , __func__, task_pid_nr(current), ## arg); \ +} while (0) + +/** + * enum p9_msg_t - 9P message types + * @P9_TSTATFS: file system status request + * @P9_RSTATFS: file system status response + * @P9_TSYMLINK: make symlink request + * @P9_RSYMLINK: make symlink response + * @P9_TMKNOD: create a special file object request + * @P9_RMKNOD: create a special file object response + * @P9_TLCREATE: prepare a handle for I/O on an new file for 9P2000.L + * @P9_RLCREATE: response with file access information for 9P2000.L + * @P9_TRENAME: rename request + * @P9_RRENAME: rename response + * @P9_TMKDIR: create a directory request + * @P9_RMKDIR: create a directory response + * @P9_TVERSION: version handshake request + * @P9_RVERSION: version handshake response + * @P9_TAUTH: request to establish authentication channel + * @P9_RAUTH: response with authentication information + * @P9_TATTACH: establish user access to file service + * @P9_RATTACH: response with top level handle to file hierarchy + * @P9_TERROR: not used + * @P9_RERROR: response for any failed request + * @P9_TFLUSH: request to abort a previous request + * @P9_RFLUSH: response when previous request has been cancelled + * @P9_TWALK: descend a directory hierarchy + * @P9_RWALK: response with new handle for position within hierarchy + * @P9_TOPEN: prepare a handle for I/O on an existing file + * @P9_ROPEN: response with file access information + * @P9_TCREATE: prepare a handle for I/O on a new file + * @P9_RCREATE: response with file access information + * @P9_TREAD: request to transfer data from a file or directory + * @P9_RREAD: response with data requested + * @P9_TWRITE: reuqest to transfer data to a file + * @P9_RWRITE: response with out much data was transfered to file + * @P9_TCLUNK: forget about a handle to an entity within the file system + * @P9_RCLUNK: response when server has forgotten about the handle + * @P9_TREMOVE: request to remove an entity from the hierarchy + * @P9_RREMOVE: response when server has removed the entity + * @P9_TSTAT: request file entity attributes + * @P9_RSTAT: response with file entity attributes + * @P9_TWSTAT: request to update file entity attributes + * @P9_RWSTAT: response when file entity attributes are updated + * + * There are 14 basic operations in 9P2000, paired as + * requests and responses. The one special case is ERROR + * as there is no @P9_TERROR request for clients to transmit to + * the server, but the server may respond to any other request + * with an @P9_RERROR. + * + * See Also: http://plan9.bell-labs.com/sys/man/5/INDEX.html + */ + +enum p9_msg_t { + P9_TSTATFS = 8, + P9_RSTATFS, + P9_TLOPEN = 12, + P9_RLOPEN, + P9_TLCREATE = 14, + P9_RLCREATE, + P9_TSYMLINK = 16, + P9_RSYMLINK, + P9_TMKNOD = 18, + P9_RMKNOD, + P9_TRENAME = 20, + P9_RRENAME, + P9_TGETATTR = 24, + P9_RGETATTR, + P9_TSETATTR = 26, + P9_RSETATTR, + P9_TXATTRWALK = 30, + P9_RXATTRWALK, + P9_TXATTRCREATE = 32, + P9_RXATTRCREATE, + P9_TREADDIR = 40, + P9_RREADDIR, + P9_TLINK = 70, + P9_RLINK, + P9_TMKDIR = 72, + P9_RMKDIR, + P9_TVERSION = 100, + P9_RVERSION, + P9_TAUTH = 102, + P9_RAUTH, + P9_TATTACH = 104, + P9_RATTACH, + P9_TERROR = 106, + P9_RERROR, + P9_TFLUSH = 108, + P9_RFLUSH, + P9_TWALK = 110, + P9_RWALK, + P9_TOPEN = 112, + P9_ROPEN, + P9_TCREATE = 114, + P9_RCREATE, + P9_TREAD = 116, + P9_RREAD, + P9_TWRITE = 118, + P9_RWRITE, + P9_TCLUNK = 120, + P9_RCLUNK, + P9_TREMOVE = 122, + P9_RREMOVE, + P9_TSTAT = 124, + P9_RSTAT, + P9_TWSTAT = 126, + P9_RWSTAT, +}; + +/** + * enum p9_open_mode_t - 9P open modes + * @P9_OREAD: open file for reading only + * @P9_OWRITE: open file for writing only + * @P9_ORDWR: open file for reading or writing + * @P9_OEXEC: open file for execution + * @P9_OTRUNC: truncate file to zero-length before opening it + * @P9_OREXEC: close the file when an exec(2) system call is made + * @P9_ORCLOSE: remove the file when the file is closed + * @P9_OAPPEND: open the file and seek to the end + * @P9_OEXCL: only create a file, do not open it + * + * 9P open modes differ slightly from Posix standard modes. + * In particular, there are extra modes which specify different + * semantic behaviors than may be available on standard Posix + * systems. For example, @P9_OREXEC and @P9_ORCLOSE are modes that + * most likely will not be issued from the Linux VFS client, but may + * be supported by servers. + * + * See Also: http://plan9.bell-labs.com/magic/man2html/2/open + */ + +enum p9_open_mode_t { + P9_OREAD = 0x00, + P9_OWRITE = 0x01, + P9_ORDWR = 0x02, + P9_OEXEC = 0x03, + P9_OTRUNC = 0x10, + P9_OREXEC = 0x20, + P9_ORCLOSE = 0x40, + P9_OAPPEND = 0x80, + P9_OEXCL = 0x1000, +}; + +/** + * enum p9_perm_t - 9P permissions + * @P9_DMDIR: mode bite for directories + * @P9_DMAPPEND: mode bit for is append-only + * @P9_DMEXCL: mode bit for excluse use (only one open handle allowed) + * @P9_DMMOUNT: mode bite for mount points + * @P9_DMAUTH: mode bit for authentication file + * @P9_DMTMP: mode bit for non-backed-up files + * @P9_DMSYMLINK: mode bit for symbolic links (9P2000.u) + * @P9_DMLINK: mode bit for hard-link (9P2000.u) + * @P9_DMDEVICE: mode bit for device files (9P2000.u) + * @P9_DMNAMEDPIPE: mode bit for named pipe (9P2000.u) + * @P9_DMSOCKET: mode bit for socket (9P2000.u) + * @P9_DMSETUID: mode bit for setuid (9P2000.u) + * @P9_DMSETGID: mode bit for setgid (9P2000.u) + * @P9_DMSETVTX: mode bit for sticky bit (9P2000.u) + * + * 9P permissions differ slightly from Posix standard modes. + * + * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat + */ +enum p9_perm_t { + P9_DMDIR = 0x80000000, + P9_DMAPPEND = 0x40000000, + P9_DMEXCL = 0x20000000, + P9_DMMOUNT = 0x10000000, + P9_DMAUTH = 0x08000000, + P9_DMTMP = 0x04000000, +/* 9P2000.u extensions */ + P9_DMSYMLINK = 0x02000000, + P9_DMLINK = 0x01000000, + P9_DMDEVICE = 0x00800000, + P9_DMNAMEDPIPE = 0x00200000, + P9_DMSOCKET = 0x00100000, + P9_DMSETUID = 0x00080000, + P9_DMSETGID = 0x00040000, + P9_DMSETVTX = 0x00010000, +}; + +/** + * enum p9_qid_t - QID types + * @P9_QTDIR: directory + * @P9_QTAPPEND: append-only + * @P9_QTEXCL: excluse use (only one open handle allowed) + * @P9_QTMOUNT: mount points + * @P9_QTAUTH: authentication file + * @P9_QTTMP: non-backed-up files + * @P9_QTSYMLINK: symbolic links (9P2000.u) + * @P9_QTLINK: hard-link (9P2000.u) + * @P9_QTFILE: normal files + * + * QID types are a subset of permissions - they are primarily + * used to differentiate semantics for a file system entity via + * a jump-table. Their value is also the most signifigant 16 bits + * of the permission_t + * + * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat + */ +enum p9_qid_t { + P9_QTDIR = 0x80, + P9_QTAPPEND = 0x40, + P9_QTEXCL = 0x20, + P9_QTMOUNT = 0x10, + P9_QTAUTH = 0x08, + P9_QTTMP = 0x04, + P9_QTSYMLINK = 0x02, + P9_QTLINK = 0x01, + P9_QTFILE = 0x00, +}; + +/* 9P Magic Numbers */ +#define P9_NOTAG (u16)(~0) +#define P9_NOFID (u32)(~0) +#define P9_MAXWELEM 16 + +/* ample room for Twrite/Rread header */ +#define P9_IOHDRSZ 24 + +/* Room for readdir header */ +#define P9_READDIRHDRSZ 24 + +/** + * struct p9_str - length prefixed string type + * @len: length of the string + * @str: the string + * + * The protocol uses length prefixed strings for all + * string data, so we replicate that for our internal + * string members. + */ + +struct p9_str { + u16 len; + char *str; +}; + +/** + * struct p9_qid - file system entity information + * @type: 8-bit type &p9_qid_t + * @version: 16-bit monotonically incrementing version number + * @path: 64-bit per-server-unique ID for a file system element + * + * qids are identifiers used by 9P servers to track file system + * entities. The type is used to differentiate semantics for operations + * on the entity (ie. read means something different on a directory than + * on a file). The path provides a server unique index for an entity + * (roughly analogous to an inode number), while the version is updated + * every time a file is modified and can be used to maintain cache + * coherency between clients and serves. + * Servers will often differentiate purely synthetic entities by setting + * their version to 0, signaling that they should never be cached and + * should be accessed synchronously. + * + * See Also://plan9.bell-labs.com/magic/man2html/2/stat + */ + +struct p9_qid { + u8 type; + u32 version; + u64 path; +}; + +/** + * struct p9_stat - file system metadata information + * @size: length prefix for this stat structure instance + * @type: the type of the server (equivilent to a major number) + * @dev: the sub-type of the server (equivilent to a minor number) + * @qid: unique id from the server of type &p9_qid + * @mode: Plan 9 format permissions of type &p9_perm_t + * @atime: Last access/read time + * @mtime: Last modify/write time + * @length: file length + * @name: last element of path (aka filename) in type &p9_str + * @uid: owner name in type &p9_str + * @gid: group owner in type &p9_str + * @muid: last modifier in type &p9_str + * @extension: area used to encode extended UNIX support in type &p9_str + * @n_uid: numeric user id of owner (part of 9p2000.u extension) + * @n_gid: numeric group id (part of 9p2000.u extension) + * @n_muid: numeric user id of laster modifier (part of 9p2000.u extension) + * + * See Also: http://plan9.bell-labs.com/magic/man2html/2/stat + */ + +struct p9_wstat { + u16 size; + u16 type; + u32 dev; + struct p9_qid qid; + u32 mode; + u32 atime; + u32 mtime; + u64 length; + char *name; + char *uid; + char *gid; + char *muid; + char *extension; /* 9p2000.u extensions */ + u32 n_uid; /* 9p2000.u extensions */ + u32 n_gid; /* 9p2000.u extensions */ + u32 n_muid; /* 9p2000.u extensions */ +}; + +struct p9_stat_dotl { + u64 st_result_mask; + struct p9_qid qid; + u32 st_mode; + u32 st_uid; + u32 st_gid; + u64 st_nlink; + u64 st_rdev; + u64 st_size; + u64 st_blksize; + u64 st_blocks; + u64 st_atime_sec; + u64 st_atime_nsec; + u64 st_mtime_sec; + u64 st_mtime_nsec; + u64 st_ctime_sec; + u64 st_ctime_nsec; + u64 st_btime_sec; + u64 st_btime_nsec; + u64 st_gen; + u64 st_data_version; +}; + +#define P9_STATS_MODE 0x00000001ULL +#define P9_STATS_NLINK 0x00000002ULL +#define P9_STATS_UID 0x00000004ULL +#define P9_STATS_GID 0x00000008ULL +#define P9_STATS_RDEV 0x00000010ULL +#define P9_STATS_ATIME 0x00000020ULL +#define P9_STATS_MTIME 0x00000040ULL +#define P9_STATS_CTIME 0x00000080ULL +#define P9_STATS_INO 0x00000100ULL +#define P9_STATS_SIZE 0x00000200ULL +#define P9_STATS_BLOCKS 0x00000400ULL + +#define P9_STATS_BTIME 0x00000800ULL +#define P9_STATS_GEN 0x00001000ULL +#define P9_STATS_DATA_VERSION 0x00002000ULL + +#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */ +#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */ + +/** + * struct p9_iattr_dotl - P9 inode attribute for setattr + * @valid: bitfield specifying which fields are valid + * same as in struct iattr + * @mode: File permission bits + * @uid: user id of owner + * @gid: group id + * @size: File size + * @atime_sec: Last access time, seconds + * @atime_nsec: Last access time, nanoseconds + * @mtime_sec: Last modification time, seconds + * @mtime_nsec: Last modification time, nanoseconds + */ + +struct p9_iattr_dotl { + u32 valid; + u32 mode; + u32 uid; + u32 gid; + u64 size; + u64 atime_sec; + u64 atime_nsec; + u64 mtime_sec; + u64 mtime_nsec; +}; + +/* Structures for Protocol Operations */ +struct p9_tstatfs { + u32 fid; +}; + +struct p9_rstatfs { + u32 type; + u32 bsize; + u64 blocks; + u64 bfree; + u64 bavail; + u64 files; + u64 ffree; + u64 fsid; + u32 namelen; +}; + +struct p9_trename { + u32 fid; + u32 newdirfid; + struct p9_str name; +}; + +struct p9_rrename { +}; + +struct p9_tversion { + u32 msize; + struct p9_str version; +}; + +struct p9_rversion { + u32 msize; + struct p9_str version; +}; + +struct p9_tauth { + u32 afid; + struct p9_str uname; + struct p9_str aname; + u32 n_uname; /* 9P2000.u extensions */ +}; + +struct p9_rauth { + struct p9_qid qid; +}; + +struct p9_rerror { + struct p9_str error; + u32 errno; /* 9p2000.u extension */ +}; + +struct p9_tflush { + u16 oldtag; +}; + +struct p9_rflush { +}; + +struct p9_tattach { + u32 fid; + u32 afid; + struct p9_str uname; + struct p9_str aname; + u32 n_uname; /* 9P2000.u extensions */ +}; + +struct p9_rattach { + struct p9_qid qid; +}; + +struct p9_twalk { + u32 fid; + u32 newfid; + u16 nwname; + struct p9_str wnames[16]; +}; + +struct p9_rwalk { + u16 nwqid; + struct p9_qid wqids[16]; +}; + +struct p9_topen { + u32 fid; + u8 mode; +}; + +struct p9_ropen { + struct p9_qid qid; + u32 iounit; +}; + +struct p9_tcreate { + u32 fid; + struct p9_str name; + u32 perm; + u8 mode; + struct p9_str extension; +}; + +struct p9_rcreate { + struct p9_qid qid; + u32 iounit; +}; + +struct p9_tread { + u32 fid; + u64 offset; + u32 count; +}; + +struct p9_rread { + u32 count; + u8 *data; +}; + +struct p9_twrite { + u32 fid; + u64 offset; + u32 count; + u8 *data; +}; + +struct p9_rwrite { + u32 count; +}; + +struct p9_treaddir { + u32 fid; + u64 offset; + u32 count; +}; + +struct p9_rreaddir { + u32 count; + u8 *data; +}; + + +struct p9_tclunk { + u32 fid; +}; + +struct p9_rclunk { +}; + +struct p9_tremove { + u32 fid; +}; + +struct p9_rremove { +}; + +struct p9_tstat { + u32 fid; +}; + +struct p9_rstat { + struct p9_wstat stat; +}; + +struct p9_twstat { + u32 fid; + struct p9_wstat stat; +}; + +struct p9_rwstat { +}; + +/** + * struct p9_fcall - primary packet structure + * @size: prefixed length of the structure + * @id: protocol operating identifier of type &p9_msg_t + * @tag: transaction id of the request + * @offset: used by marshalling routines to track currentposition in buffer + * @capacity: used by marshalling routines to track total capacity + * @sdata: payload + * + * &p9_fcall represents the structure for all 9P RPC + * transactions. Requests are packaged into fcalls, and reponses + * must be extracted from them. + * + * See Also: http://plan9.bell-labs.com/magic/man2html/2/fcall + */ + +struct p9_fcall { + u32 size; + u8 id; + u16 tag; + + size_t offset; + size_t capacity; + + uint8_t *sdata; +}; + +struct p9_idpool; + +int p9_errstr2errno(char *errstr, int len); + +struct p9_idpool *p9_idpool_create(void); +void p9_idpool_destroy(struct p9_idpool *); +int p9_idpool_get(struct p9_idpool *p); +void p9_idpool_put(int id, struct p9_idpool *p); +int p9_idpool_check(int id, struct p9_idpool *p); + +int p9_error_init(void); +int p9_errstr2errno(char *, int); +int p9_trans_fd_init(void); +void p9_trans_fd_exit(void); +#endif /* NET_9P_H */ diff --git a/include/net/9p/client.h b/include/net/9p/client.h new file mode 100644 index 00000000..d1aa2cfb --- /dev/null +++ b/include/net/9p/client.h @@ -0,0 +1,266 @@ +/* + * include/net/9p/client.h + * + * 9P Client Definitions + * + * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#ifndef NET_9P_CLIENT_H +#define NET_9P_CLIENT_H + +/* Number of requests per row */ +#define P9_ROW_MAXTAG 255 + +/** enum p9_proto_versions - 9P protocol versions + * @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u + * @p9_proto_2000u: 9P2000.u extension + * @p9_proto_2000L: 9P2000.L extension + */ + +enum p9_proto_versions{ + p9_proto_legacy = 0, + p9_proto_2000u = 1, + p9_proto_2000L = 2, +}; + + +/** + * enum p9_trans_status - different states of underlying transports + * @Connected: transport is connected and healthy + * @Disconnected: transport has been disconnected + * @Hung: transport is connected by wedged + * + * This enumeration details the various states a transport + * instatiation can be in. + */ + +enum p9_trans_status { + Connected, + BeginDisconnect, + Disconnected, + Hung, +}; + +/** + * enum p9_req_status_t - virtio request status + * @REQ_STATUS_IDLE: request slot unused + * @REQ_STATUS_ALLOC: request has been allocated but not sent + * @REQ_STATUS_UNSENT: request waiting to be sent + * @REQ_STATUS_SENT: request sent to server + * @REQ_STATUS_FLSH: a flush has been sent for this request + * @REQ_STATUS_RCVD: response received from server + * @REQ_STATUS_FLSHD: request has been flushed + * @REQ_STATUS_ERROR: request encountered an error on the client side + * + * The @REQ_STATUS_IDLE state is used to mark a request slot as unused + * but use is actually tracked by the idpool structure which handles tag + * id allocation. + * + */ + +enum p9_req_status_t { + REQ_STATUS_IDLE, + REQ_STATUS_ALLOC, + REQ_STATUS_UNSENT, + REQ_STATUS_SENT, + REQ_STATUS_FLSH, + REQ_STATUS_RCVD, + REQ_STATUS_FLSHD, + REQ_STATUS_ERROR, +}; + +/** + * struct p9_req_t - request slots + * @status: status of this request slot + * @t_err: transport error + * @flush_tag: tag of request being flushed (for flush requests) + * @wq: wait_queue for the client to block on for this request + * @tc: the request fcall structure + * @rc: the response fcall structure + * @aux: transport specific data (provided for trans_fd migration) + * @req_list: link for higher level objects to chain requests + * + * Transport use an array to track outstanding requests + * instead of a list. While this may incurr overhead during initial + * allocation or expansion, it makes request lookup much easier as the + * tag id is a index into an array. (We use tag+1 so that we can accomodate + * the -1 tag for the T_VERSION request). + * This also has the nice effect of only having to allocate wait_queues + * once, instead of constantly allocating and freeing them. Its possible + * other resources could benefit from this scheme as well. + * + */ + +struct p9_req_t { + int status; + int t_err; + wait_queue_head_t *wq; + struct p9_fcall *tc; + struct p9_fcall *rc; + void *aux; + + struct list_head req_list; +}; + +/** + * struct p9_client - per client instance state + * @lock: protect @fidlist + * @msize: maximum data size negotiated by protocol + * @dotu: extension flags negotiated by protocol + * @proto_version: 9P protocol version to use + * @trans_mod: module API instantiated with this client + * @trans: tranport instance state and API + * @conn: connection state information used by trans_fd + * @fidpool: fid handle accounting for session + * @fidlist: List of active fid handles + * @tagpool - transaction id accounting for session + * @reqs - 2D array of requests + * @max_tag - current maximum tag id allocated + * + * The client structure is used to keep track of various per-client + * state that has been instantiated. + * In order to minimize per-transaction overhead we use a + * simple array to lookup requests instead of a hash table + * or linked list. In order to support larger number of + * transactions, we make this a 2D array, allocating new rows + * when we need to grow the total number of the transactions. + * + * Each row is 256 requests and we'll support up to 256 rows for + * a total of 64k concurrent requests per session. + * + * Bugs: duplicated data and potentially unnecessary elements. + */ + +struct p9_client { + spinlock_t lock; /* protect client structure */ + int msize; + unsigned char proto_version; + struct p9_trans_module *trans_mod; + enum p9_trans_status status; + void *trans; + struct p9_conn *conn; + + struct p9_idpool *fidpool; + struct list_head fidlist; + + struct p9_idpool *tagpool; + struct p9_req_t *reqs[P9_ROW_MAXTAG]; + int max_tag; +}; + +/** + * struct p9_fid - file system entity handle + * @clnt: back pointer to instantiating &p9_client + * @fid: numeric identifier for this handle + * @mode: current mode of this fid (enum?) + * @qid: the &p9_qid server identifier this handle points to + * @iounit: the server reported maximum transaction size for this file + * @uid: the numeric uid of the local user who owns this handle + * @rdir: readdir accounting structure (allocated on demand) + * @flist: per-client-instance fid tracking + * @dlist: per-dentry fid tracking + * + * TODO: This needs lots of explanation. + */ + +struct p9_fid { + struct p9_client *clnt; + u32 fid; + int mode; + struct p9_qid qid; + u32 iounit; + uid_t uid; + + void *rdir; + + struct list_head flist; + struct list_head dlist; /* list of all fids attached to a dentry */ +}; + +/** + * struct p9_dirent - directory entry structure + * @qid: The p9 server qid for this dirent + * @d_off: offset to the next dirent + * @d_type: type of file + * @d_name: file name + */ + +struct p9_dirent { + struct p9_qid qid; + u64 d_off; + unsigned char d_type; + char d_name[256]; +}; + +int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); +int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name); +int p9_client_version(struct p9_client *); +struct p9_client *p9_client_create(const char *dev_name, char *options); +void p9_client_destroy(struct p9_client *clnt); +void p9_client_disconnect(struct p9_client *clnt); +void p9_client_begin_disconnect(struct p9_client *clnt); +struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, + char *uname, u32 n_uname, char *aname); +struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, + u32 n_uname, char *aname); +struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, + int clone); +int p9_client_open(struct p9_fid *fid, int mode); +int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, + char *extension); +int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); +int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, + struct p9_qid *qid); +int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, + gid_t gid, struct p9_qid *qid); +int p9_client_clunk(struct p9_fid *fid); +int p9_client_remove(struct p9_fid *fid); +int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, + u64 offset, u32 count); +int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, + u64 offset, u32 count); +int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset); +int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, + int proto_version); +struct p9_wstat *p9_client_stat(struct p9_fid *fid); +int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); +int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *attr); + +struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, + u64 request_mask); + +int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode, + dev_t rdev, gid_t gid, struct p9_qid *); +int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, + gid_t gid, struct p9_qid *); +struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); +void p9_client_cb(struct p9_client *c, struct p9_req_t *req); + +int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int); +int p9stat_read(char *, int, struct p9_wstat *, int); +void p9stat_free(struct p9_wstat *); + +int p9_is_proto_dotu(struct p9_client *clnt); +int p9_is_proto_dotl(struct p9_client *clnt); +struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *); +int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int); + +#endif /* NET_9P_CLIENT_H */ diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h new file mode 100644 index 00000000..6d5886ef --- /dev/null +++ b/include/net/9p/transport.h @@ -0,0 +1,63 @@ +/* + * include/net/9p/transport.h + * + * Transport Definition + * + * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net> + * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#ifndef NET_9P_TRANSPORT_H +#define NET_9P_TRANSPORT_H + +/** + * struct p9_trans_module - transport module interface + * @list: used to maintain a list of currently available transports + * @name: the human-readable name of the transport + * @maxsize: transport provided maximum packet size + * @def: set if this transport should be considered the default + * @create: member function to create a new connection on this transport + * @request: member function to issue a request to the transport + * @cancel: member function to cancel a request (if it hasn't been sent) + * + * This is the basic API for a transport module which is registered by the + * transport module with the 9P core network module and used by the client + * to instantiate a new connection on a transport. + * + * BUGS: the transport module list isn't protected. + */ + +struct p9_trans_module { + struct list_head list; + char *name; /* name of transport */ + int maxsize; /* max message size of transport */ + int def; /* this transport should be default */ + struct module *owner; + int (*create)(struct p9_client *, const char *, char *); + void (*close) (struct p9_client *); + int (*request) (struct p9_client *, struct p9_req_t *req); + int (*cancel) (struct p9_client *, struct p9_req_t *req); +}; + +void v9fs_register_trans(struct p9_trans_module *m); +void v9fs_unregister_trans(struct p9_trans_module *m); +struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name); +struct p9_trans_module *v9fs_get_default_trans(void); +void v9fs_put_trans(struct p9_trans_module *m); +#endif /* NET_9P_TRANSPORT_H */ diff --git a/include/net/act_api.h b/include/net/act_api.h new file mode 100644 index 00000000..bab385f1 --- /dev/null +++ b/include/net/act_api.h @@ -0,0 +1,126 @@ +#ifndef __NET_ACT_API_H +#define __NET_ACT_API_H + +/* + * Public police action API for classifiers/qdiscs + */ + +#include <net/sch_generic.h> +#include <net/pkt_sched.h> + +struct tcf_common { + struct tcf_common *tcfc_next; + u32 tcfc_index; + int tcfc_refcnt; + int tcfc_bindcnt; + u32 tcfc_capab; + int tcfc_action; + struct tcf_t tcfc_tm; + struct gnet_stats_basic_packed tcfc_bstats; + struct gnet_stats_queue tcfc_qstats; + struct gnet_stats_rate_est tcfc_rate_est; + spinlock_t tcfc_lock; + struct rcu_head tcfc_rcu; +}; +#define tcf_next common.tcfc_next +#define tcf_index common.tcfc_index +#define tcf_refcnt common.tcfc_refcnt +#define tcf_bindcnt common.tcfc_bindcnt +#define tcf_capab common.tcfc_capab +#define tcf_action common.tcfc_action +#define tcf_tm common.tcfc_tm +#define tcf_bstats common.tcfc_bstats +#define tcf_qstats common.tcfc_qstats +#define tcf_rate_est common.tcfc_rate_est +#define tcf_lock common.tcfc_lock +#define tcf_rcu common.tcfc_rcu + +struct tcf_police { + struct tcf_common common; + int tcfp_result; + u32 tcfp_ewma_rate; + u32 tcfp_burst; + u32 tcfp_mtu; + u32 tcfp_toks; + u32 tcfp_ptoks; + psched_time_t tcfp_t_c; + struct qdisc_rate_table *tcfp_R_tab; + struct qdisc_rate_table *tcfp_P_tab; +}; +#define to_police(pc) \ + container_of(pc, struct tcf_police, common) + +struct tcf_hashinfo { + struct tcf_common **htab; + unsigned int hmask; + rwlock_t *lock; +}; + +static inline unsigned int tcf_hash(u32 index, unsigned int hmask) +{ + return index & hmask; +} + +#ifdef CONFIG_NET_CLS_ACT + +#define ACT_P_CREATED 1 +#define ACT_P_DELETED 1 + +struct tcf_act_hdr { + struct tcf_common common; +}; + +struct tc_action { + void *priv; + struct tc_action_ops *ops; + __u32 type; /* for backward compat(TCA_OLD_COMPAT) */ + __u32 order; + struct tc_action *next; +}; + +#define TCA_CAP_NONE 0 +struct tc_action_ops { + struct tc_action_ops *next; + struct tcf_hashinfo *hinfo; + char kind[IFNAMSIZ]; + __u32 type; /* TBD to match kind */ + __u32 capab; /* capabilities includes 4 bit version */ + struct module *owner; + int (*act)(struct sk_buff *, struct tc_action *, struct tcf_result *); + int (*get_stats)(struct sk_buff *, struct tc_action *); + int (*dump)(struct sk_buff *, struct tc_action *, int, int); + int (*cleanup)(struct tc_action *, int bind); + int (*lookup)(struct tc_action *, u32); + int (*init)(struct nlattr *, struct nlattr *, struct tc_action *, int , int); + int (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *); +}; + +extern struct tcf_common *tcf_hash_lookup(u32 index, + struct tcf_hashinfo *hinfo); +extern void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo); +extern int tcf_hash_release(struct tcf_common *p, int bind, + struct tcf_hashinfo *hinfo); +extern int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, + int type, struct tc_action *a); +extern u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo); +extern int tcf_hash_search(struct tc_action *a, u32 index); +extern struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, + int bind, struct tcf_hashinfo *hinfo); +extern struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, + struct tc_action *a, int size, + int bind, u32 *idx_gen, + struct tcf_hashinfo *hinfo); +extern void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo); + +extern int tcf_register_action(struct tc_action_ops *a); +extern int tcf_unregister_action(struct tc_action_ops *a); +extern void tcf_action_destroy(struct tc_action *a, int bind); +extern int tcf_action_exec(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res); +extern struct tc_action *tcf_action_init(struct nlattr *nla, struct nlattr *est, char *n, int ovr, int bind); +extern struct tc_action *tcf_action_init_1(struct nlattr *nla, struct nlattr *est, char *n, int ovr, int bind); +extern int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int); +extern int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int); +extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int); +extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *, int); +#endif /* CONFIG_NET_CLS_ACT */ +#endif diff --git a/include/net/addrconf.h b/include/net/addrconf.h new file mode 100644 index 00000000..4d40c4d0 --- /dev/null +++ b/include/net/addrconf.h @@ -0,0 +1,269 @@ +#ifndef _ADDRCONF_H +#define _ADDRCONF_H + +#define RETRANS_TIMER HZ + +#define MAX_RTR_SOLICITATIONS 3 +#define RTR_SOLICITATION_INTERVAL (4*HZ) + +#define MIN_VALID_LIFETIME (2*3600) /* 2 hours */ + +#define TEMP_VALID_LIFETIME (7*86400) +#define TEMP_PREFERRED_LIFETIME (86400) +#define REGEN_MAX_RETRY (5) +#define MAX_DESYNC_FACTOR (600) + +#define ADDR_CHECK_FREQUENCY (120*HZ) + +#define IPV6_MAX_ADDRESSES 16 + +#include <linux/in.h> +#include <linux/in6.h> + +struct prefix_info { + __u8 type; + __u8 length; + __u8 prefix_len; + +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 onlink : 1, + autoconf : 1, + reserved : 6; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 reserved : 6, + autoconf : 1, + onlink : 1; +#else +#error "Please fix <asm/byteorder.h>" +#endif + __be32 valid; + __be32 prefered; + __be32 reserved2; + + struct in6_addr prefix; +}; + + +#ifdef __KERNEL__ + +#include <linux/netdevice.h> +#include <net/if_inet6.h> +#include <net/ipv6.h> + +#define IN6_ADDR_HSIZE 16 + +extern int addrconf_init(void); +extern void addrconf_cleanup(void); + +extern int addrconf_add_ifaddr(struct net *net, + void __user *arg); +extern int addrconf_del_ifaddr(struct net *net, + void __user *arg); +extern int addrconf_set_dstaddr(struct net *net, + void __user *arg); + +extern int ipv6_chk_addr(struct net *net, + struct in6_addr *addr, + struct net_device *dev, + int strict); + +#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) +extern int ipv6_chk_home_addr(struct net *net, + struct in6_addr *addr); +#endif + +extern int ipv6_chk_prefix(struct in6_addr *addr, + struct net_device *dev); + +extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, + const struct in6_addr *addr, + struct net_device *dev, + int strict); + +extern int ipv6_dev_get_saddr(struct net *net, + struct net_device *dev, + const struct in6_addr *daddr, + unsigned int srcprefs, + struct in6_addr *saddr); +extern int ipv6_get_lladdr(struct net_device *dev, + struct in6_addr *addr, + unsigned char banned_flags); +extern int ipv6_rcv_saddr_equal(const struct sock *sk, + const struct sock *sk2); +extern void addrconf_join_solict(struct net_device *dev, + struct in6_addr *addr); +extern void addrconf_leave_solict(struct inet6_dev *idev, + struct in6_addr *addr); + +static inline unsigned long addrconf_timeout_fixup(u32 timeout, + unsigned unit) +{ + if (timeout == 0xffffffff) + return ~0UL; + + /* + * Avoid arithmetic overflow. + * Assuming unit is constant and non-zero, this "if" statement + * will go away on 64bit archs. + */ + if (0xfffffffe > LONG_MAX / unit && timeout > LONG_MAX / unit) + return LONG_MAX / unit; + + return timeout; +} + +static inline int addrconf_finite_timeout(unsigned long timeout) +{ + return ~timeout; +} + +/* + * IPv6 Address Label subsystem (addrlabel.c) + */ +extern int ipv6_addr_label_init(void); +extern void ipv6_addr_label_cleanup(void); +extern void ipv6_addr_label_rtnl_register(void); +extern u32 ipv6_addr_label(struct net *net, + const struct in6_addr *addr, + int type, int ifindex); + +/* + * multicast prototypes (mcast.c) + */ +extern int ipv6_sock_mc_join(struct sock *sk, int ifindex, + const struct in6_addr *addr); +extern int ipv6_sock_mc_drop(struct sock *sk, int ifindex, + const struct in6_addr *addr); +extern void ipv6_sock_mc_close(struct sock *sk); +extern int inet6_mc_check(struct sock *sk, + const struct in6_addr *mc_addr, + const struct in6_addr *src_addr); + +extern int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr); +extern int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr); +extern int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr); +extern void ipv6_mc_up(struct inet6_dev *idev); +extern void ipv6_mc_down(struct inet6_dev *idev); +extern void ipv6_mc_unmap(struct inet6_dev *idev); +extern void ipv6_mc_remap(struct inet6_dev *idev); +extern void ipv6_mc_init_dev(struct inet6_dev *idev); +extern void ipv6_mc_destroy_dev(struct inet6_dev *idev); +extern void addrconf_dad_failure(struct inet6_ifaddr *ifp); + +extern int ipv6_chk_mcast_addr(struct net_device *dev, + const struct in6_addr *group, + const struct in6_addr *src_addr); +extern int ipv6_is_mld(struct sk_buff *skb, int nexthdr); + +extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); + +/* + * anycast prototypes (anycast.c) + */ +extern int ipv6_sock_ac_join(struct sock *sk,int ifindex,struct in6_addr *addr); +extern int ipv6_sock_ac_drop(struct sock *sk,int ifindex,struct in6_addr *addr); +extern void ipv6_sock_ac_close(struct sock *sk); +extern int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex); + +extern int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr); +extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr); +extern int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, + struct in6_addr *addr); + + +/* Device notifier */ +extern int register_inet6addr_notifier(struct notifier_block *nb); +extern int unregister_inet6addr_notifier(struct notifier_block *nb); + +static inline struct inet6_dev * +__in6_dev_get(struct net_device *dev) +{ + return rcu_dereference_check(dev->ip6_ptr, + rcu_read_lock_held() || + lockdep_rtnl_is_held()); +} + +static inline struct inet6_dev * +in6_dev_get(struct net_device *dev) +{ + struct inet6_dev *idev = NULL; + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) + atomic_inc(&idev->refcnt); + rcu_read_unlock(); + return idev; +} + +extern void in6_dev_finish_destroy(struct inet6_dev *idev); + +static inline void +in6_dev_put(struct inet6_dev *idev) +{ + if (atomic_dec_and_test(&idev->refcnt)) + in6_dev_finish_destroy(idev); +} + +#define __in6_dev_put(idev) atomic_dec(&(idev)->refcnt) +#define in6_dev_hold(idev) atomic_inc(&(idev)->refcnt) + + +extern void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp); + +static inline void in6_ifa_put(struct inet6_ifaddr *ifp) +{ + if (atomic_dec_and_test(&ifp->refcnt)) + inet6_ifa_finish_destroy(ifp); +} + +#define __in6_ifa_put(ifp) atomic_dec(&(ifp)->refcnt) +#define in6_ifa_hold(ifp) atomic_inc(&(ifp)->refcnt) + + + +/* + * compute link-local solicited-node multicast address + */ + +static inline void addrconf_addr_solict_mult(const struct in6_addr *addr, + struct in6_addr *solicited) +{ + ipv6_addr_set(solicited, + htonl(0xFF020000), 0, + htonl(0x1), + htonl(0xFF000000) | addr->s6_addr32[3]); +} + +static inline int ipv6_addr_is_multicast(const struct in6_addr *addr) +{ + return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); +} + +static inline int ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr) +{ + return (((addr->s6_addr32[0] ^ htonl(0xff020000)) | + addr->s6_addr32[1] | addr->s6_addr32[2] | + (addr->s6_addr32[3] ^ htonl(0x00000001))) == 0); +} + +static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr) +{ + return (((addr->s6_addr32[0] ^ htonl(0xff020000)) | + addr->s6_addr32[1] | addr->s6_addr32[2] | + (addr->s6_addr32[3] ^ htonl(0x00000002))) == 0); +} + +extern int __ipv6_isatap_ifid(u8 *eui, __be32 addr); + +static inline int ipv6_addr_is_isatap(const struct in6_addr *addr) +{ + return ((addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE)); +} + +#ifdef CONFIG_PROC_FS +extern int if6_proc_init(void); +extern void if6_proc_exit(void); +#endif + +#endif +#endif diff --git a/include/net/af_ieee802154.h b/include/net/af_ieee802154.h new file mode 100644 index 00000000..75e64c7a --- /dev/null +++ b/include/net/af_ieee802154.h @@ -0,0 +1,62 @@ +/* + * IEEE 802.15.4 inteface for userspace + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin <slapin@ossfans.org> + * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> + */ + +#ifndef _AF_IEEE802154_H +#define _AF_IEEE802154_H + +#include <linux/socket.h> /* for sa_family_t */ + +enum { + IEEE802154_ADDR_NONE = 0x0, + /* RESERVED = 0x01, */ + IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */ + IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */ +}; + +/* address length, octets */ +#define IEEE802154_ADDR_LEN 8 + +struct ieee802154_addr { + int addr_type; + u16 pan_id; + union { + u8 hwaddr[IEEE802154_ADDR_LEN]; + u16 short_addr; + }; +}; + +#define IEEE802154_PANID_BROADCAST 0xffff +#define IEEE802154_ADDR_BROADCAST 0xffff +#define IEEE802154_ADDR_UNDEF 0xfffe + +struct sockaddr_ieee802154 { + sa_family_t family; /* AF_IEEE802154 */ + struct ieee802154_addr addr; +}; + +/* get/setsockopt */ +#define SOL_IEEE802154 0 + +#define WPAN_WANTACK 0 + +#endif diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h new file mode 100644 index 00000000..00c2eaa0 --- /dev/null +++ b/include/net/af_rxrpc.h @@ -0,0 +1,57 @@ +/* RxRPC kernel service interface definitions + * + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _NET_RXRPC_H +#define _NET_RXRPC_H + +#ifdef __KERNEL__ + +#include <linux/rxrpc.h> + +struct rxrpc_call; + +/* + * the mark applied to socket buffers that may be intercepted + */ +enum { + RXRPC_SKB_MARK_DATA, /* data message */ + RXRPC_SKB_MARK_FINAL_ACK, /* final ACK received message */ + RXRPC_SKB_MARK_BUSY, /* server busy message */ + RXRPC_SKB_MARK_REMOTE_ABORT, /* remote abort message */ + RXRPC_SKB_MARK_NET_ERROR, /* network error message */ + RXRPC_SKB_MARK_LOCAL_ERROR, /* local error message */ + RXRPC_SKB_MARK_NEW_CALL, /* local error message */ +}; + +typedef void (*rxrpc_interceptor_t)(struct sock *, unsigned long, + struct sk_buff *); +extern void rxrpc_kernel_intercept_rx_messages(struct socket *, + rxrpc_interceptor_t); +extern struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *, + struct sockaddr_rxrpc *, + struct key *, + unsigned long, + gfp_t); +extern int rxrpc_kernel_send_data(struct rxrpc_call *, struct msghdr *, + size_t); +extern void rxrpc_kernel_abort_call(struct rxrpc_call *, u32); +extern void rxrpc_kernel_end_call(struct rxrpc_call *); +extern bool rxrpc_kernel_is_data_last(struct sk_buff *); +extern u32 rxrpc_kernel_get_abort_code(struct sk_buff *); +extern int rxrpc_kernel_get_error_number(struct sk_buff *); +extern void rxrpc_kernel_data_delivered(struct sk_buff *); +extern void rxrpc_kernel_free_skb(struct sk_buff *); +extern struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *, + unsigned long); +extern int rxrpc_kernel_reject_call(struct socket *); + +#endif /* __KERNEL__ */ +#endif /* _NET_RXRPC_H */ diff --git a/include/net/af_unix.h b/include/net/af_unix.h new file mode 100644 index 00000000..18e5c3f6 --- /dev/null +++ b/include/net/af_unix.h @@ -0,0 +1,75 @@ +#ifndef __LINUX_NET_AFUNIX_H +#define __LINUX_NET_AFUNIX_H + +#include <linux/socket.h> +#include <linux/un.h> +#include <linux/mutex.h> +#include <net/sock.h> + +extern void unix_inflight(struct file *fp); +extern void unix_notinflight(struct file *fp); +extern void unix_gc(void); +extern void wait_for_unix_gc(void); +extern struct sock *unix_get_socket(struct file *filp); + +#define UNIX_HASH_SIZE 256 + +extern unsigned int unix_tot_inflight; + +struct unix_address { + atomic_t refcnt; + int len; + unsigned hash; + struct sockaddr_un name[0]; +}; + +struct unix_skb_parms { + struct pid *pid; /* Skb credentials */ + const struct cred *cred; + struct scm_fp_list *fp; /* Passed files */ +#ifdef CONFIG_SECURITY_NETWORK + u32 secid; /* Security ID */ +#endif +}; + +#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb)) +#define UNIXSID(skb) (&UNIXCB((skb)).secid) + +#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock) +#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock) +#define unix_state_lock_nested(s) \ + spin_lock_nested(&unix_sk(s)->lock, \ + SINGLE_DEPTH_NESTING) + +#ifdef __KERNEL__ +/* The AF_UNIX socket */ +struct unix_sock { + /* WARNING: sk has to be the first member */ + struct sock sk; + struct unix_address *addr; + struct dentry *dentry; + struct vfsmount *mnt; + struct mutex readlock; + struct sock *peer; + struct sock *other; + struct list_head link; + atomic_long_t inflight; + spinlock_t lock; + unsigned int gc_candidate : 1; + unsigned int gc_maybe_cycle : 1; + unsigned char recursion_level; + struct socket_wq peer_wq; +}; +#define unix_sk(__sk) ((struct unix_sock *)__sk) + +#define peer_wait peer_wq.wait + +#ifdef CONFIG_SYSCTL +extern int unix_sysctl_register(struct net *net); +extern void unix_sysctl_unregister(struct net *net); +#else +static inline int unix_sysctl_register(struct net *net) { return 0; } +static inline void unix_sysctl_unregister(struct net *net) {} +#endif +#endif +#endif diff --git a/include/net/ah.h b/include/net/ah.h new file mode 100644 index 00000000..f0129f79 --- /dev/null +++ b/include/net/ah.h @@ -0,0 +1,25 @@ +#ifndef _NET_AH_H +#define _NET_AH_H + +#include <linux/skbuff.h> + +/* This is the maximum truncated ICV length that we know of. */ +#define MAX_AH_AUTH_LEN 12 + +struct crypto_ahash; + +struct ah_data { + int icv_full_len; + int icv_trunc_len; + + struct crypto_ahash *ahash; +}; + +struct ip_auth_hdr; + +static inline struct ip_auth_hdr *ip_auth_hdr(const struct sk_buff *skb) +{ + return (struct ip_auth_hdr *)skb_transport_header(skb); +} + +#endif diff --git a/include/net/arp.h b/include/net/arp.h new file mode 100644 index 00000000..716f43c5 --- /dev/null +++ b/include/net/arp.h @@ -0,0 +1,31 @@ +/* linux/net/inet/arp.h */ +#ifndef _ARP_H +#define _ARP_H + +#include <linux/if_arp.h> +#include <net/neighbour.h> + + +extern struct neigh_table arp_tbl; + +extern void arp_init(void); +extern int arp_find(unsigned char *haddr, struct sk_buff *skb); +extern int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg); +extern void arp_send(int type, int ptype, __be32 dest_ip, + struct net_device *dev, __be32 src_ip, + const unsigned char *dest_hw, + const unsigned char *src_hw, const unsigned char *th); +extern int arp_bind_neighbour(struct dst_entry *dst); +extern int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir); +extern void arp_ifdown(struct net_device *dev); + +extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, + struct net_device *dev, __be32 src_ip, + const unsigned char *dest_hw, + const unsigned char *src_hw, + const unsigned char *target_hw); +extern void arp_xmit(struct sk_buff *skb); + +extern const struct neigh_ops arp_broken_ops; + +#endif /* _ARP_H */ diff --git a/include/net/atmclip.h b/include/net/atmclip.h new file mode 100644 index 00000000..467c531b --- /dev/null +++ b/include/net/atmclip.h @@ -0,0 +1,61 @@ +/* net/atm/atmarp.h - RFC1577 ATM ARP */ + +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef _ATMCLIP_H +#define _ATMCLIP_H + +#include <linux/netdevice.h> +#include <linux/atm.h> +#include <linux/atmdev.h> +#include <linux/atmarp.h> +#include <linux/spinlock.h> +#include <net/neighbour.h> + + +#define CLIP_VCC(vcc) ((struct clip_vcc *) ((vcc)->user_back)) +#define NEIGH2ENTRY(neigh) ((struct atmarp_entry *) (neigh)->primary_key) + +struct sk_buff; + +struct clip_vcc { + struct atm_vcc *vcc; /* VCC descriptor */ + struct atmarp_entry *entry; /* ATMARP table entry, NULL if IP addr. + isn't known yet */ + int xoff; /* 1 if send buffer is full */ + unsigned char encap; /* 0: NULL, 1: LLC/SNAP */ + unsigned long last_use; /* last send or receive operation */ + unsigned long idle_timeout; /* keep open idle for so many jiffies*/ + void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); + /* keep old push fn for chaining */ + void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); + /* keep old pop fn for chaining */ + struct clip_vcc *next; /* next VCC */ +}; + + +struct atmarp_entry { + __be32 ip; /* IP address */ + struct clip_vcc *vccs; /* active VCCs; NULL if resolution is + pending */ + unsigned long expires; /* entry expiration time */ + struct neighbour *neigh; /* neighbour back-pointer */ +}; + + +#define PRIV(dev) ((struct clip_priv *) netdev_priv(dev)) + + +struct clip_priv { + int number; /* for convenience ... */ + spinlock_t xoff_lock; /* ensures that pop is atomic (SMP) */ + struct net_device *next; /* next CLIP interface */ +}; + + +#ifdef __KERNEL__ +extern struct neigh_table *clip_tbl_hook; +#endif + +#endif diff --git a/include/net/ax25.h b/include/net/ax25.h new file mode 100644 index 00000000..206d2229 --- /dev/null +++ b/include/net/ax25.h @@ -0,0 +1,451 @@ +/* + * Declarations of AX.25 type objects. + * + * Alan Cox (GW4PTS) 10/11/93 + */ +#ifndef _AX25_H +#define _AX25_H + +#include <linux/ax25.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <asm/atomic.h> + +#define AX25_T1CLAMPLO 1 +#define AX25_T1CLAMPHI (30 * HZ) + +#define AX25_BPQ_HEADER_LEN 16 +#define AX25_KISS_HEADER_LEN 1 + +#define AX25_HEADER_LEN 17 +#define AX25_ADDR_LEN 7 +#define AX25_DIGI_HEADER_LEN (AX25_MAX_DIGIS * AX25_ADDR_LEN) +#define AX25_MAX_HEADER_LEN (AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN) + +/* AX.25 Protocol IDs */ +#define AX25_P_ROSE 0x01 +#define AX25_P_VJCOMP 0x06 /* Compressed TCP/IP packet */ + /* Van Jacobsen (RFC 1144) */ +#define AX25_P_VJUNCOMP 0x07 /* Uncompressed TCP/IP packet */ + /* Van Jacobsen (RFC 1144) */ +#define AX25_P_SEGMENT 0x08 /* Segmentation fragment */ +#define AX25_P_TEXNET 0xc3 /* TEXTNET datagram protocol */ +#define AX25_P_LQ 0xc4 /* Link Quality Protocol */ +#define AX25_P_ATALK 0xca /* Appletalk */ +#define AX25_P_ATALK_ARP 0xcb /* Appletalk ARP */ +#define AX25_P_IP 0xcc /* ARPA Internet Protocol */ +#define AX25_P_ARP 0xcd /* ARPA Address Resolution */ +#define AX25_P_FLEXNET 0xce /* FlexNet */ +#define AX25_P_NETROM 0xcf /* NET/ROM */ +#define AX25_P_TEXT 0xF0 /* No layer 3 protocol impl. */ + +/* AX.25 Segment control values */ +#define AX25_SEG_REM 0x7F +#define AX25_SEG_FIRST 0x80 + +#define AX25_CBIT 0x80 /* Command/Response bit */ +#define AX25_EBIT 0x01 /* HDLC Address Extension bit */ +#define AX25_HBIT 0x80 /* Has been repeated bit */ + +#define AX25_SSSID_SPARE 0x60 /* Unused bits in SSID for standard AX.25 */ +#define AX25_ESSID_SPARE 0x20 /* Unused bits in SSID for extended AX.25 */ +#define AX25_DAMA_FLAG 0x20 /* Well, it is *NOT* unused! (dl1bke 951121 */ + +#define AX25_COND_ACK_PENDING 0x01 +#define AX25_COND_REJECT 0x02 +#define AX25_COND_PEER_RX_BUSY 0x04 +#define AX25_COND_OWN_RX_BUSY 0x08 +#define AX25_COND_DAMA_MODE 0x10 + +#ifndef _LINUX_NETDEVICE_H +#include <linux/netdevice.h> +#endif + +/* Upper sub-layer (LAPB) definitions */ + +/* Control field templates */ +#define AX25_I 0x00 /* Information frames */ +#define AX25_S 0x01 /* Supervisory frames */ +#define AX25_RR 0x01 /* Receiver ready */ +#define AX25_RNR 0x05 /* Receiver not ready */ +#define AX25_REJ 0x09 /* Reject */ +#define AX25_U 0x03 /* Unnumbered frames */ +#define AX25_SABM 0x2f /* Set Asynchronous Balanced Mode */ +#define AX25_SABME 0x6f /* Set Asynchronous Balanced Mode Extended */ +#define AX25_DISC 0x43 /* Disconnect */ +#define AX25_DM 0x0f /* Disconnected mode */ +#define AX25_UA 0x63 /* Unnumbered acknowledge */ +#define AX25_FRMR 0x87 /* Frame reject */ +#define AX25_UI 0x03 /* Unnumbered information */ +#define AX25_XID 0xaf /* Exchange information */ +#define AX25_TEST 0xe3 /* Test */ + +#define AX25_PF 0x10 /* Poll/final bit for standard AX.25 */ +#define AX25_EPF 0x01 /* Poll/final bit for extended AX.25 */ + +#define AX25_ILLEGAL 0x100 /* Impossible to be a real frame type */ + +#define AX25_POLLOFF 0 +#define AX25_POLLON 1 + +/* AX25 L2 C-bit */ +#define AX25_COMMAND 1 +#define AX25_RESPONSE 2 + +/* Define Link State constants. */ + +enum { + AX25_STATE_0, /* Listening */ + AX25_STATE_1, /* SABM sent */ + AX25_STATE_2, /* DISC sent */ + AX25_STATE_3, /* Established */ + AX25_STATE_4 /* Recovery */ +}; + +#define AX25_MODULUS 8 /* Standard AX.25 modulus */ +#define AX25_EMODULUS 128 /* Extended AX.25 modulus */ + +enum { + AX25_PROTO_STD_SIMPLEX, + AX25_PROTO_STD_DUPLEX, +#ifdef CONFIG_AX25_DAMA_SLAVE + AX25_PROTO_DAMA_SLAVE, +#ifdef CONFIG_AX25_DAMA_MASTER + AX25_PROTO_DAMA_MASTER, +#define AX25_PROTO_MAX AX25_PROTO_DAMA_MASTER +#endif +#endif + __AX25_PROTO_MAX, + AX25_PROTO_MAX = __AX25_PROTO_MAX -1 +}; + +enum { + AX25_VALUES_IPDEFMODE, /* 0=DG 1=VC */ + AX25_VALUES_AXDEFMODE, /* 0=Normal 1=Extended Seq Nos */ + AX25_VALUES_BACKOFF, /* 0=None 1=Linear 2=Exponential */ + AX25_VALUES_CONMODE, /* Allow connected modes - 0=No 1=no "PID text" 2=all PIDs */ + AX25_VALUES_WINDOW, /* Default window size for standard AX.25 */ + AX25_VALUES_EWINDOW, /* Default window size for extended AX.25 */ + AX25_VALUES_T1, /* Default T1 timeout value */ + AX25_VALUES_T2, /* Default T2 timeout value */ + AX25_VALUES_T3, /* Default T3 timeout value */ + AX25_VALUES_IDLE, /* Connected mode idle timer */ + AX25_VALUES_N2, /* Default N2 value */ + AX25_VALUES_PACLEN, /* AX.25 MTU */ + AX25_VALUES_PROTOCOL, /* Std AX.25, DAMA Slave, DAMA Master */ + AX25_VALUES_DS_TIMEOUT, /* DAMA Slave timeout */ + AX25_MAX_VALUES /* THIS MUST REMAIN THE LAST ENTRY OF THIS LIST */ +}; + +#define AX25_DEF_IPDEFMODE 0 /* Datagram */ +#define AX25_DEF_AXDEFMODE 0 /* Normal */ +#define AX25_DEF_BACKOFF 1 /* Linear backoff */ +#define AX25_DEF_CONMODE 2 /* Connected mode allowed */ +#define AX25_DEF_WINDOW 2 /* Window=2 */ +#define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */ +#define AX25_DEF_T1 10000 /* T1=10s */ +#define AX25_DEF_T2 3000 /* T2=3s */ +#define AX25_DEF_T3 300000 /* T3=300s */ +#define AX25_DEF_N2 10 /* N2=10 */ +#define AX25_DEF_IDLE 0 /* Idle=None */ +#define AX25_DEF_PACLEN 256 /* Paclen=256 */ +#define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */ +#define AX25_DEF_DS_TIMEOUT 180000 /* DAMA timeout 3 minutes */ + +typedef struct ax25_uid_assoc { + struct hlist_node uid_node; + atomic_t refcount; + uid_t uid; + ax25_address call; +} ax25_uid_assoc; + +#define ax25_uid_for_each(__ax25, node, list) \ + hlist_for_each_entry(__ax25, node, list, uid_node) + +#define ax25_uid_hold(ax25) \ + atomic_inc(&((ax25)->refcount)) + +static inline void ax25_uid_put(ax25_uid_assoc *assoc) +{ + if (atomic_dec_and_test(&assoc->refcount)) { + kfree(assoc); + } +} + +typedef struct { + ax25_address calls[AX25_MAX_DIGIS]; + unsigned char repeated[AX25_MAX_DIGIS]; + unsigned char ndigi; + signed char lastrepeat; +} ax25_digi; + +typedef struct ax25_route { + struct ax25_route *next; + atomic_t refcount; + ax25_address callsign; + struct net_device *dev; + ax25_digi *digipeat; + char ip_mode; +} ax25_route; + +static inline void ax25_hold_route(ax25_route *ax25_rt) +{ + atomic_inc(&ax25_rt->refcount); +} + +extern void __ax25_put_route(ax25_route *ax25_rt); + +static inline void ax25_put_route(ax25_route *ax25_rt) +{ + if (atomic_dec_and_test(&ax25_rt->refcount)) + __ax25_put_route(ax25_rt); +} + +typedef struct { + char slave; /* slave_mode? */ + struct timer_list slave_timer; /* timeout timer */ + unsigned short slave_timeout; /* when? */ +} ax25_dama_info; + +struct ctl_table; + +typedef struct ax25_dev { + struct ax25_dev *next; + struct net_device *dev; + struct net_device *forward; + struct ctl_table *systable; + int values[AX25_MAX_VALUES]; +#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER) + ax25_dama_info dama; +#endif +} ax25_dev; + +typedef struct ax25_cb { + struct hlist_node ax25_node; + ax25_address source_addr, dest_addr; + ax25_digi *digipeat; + ax25_dev *ax25_dev; + unsigned char iamdigi; + unsigned char state, modulus, pidincl; + unsigned short vs, vr, va; + unsigned char condition, backoff; + unsigned char n2, n2count; + struct timer_list t1timer, t2timer, t3timer, idletimer; + unsigned long t1, t2, t3, idle, rtt; + unsigned short paclen, fragno, fraglen; + struct sk_buff_head write_queue; + struct sk_buff_head reseq_queue; + struct sk_buff_head ack_queue; + struct sk_buff_head frag_queue; + unsigned char window; + struct timer_list timer, dtimer; + struct sock *sk; /* Backlink to socket */ + atomic_t refcount; +} ax25_cb; + +#define ax25_sk(__sk) ((ax25_cb *)(__sk)->sk_protinfo) + +#define ax25_for_each(__ax25, node, list) \ + hlist_for_each_entry(__ax25, node, list, ax25_node) + +#define ax25_cb_hold(__ax25) \ + atomic_inc(&((__ax25)->refcount)) + +static __inline__ void ax25_cb_put(ax25_cb *ax25) +{ + if (atomic_dec_and_test(&ax25->refcount)) { + kfree(ax25->digipeat); + kfree(ax25); + } +} + +static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + skb->dev = dev; + skb_reset_mac_header(skb); + skb->pkt_type = PACKET_HOST; + return htons(ETH_P_AX25); +} + +/* af_ax25.c */ +extern struct hlist_head ax25_list; +extern spinlock_t ax25_list_lock; +extern void ax25_cb_add(ax25_cb *); +struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int); +struct sock *ax25_get_socket(ax25_address *, ax25_address *, int); +extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *); +extern void ax25_send_to_raw(ax25_address *, struct sk_buff *, int); +extern void ax25_destroy_socket(ax25_cb *); +extern ax25_cb * __must_check ax25_create_cb(void); +extern void ax25_fillin_cb(ax25_cb *, ax25_dev *); +extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *); + +/* ax25_addr.c */ +extern const ax25_address ax25_bcast; +extern const ax25_address ax25_defaddr; +extern const ax25_address null_ax25_address; +extern char *ax2asc(char *buf, const ax25_address *); +extern void asc2ax(ax25_address *addr, const char *callsign); +extern int ax25cmp(const ax25_address *, const ax25_address *); +extern int ax25digicmp(const ax25_digi *, const ax25_digi *); +extern const unsigned char *ax25_addr_parse(const unsigned char *, int, + ax25_address *, ax25_address *, ax25_digi *, int *, int *); +extern int ax25_addr_build(unsigned char *, const ax25_address *, + const ax25_address *, const ax25_digi *, int, int); +extern int ax25_addr_size(const ax25_digi *); +extern void ax25_digi_invert(const ax25_digi *, ax25_digi *); + +/* ax25_dev.c */ +extern ax25_dev *ax25_dev_list; +extern spinlock_t ax25_dev_lock; + +static inline ax25_dev *ax25_dev_ax25dev(struct net_device *dev) +{ + return dev->ax25_ptr; +} + +extern ax25_dev *ax25_addr_ax25dev(ax25_address *); +extern void ax25_dev_device_up(struct net_device *); +extern void ax25_dev_device_down(struct net_device *); +extern int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *); +extern struct net_device *ax25_fwd_dev(struct net_device *); +extern void ax25_dev_free(void); + +/* ax25_ds_in.c */ +extern int ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int); + +/* ax25_ds_subr.c */ +extern void ax25_ds_nr_error_recovery(ax25_cb *); +extern void ax25_ds_enquiry_response(ax25_cb *); +extern void ax25_ds_establish_data_link(ax25_cb *); +extern void ax25_dev_dama_off(ax25_dev *); +extern void ax25_dama_on(ax25_cb *); +extern void ax25_dama_off(ax25_cb *); + +/* ax25_ds_timer.c */ +extern void ax25_ds_setup_timer(ax25_dev *); +extern void ax25_ds_set_timer(ax25_dev *); +extern void ax25_ds_del_timer(ax25_dev *); +extern void ax25_ds_timer(ax25_cb *); +extern void ax25_ds_t1_timeout(ax25_cb *); +extern void ax25_ds_heartbeat_expiry(ax25_cb *); +extern void ax25_ds_t3timer_expiry(ax25_cb *); +extern void ax25_ds_idletimer_expiry(ax25_cb *); + +/* ax25_iface.c */ + +struct ax25_protocol { + struct ax25_protocol *next; + unsigned int pid; + int (*func)(struct sk_buff *, ax25_cb *); +}; + +extern void ax25_register_pid(struct ax25_protocol *ap); +extern void ax25_protocol_release(unsigned int); + +struct ax25_linkfail { + struct hlist_node lf_node; + void (*func)(ax25_cb *, int); +}; + +extern void ax25_linkfail_register(struct ax25_linkfail *lf); +extern void ax25_linkfail_release(struct ax25_linkfail *lf); +extern int __must_check ax25_listen_register(ax25_address *, + struct net_device *); +extern void ax25_listen_release(ax25_address *, struct net_device *); +extern int (*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *); +extern int ax25_listen_mine(ax25_address *, struct net_device *); +extern void ax25_link_failed(ax25_cb *, int); +extern int ax25_protocol_is_registered(unsigned int); + +/* ax25_in.c */ +extern int ax25_rx_iframe(ax25_cb *, struct sk_buff *); +extern int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); + +/* ax25_ip.c */ +extern int ax25_hard_header(struct sk_buff *, struct net_device *, + unsigned short, const void *, + const void *, unsigned int); +extern int ax25_rebuild_header(struct sk_buff *); +extern const struct header_ops ax25_header_ops; + +/* ax25_out.c */ +extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct net_device *); +extern void ax25_output(ax25_cb *, int, struct sk_buff *); +extern void ax25_kick(ax25_cb *); +extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int); +extern void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev); +extern int ax25_check_iframes_acked(ax25_cb *, unsigned short); + +/* ax25_route.c */ +extern void ax25_rt_device_down(struct net_device *); +extern int ax25_rt_ioctl(unsigned int, void __user *); +extern const struct file_operations ax25_route_fops; +extern ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev); +extern int ax25_rt_autobind(ax25_cb *, ax25_address *); +extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *); +extern void ax25_rt_free(void); + +/* ax25_std_in.c */ +extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); + +/* ax25_std_subr.c */ +extern void ax25_std_nr_error_recovery(ax25_cb *); +extern void ax25_std_establish_data_link(ax25_cb *); +extern void ax25_std_transmit_enquiry(ax25_cb *); +extern void ax25_std_enquiry_response(ax25_cb *); +extern void ax25_std_timeout_response(ax25_cb *); + +/* ax25_std_timer.c */ +extern void ax25_std_heartbeat_expiry(ax25_cb *); +extern void ax25_std_t1timer_expiry(ax25_cb *); +extern void ax25_std_t2timer_expiry(ax25_cb *); +extern void ax25_std_t3timer_expiry(ax25_cb *); +extern void ax25_std_idletimer_expiry(ax25_cb *); + +/* ax25_subr.c */ +extern void ax25_clear_queues(ax25_cb *); +extern void ax25_frames_acked(ax25_cb *, unsigned short); +extern void ax25_requeue_frames(ax25_cb *); +extern int ax25_validate_nr(ax25_cb *, unsigned short); +extern int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *); +extern void ax25_send_control(ax25_cb *, int, int, int); +extern void ax25_return_dm(struct net_device *, ax25_address *, ax25_address *, ax25_digi *); +extern void ax25_calculate_t1(ax25_cb *); +extern void ax25_calculate_rtt(ax25_cb *); +extern void ax25_disconnect(ax25_cb *, int); + +/* ax25_timer.c */ +extern void ax25_setup_timers(ax25_cb *); +extern void ax25_start_heartbeat(ax25_cb *); +extern void ax25_start_t1timer(ax25_cb *); +extern void ax25_start_t2timer(ax25_cb *); +extern void ax25_start_t3timer(ax25_cb *); +extern void ax25_start_idletimer(ax25_cb *); +extern void ax25_stop_heartbeat(ax25_cb *); +extern void ax25_stop_t1timer(ax25_cb *); +extern void ax25_stop_t2timer(ax25_cb *); +extern void ax25_stop_t3timer(ax25_cb *); +extern void ax25_stop_idletimer(ax25_cb *); +extern int ax25_t1timer_running(ax25_cb *); +extern unsigned long ax25_display_timer(struct timer_list *); + +/* ax25_uid.c */ +extern int ax25_uid_policy; +extern ax25_uid_assoc *ax25_findbyuid(uid_t); +extern int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *); +extern const struct file_operations ax25_uid_fops; +extern void ax25_uid_free(void); + +/* sysctl_net_ax25.c */ +#ifdef CONFIG_SYSCTL +extern void ax25_register_sysctl(void); +extern void ax25_unregister_sysctl(void); +#else +static inline void ax25_register_sysctl(void) {}; +static inline void ax25_unregister_sysctl(void) {}; +#endif /* CONFIG_SYSCTL */ + +#endif diff --git a/include/net/ax88796.h b/include/net/ax88796.h new file mode 100644 index 00000000..b9a3beca --- /dev/null +++ b/include/net/ax88796.h @@ -0,0 +1,31 @@ +/* include/net/ax88796.h + * + * Copyright 2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#ifndef __NET_AX88796_PLAT_H +#define __NET_AX88796_PLAT_H + +#define AXFLG_HAS_EEPROM (1<<0) +#define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ +#define AXFLG_HAS_93CX6 (1<<2) /* use eeprom_93cx6 driver */ +#define AXFLG_MAC_FROMPLATFORM (1<<3) /* MAC given by platform data */ + +struct ax_plat_data { + unsigned int flags; + unsigned char wordlength; /* 1 or 2 */ + unsigned char dcr_val; /* default value for DCR */ + unsigned char rcr_val; /* default value for RCR */ + unsigned char gpoc_val; /* default value for GPOC */ + u32 *reg_offsets; /* register offsets */ + u8 *mac_addr; /* MAC addr (only used when + AXFLG_MAC_FROMPLATFORM is used */ +}; + +#endif /* __NET_AX88796_PLAT_H */ diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h new file mode 100644 index 00000000..bfaef4a1 --- /dev/null +++ b/include/net/bluetooth/bluetooth.h @@ -0,0 +1,204 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __BLUETOOTH_H +#define __BLUETOOTH_H + +#include <asm/types.h> +#include <asm/byteorder.h> +#include <linux/list.h> +#include <linux/poll.h> +#include <net/sock.h> + +#ifndef AF_BLUETOOTH +#define AF_BLUETOOTH 31 +#define PF_BLUETOOTH AF_BLUETOOTH +#endif + +#define FEATURE_DELAYED_HCI_UNREGISTER + +/* Reserv for core and drivers use */ +#define BT_SKB_RESERVE 8 + +#define BTPROTO_L2CAP 0 +#define BTPROTO_HCI 1 +#define BTPROTO_SCO 2 +#define BTPROTO_RFCOMM 3 +#define BTPROTO_BNEP 4 +#define BTPROTO_CMTP 5 +#define BTPROTO_HIDP 6 +#define BTPROTO_AVDTP 7 + +#define SOL_HCI 0 +#define SOL_L2CAP 6 +#define SOL_SCO 17 +#define SOL_RFCOMM 18 + +#define BT_SECURITY 4 +struct bt_security { + __u8 level; +}; +#define BT_SECURITY_SDP 0 +#define BT_SECURITY_LOW 1 +#define BT_SECURITY_MEDIUM 2 +#define BT_SECURITY_HIGH 3 + +#define BT_DEFER_SETUP 7 + +#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) +#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) +#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg) + +/* Connection and socket states */ +enum { + BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ + BT_OPEN, + BT_BOUND, + BT_LISTEN, + BT_CONNECT, + BT_CONNECT2, + BT_CONFIG, + BT_DISCONN, + BT_CLOSED +}; + +/* BD Address */ +typedef struct { + __u8 b[6]; +} __packed bdaddr_t; + +#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) +#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) + +/* Copy, swap, convert BD Address */ +static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) +{ + return memcmp(ba1, ba2, sizeof(bdaddr_t)); +} +static inline void bacpy(bdaddr_t *dst, bdaddr_t *src) +{ + memcpy(dst, src, sizeof(bdaddr_t)); +} + +void baswap(bdaddr_t *dst, bdaddr_t *src); +char *batostr(bdaddr_t *ba); +bdaddr_t *strtoba(char *str); + +/* Common socket structures and functions */ + +#define bt_sk(__sk) ((struct bt_sock *) __sk) + +struct bt_sock { + struct sock sk; + bdaddr_t src; + bdaddr_t dst; + struct list_head accept_q; + struct sock *parent; + u32 defer_setup; +}; + +struct bt_sock_list { + struct hlist_head head; + rwlock_t lock; +}; + +int bt_sock_register(int proto, const struct net_proto_family *ops); +int bt_sock_unregister(int proto); +void bt_sock_link(struct bt_sock_list *l, struct sock *s); +void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); +int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); +int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags); +uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait); +int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); + +void bt_accept_enqueue(struct sock *parent, struct sock *sk); +void bt_accept_unlink(struct sock *sk); +struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); + +/* Skb helpers */ +struct bt_skb_cb { + __u8 pkt_type; + __u8 incoming; + __u16 expect; + __u8 tx_seq; + __u8 retries; + __u8 sar; +}; +#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) + +static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how) +{ + struct sk_buff *skb; + + if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) { + skb_reserve(skb, BT_SKB_RESERVE); + bt_cb(skb)->incoming = 0; + } + return skb; +} + +static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, unsigned long len, + int nb, int *err) +{ + struct sk_buff *skb; + + release_sock(sk); + if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) { + skb_reserve(skb, BT_SKB_RESERVE); + bt_cb(skb)->incoming = 0; + } + lock_sock(sk); + + if (!skb && *err) + return NULL; + + *err = sock_error(sk); + if (*err) + goto out; + + if (sk->sk_shutdown) { + *err = -ECONNRESET; + goto out; + } + + return skb; + +out: + kfree_skb(skb); + return NULL; +} + +int bt_err(__u16 code); + +extern int hci_sock_init(void); +extern void hci_sock_cleanup(void); + +extern int bt_sysfs_init(void); +extern void bt_sysfs_cleanup(void); + +extern struct dentry *bt_debugfs; + +#endif /* __BLUETOOTH_H */ diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h new file mode 100644 index 00000000..e30e0083 --- /dev/null +++ b/include/net/bluetooth/hci.h @@ -0,0 +1,1039 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_H +#define __HCI_H + +#define HCI_MAX_ACL_SIZE 1024 +#define HCI_MAX_SCO_SIZE 255 +#define HCI_MAX_EVENT_SIZE 260 +#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) + +/* HCI dev events */ +#define HCI_DEV_REG 1 +#define HCI_DEV_UNREG 2 +#define HCI_DEV_UP 3 +#define HCI_DEV_DOWN 4 +#define HCI_DEV_SUSPEND 5 +#define HCI_DEV_RESUME 6 + +/* HCI notify events */ +#define HCI_NOTIFY_CONN_ADD 1 +#define HCI_NOTIFY_CONN_DEL 2 +#define HCI_NOTIFY_VOICE_SETTING 3 + +/* HCI bus types */ +#define HCI_VIRTUAL 0 +#define HCI_USB 1 +#define HCI_PCCARD 2 +#define HCI_UART 3 +#define HCI_RS232 4 +#define HCI_PCI 5 +#define HCI_SDIO 6 + +/* HCI controller types */ +#define HCI_BREDR 0x00 +#define HCI_AMP 0x01 + +/* HCI device quirks */ +enum { + HCI_QUIRK_NO_RESET, + HCI_QUIRK_RAW_DEVICE, + HCI_QUIRK_FIXUP_BUFFER_SIZE +}; + +/* HCI device flags */ +enum { + HCI_UP, + HCI_INIT, + HCI_RUNNING, + + HCI_PSCAN, + HCI_ISCAN, + HCI_AUTH, + HCI_ENCRYPT, + HCI_INQUIRY, + + HCI_RAW, +}; + +/* HCI ioctl defines */ +#define HCIDEVUP _IOW('H', 201, int) +#define HCIDEVDOWN _IOW('H', 202, int) +#define HCIDEVRESET _IOW('H', 203, int) +#define HCIDEVRESTAT _IOW('H', 204, int) + +#define HCIGETDEVLIST _IOR('H', 210, int) +#define HCIGETDEVINFO _IOR('H', 211, int) +#define HCIGETCONNLIST _IOR('H', 212, int) +#define HCIGETCONNINFO _IOR('H', 213, int) +#define HCIGETAUTHINFO _IOR('H', 215, int) + +#define HCISETRAW _IOW('H', 220, int) +#define HCISETSCAN _IOW('H', 221, int) +#define HCISETAUTH _IOW('H', 222, int) +#define HCISETENCRYPT _IOW('H', 223, int) +#define HCISETPTYPE _IOW('H', 224, int) +#define HCISETLINKPOL _IOW('H', 225, int) +#define HCISETLINKMODE _IOW('H', 226, int) +#define HCISETACLMTU _IOW('H', 227, int) +#define HCISETSCOMTU _IOW('H', 228, int) + +#define HCIBLOCKADDR _IOW('H', 230, int) +#define HCIUNBLOCKADDR _IOW('H', 231, int) + +#define HCIINQUIRY _IOR('H', 240, int) + +/* HCI timeouts */ +#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */ +#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */ +#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ +#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ +#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ + +/* HCI data types */ +#define HCI_COMMAND_PKT 0x01 +#define HCI_ACLDATA_PKT 0x02 +#define HCI_SCODATA_PKT 0x03 +#define HCI_EVENT_PKT 0x04 +#define HCI_VENDOR_PKT 0xff + +/* HCI packet types */ +#define HCI_DM1 0x0008 +#define HCI_DM3 0x0400 +#define HCI_DM5 0x4000 +#define HCI_DH1 0x0010 +#define HCI_DH3 0x0800 +#define HCI_DH5 0x8000 + +#define HCI_HV1 0x0020 +#define HCI_HV2 0x0040 +#define HCI_HV3 0x0080 + +#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) +#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) + +/* eSCO packet types */ +#define ESCO_HV1 0x0001 +#define ESCO_HV2 0x0002 +#define ESCO_HV3 0x0004 +#define ESCO_EV3 0x0008 +#define ESCO_EV4 0x0010 +#define ESCO_EV5 0x0020 +#define ESCO_2EV3 0x0040 +#define ESCO_3EV3 0x0080 +#define ESCO_2EV5 0x0100 +#define ESCO_3EV5 0x0200 + +#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) +#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) + +/* ACL flags */ +#define ACL_CONT 0x01 +#define ACL_START 0x02 +#define ACL_ACTIVE_BCAST 0x04 +#define ACL_PICO_BCAST 0x08 + +/* Baseband links */ +#define SCO_LINK 0x00 +#define ACL_LINK 0x01 +#define ESCO_LINK 0x02 + +/* LMP features */ +#define LMP_3SLOT 0x01 +#define LMP_5SLOT 0x02 +#define LMP_ENCRYPT 0x04 +#define LMP_SOFFSET 0x08 +#define LMP_TACCURACY 0x10 +#define LMP_RSWITCH 0x20 +#define LMP_HOLD 0x40 +#define LMP_SNIFF 0x80 + +#define LMP_PARK 0x01 +#define LMP_RSSI 0x02 +#define LMP_QUALITY 0x04 +#define LMP_SCO 0x08 +#define LMP_HV2 0x10 +#define LMP_HV3 0x20 +#define LMP_ULAW 0x40 +#define LMP_ALAW 0x80 + +#define LMP_CVSD 0x01 +#define LMP_PSCHEME 0x02 +#define LMP_PCONTROL 0x04 + +#define LMP_ESCO 0x80 + +#define LMP_EV4 0x01 +#define LMP_EV5 0x02 + +#define LMP_SNIFF_SUBR 0x02 +#define LMP_EDR_ESCO_2M 0x20 +#define LMP_EDR_ESCO_3M 0x40 +#define LMP_EDR_3S_ESCO 0x80 + +#define LMP_SIMPLE_PAIR 0x08 + +/* Connection modes */ +#define HCI_CM_ACTIVE 0x0000 +#define HCI_CM_HOLD 0x0001 +#define HCI_CM_SNIFF 0x0002 +#define HCI_CM_PARK 0x0003 + +/* Link policies */ +#define HCI_LP_RSWITCH 0x0001 +#define HCI_LP_HOLD 0x0002 +#define HCI_LP_SNIFF 0x0004 +#define HCI_LP_PARK 0x0008 + +/* Link modes */ +#define HCI_LM_ACCEPT 0x8000 +#define HCI_LM_MASTER 0x0001 +#define HCI_LM_AUTH 0x0002 +#define HCI_LM_ENCRYPT 0x0004 +#define HCI_LM_TRUSTED 0x0008 +#define HCI_LM_RELIABLE 0x0010 +#define HCI_LM_SECURE 0x0020 + +/* Authentication types */ +#define HCI_AT_NO_BONDING 0x00 +#define HCI_AT_NO_BONDING_MITM 0x01 +#define HCI_AT_DEDICATED_BONDING 0x02 +#define HCI_AT_DEDICATED_BONDING_MITM 0x03 +#define HCI_AT_GENERAL_BONDING 0x04 +#define HCI_AT_GENERAL_BONDING_MITM 0x05 + +/* ----- HCI Commands ---- */ +#define HCI_OP_INQUIRY 0x0401 +struct hci_cp_inquiry { + __u8 lap[3]; + __u8 length; + __u8 num_rsp; +} __packed; + +#define HCI_OP_INQUIRY_CANCEL 0x0402 + +#define HCI_OP_EXIT_PERIODIC_INQ 0x0404 + +#define HCI_OP_CREATE_CONN 0x0405 +struct hci_cp_create_conn { + bdaddr_t bdaddr; + __le16 pkt_type; + __u8 pscan_rep_mode; + __u8 pscan_mode; + __le16 clock_offset; + __u8 role_switch; +} __packed; + +#define HCI_OP_DISCONNECT 0x0406 +struct hci_cp_disconnect { + __le16 handle; + __u8 reason; +} __packed; + +#define HCI_OP_ADD_SCO 0x0407 +struct hci_cp_add_sco { + __le16 handle; + __le16 pkt_type; +} __packed; + +#define HCI_OP_CREATE_CONN_CANCEL 0x0408 +struct hci_cp_create_conn_cancel { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_ACCEPT_CONN_REQ 0x0409 +struct hci_cp_accept_conn_req { + bdaddr_t bdaddr; + __u8 role; +} __packed; + +#define HCI_OP_REJECT_CONN_REQ 0x040a +struct hci_cp_reject_conn_req { + bdaddr_t bdaddr; + __u8 reason; +} __packed; + +#define HCI_OP_LINK_KEY_REPLY 0x040b +struct hci_cp_link_key_reply { + bdaddr_t bdaddr; + __u8 link_key[16]; +} __packed; + +#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c +struct hci_cp_link_key_neg_reply { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_PIN_CODE_REPLY 0x040d +struct hci_cp_pin_code_reply { + bdaddr_t bdaddr; + __u8 pin_len; + __u8 pin_code[16]; +} __packed; + +#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e +struct hci_cp_pin_code_neg_reply { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_CHANGE_CONN_PTYPE 0x040f +struct hci_cp_change_conn_ptype { + __le16 handle; + __le16 pkt_type; +} __packed; + +#define HCI_OP_AUTH_REQUESTED 0x0411 +struct hci_cp_auth_requested { + __le16 handle; +} __packed; + +#define HCI_OP_SET_CONN_ENCRYPT 0x0413 +struct hci_cp_set_conn_encrypt { + __le16 handle; + __u8 encrypt; +} __packed; + +#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415 +struct hci_cp_change_conn_link_key { + __le16 handle; +} __packed; + +#define HCI_OP_REMOTE_NAME_REQ 0x0419 +struct hci_cp_remote_name_req { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_mode; + __le16 clock_offset; +} __packed; + +#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a +struct hci_cp_remote_name_req_cancel { + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_READ_REMOTE_FEATURES 0x041b +struct hci_cp_read_remote_features { + __le16 handle; +} __packed; + +#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c +struct hci_cp_read_remote_ext_features { + __le16 handle; + __u8 page; +} __packed; + +#define HCI_OP_READ_REMOTE_VERSION 0x041d +struct hci_cp_read_remote_version { + __le16 handle; +} __packed; + +#define HCI_OP_SETUP_SYNC_CONN 0x0428 +struct hci_cp_setup_sync_conn { + __le16 handle; + __le32 tx_bandwidth; + __le32 rx_bandwidth; + __le16 max_latency; + __le16 voice_setting; + __u8 retrans_effort; + __le16 pkt_type; +} __packed; + +#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429 +struct hci_cp_accept_sync_conn_req { + bdaddr_t bdaddr; + __le32 tx_bandwidth; + __le32 rx_bandwidth; + __le16 max_latency; + __le16 content_format; + __u8 retrans_effort; + __le16 pkt_type; +} __packed; + +#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a +struct hci_cp_reject_sync_conn_req { + bdaddr_t bdaddr; + __u8 reason; +} __packed; + +#define HCI_OP_SNIFF_MODE 0x0803 +struct hci_cp_sniff_mode { + __le16 handle; + __le16 max_interval; + __le16 min_interval; + __le16 attempt; + __le16 timeout; +} __packed; + +#define HCI_OP_EXIT_SNIFF_MODE 0x0804 +struct hci_cp_exit_sniff_mode { + __le16 handle; +} __packed; + +#define HCI_OP_ROLE_DISCOVERY 0x0809 +struct hci_cp_role_discovery { + __le16 handle; +} __packed; +struct hci_rp_role_discovery { + __u8 status; + __le16 handle; + __u8 role; +} __packed; + +#define HCI_OP_SWITCH_ROLE 0x080b +struct hci_cp_switch_role { + bdaddr_t bdaddr; + __u8 role; +} __packed; + +#define HCI_OP_READ_LINK_POLICY 0x080c +struct hci_cp_read_link_policy { + __le16 handle; +} __packed; +struct hci_rp_read_link_policy { + __u8 status; + __le16 handle; + __le16 policy; +} __packed; + +#define HCI_OP_WRITE_LINK_POLICY 0x080d +struct hci_cp_write_link_policy { + __le16 handle; + __le16 policy; +} __packed; +struct hci_rp_write_link_policy { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_OP_READ_DEF_LINK_POLICY 0x080e +struct hci_rp_read_def_link_policy { + __u8 status; + __le16 policy; +} __packed; + +#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f +struct hci_cp_write_def_link_policy { + __le16 policy; +} __packed; + +#define HCI_OP_SNIFF_SUBRATE 0x0811 +struct hci_cp_sniff_subrate { + __le16 handle; + __le16 max_latency; + __le16 min_remote_timeout; + __le16 min_local_timeout; +} __packed; + +#define HCI_OP_SET_EVENT_MASK 0x0c01 +struct hci_cp_set_event_mask { + __u8 mask[8]; +} __packed; + +#define HCI_OP_RESET 0x0c03 + +#define HCI_OP_SET_EVENT_FLT 0x0c05 +struct hci_cp_set_event_flt { + __u8 flt_type; + __u8 cond_type; + __u8 condition[0]; +} __packed; + +/* Filter types */ +#define HCI_FLT_CLEAR_ALL 0x00 +#define HCI_FLT_INQ_RESULT 0x01 +#define HCI_FLT_CONN_SETUP 0x02 + +/* CONN_SETUP Condition types */ +#define HCI_CONN_SETUP_ALLOW_ALL 0x00 +#define HCI_CONN_SETUP_ALLOW_CLASS 0x01 +#define HCI_CONN_SETUP_ALLOW_BDADDR 0x02 + +/* CONN_SETUP Conditions */ +#define HCI_CONN_SETUP_AUTO_OFF 0x01 +#define HCI_CONN_SETUP_AUTO_ON 0x02 + +#define HCI_OP_WRITE_LOCAL_NAME 0x0c13 +struct hci_cp_write_local_name { + __u8 name[248]; +} __packed; + +#define HCI_OP_READ_LOCAL_NAME 0x0c14 +struct hci_rp_read_local_name { + __u8 status; + __u8 name[248]; +} __packed; + +#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 + +#define HCI_OP_WRITE_PG_TIMEOUT 0x0c18 + +#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a + #define SCAN_DISABLED 0x00 + #define SCAN_INQUIRY 0x01 + #define SCAN_PAGE 0x02 + +#define HCI_OP_READ_AUTH_ENABLE 0x0c1f + +#define HCI_OP_WRITE_AUTH_ENABLE 0x0c20 + #define AUTH_DISABLED 0x00 + #define AUTH_ENABLED 0x01 + +#define HCI_OP_READ_ENCRYPT_MODE 0x0c21 + +#define HCI_OP_WRITE_ENCRYPT_MODE 0x0c22 + #define ENCRYPT_DISABLED 0x00 + #define ENCRYPT_P2P 0x01 + #define ENCRYPT_BOTH 0x02 + +#define HCI_OP_READ_CLASS_OF_DEV 0x0c23 +struct hci_rp_read_class_of_dev { + __u8 status; + __u8 dev_class[3]; +} __packed; + +#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24 +struct hci_cp_write_class_of_dev { + __u8 dev_class[3]; +} __packed; + +#define HCI_OP_READ_VOICE_SETTING 0x0c25 +struct hci_rp_read_voice_setting { + __u8 status; + __le16 voice_setting; +} __packed; + +#define HCI_OP_WRITE_VOICE_SETTING 0x0c26 +struct hci_cp_write_voice_setting { + __le16 voice_setting; +} __packed; + +#define HCI_OP_HOST_BUFFER_SIZE 0x0c33 +struct hci_cp_host_buffer_size { + __le16 acl_mtu; + __u8 sco_mtu; + __le16 acl_max_pkt; + __le16 sco_max_pkt; +} __packed; + +#define HCI_OP_READ_SSP_MODE 0x0c55 +struct hci_rp_read_ssp_mode { + __u8 status; + __u8 mode; +} __packed; + +#define HCI_OP_WRITE_SSP_MODE 0x0c56 +struct hci_cp_write_ssp_mode { + __u8 mode; +} __packed; + +#define HCI_OP_READ_LOCAL_VERSION 0x1001 +struct hci_rp_read_local_version { + __u8 status; + __u8 hci_ver; + __le16 hci_rev; + __u8 lmp_ver; + __le16 manufacturer; + __le16 lmp_subver; +} __packed; + +#define HCI_OP_READ_LOCAL_COMMANDS 0x1002 +struct hci_rp_read_local_commands { + __u8 status; + __u8 commands[64]; +} __packed; + +#define HCI_OP_READ_LOCAL_FEATURES 0x1003 +struct hci_rp_read_local_features { + __u8 status; + __u8 features[8]; +} __packed; + +#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004 +struct hci_rp_read_local_ext_features { + __u8 status; + __u8 page; + __u8 max_page; + __u8 features[8]; +} __packed; + +#define HCI_OP_READ_BUFFER_SIZE 0x1005 +struct hci_rp_read_buffer_size { + __u8 status; + __le16 acl_mtu; + __u8 sco_mtu; + __le16 acl_max_pkt; + __le16 sco_max_pkt; +} __packed; + +#define HCI_OP_READ_BD_ADDR 0x1009 +struct hci_rp_read_bd_addr { + __u8 status; + bdaddr_t bdaddr; +} __packed; + +/* ---- HCI Events ---- */ +#define HCI_EV_INQUIRY_COMPLETE 0x01 + +#define HCI_EV_INQUIRY_RESULT 0x02 +struct inquiry_info { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; + __u8 dev_class[3]; + __le16 clock_offset; +} __packed; + +#define HCI_EV_CONN_COMPLETE 0x03 +struct hci_ev_conn_complete { + __u8 status; + __le16 handle; + bdaddr_t bdaddr; + __u8 link_type; + __u8 encr_mode; +} __packed; + +#define HCI_EV_CONN_REQUEST 0x04 +struct hci_ev_conn_request { + bdaddr_t bdaddr; + __u8 dev_class[3]; + __u8 link_type; +} __packed; + +#define HCI_EV_DISCONN_COMPLETE 0x05 +struct hci_ev_disconn_complete { + __u8 status; + __le16 handle; + __u8 reason; +} __packed; + +#define HCI_EV_AUTH_COMPLETE 0x06 +struct hci_ev_auth_complete { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_EV_REMOTE_NAME 0x07 +struct hci_ev_remote_name { + __u8 status; + bdaddr_t bdaddr; + __u8 name[248]; +} __packed; + +#define HCI_EV_ENCRYPT_CHANGE 0x08 +struct hci_ev_encrypt_change { + __u8 status; + __le16 handle; + __u8 encrypt; +} __packed; + +#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09 +struct hci_ev_change_link_key_complete { + __u8 status; + __le16 handle; +} __packed; + +#define HCI_EV_REMOTE_FEATURES 0x0b +struct hci_ev_remote_features { + __u8 status; + __le16 handle; + __u8 features[8]; +} __packed; + +#define HCI_EV_REMOTE_VERSION 0x0c +struct hci_ev_remote_version { + __u8 status; + __le16 handle; + __u8 lmp_ver; + __le16 manufacturer; + __le16 lmp_subver; +} __packed; + +#define HCI_EV_QOS_SETUP_COMPLETE 0x0d +struct hci_qos { + __u8 service_type; + __u32 token_rate; + __u32 peak_bandwidth; + __u32 latency; + __u32 delay_variation; +} __packed; +struct hci_ev_qos_setup_complete { + __u8 status; + __le16 handle; + struct hci_qos qos; +} __packed; + +#define HCI_EV_CMD_COMPLETE 0x0e +struct hci_ev_cmd_complete { + __u8 ncmd; + __le16 opcode; +} __packed; + +#define HCI_EV_CMD_STATUS 0x0f +struct hci_ev_cmd_status { + __u8 status; + __u8 ncmd; + __le16 opcode; +} __packed; + +#define HCI_EV_ROLE_CHANGE 0x12 +struct hci_ev_role_change { + __u8 status; + bdaddr_t bdaddr; + __u8 role; +} __packed; + +#define HCI_EV_NUM_COMP_PKTS 0x13 +struct hci_ev_num_comp_pkts { + __u8 num_hndl; + /* variable length part */ +} __packed; + +#define HCI_EV_MODE_CHANGE 0x14 +struct hci_ev_mode_change { + __u8 status; + __le16 handle; + __u8 mode; + __le16 interval; +} __packed; + +#define HCI_EV_PIN_CODE_REQ 0x16 +struct hci_ev_pin_code_req { + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_LINK_KEY_REQ 0x17 +struct hci_ev_link_key_req { + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_LINK_KEY_NOTIFY 0x18 +struct hci_ev_link_key_notify { + bdaddr_t bdaddr; + __u8 link_key[16]; + __u8 key_type; +} __packed; + +#define HCI_EV_CLOCK_OFFSET 0x1c +struct hci_ev_clock_offset { + __u8 status; + __le16 handle; + __le16 clock_offset; +} __packed; + +#define HCI_EV_PKT_TYPE_CHANGE 0x1d +struct hci_ev_pkt_type_change { + __u8 status; + __le16 handle; + __le16 pkt_type; +} __packed; + +#define HCI_EV_PSCAN_REP_MODE 0x20 +struct hci_ev_pscan_rep_mode { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; +} __packed; + +#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 +struct inquiry_info_with_rssi { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; +} __packed; +struct inquiry_info_with_rssi_and_pscan_mode { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; +} __packed; + +#define HCI_EV_REMOTE_EXT_FEATURES 0x23 +struct hci_ev_remote_ext_features { + __u8 status; + __le16 handle; + __u8 page; + __u8 max_page; + __u8 features[8]; +} __packed; + +#define HCI_EV_SYNC_CONN_COMPLETE 0x2c +struct hci_ev_sync_conn_complete { + __u8 status; + __le16 handle; + bdaddr_t bdaddr; + __u8 link_type; + __u8 tx_interval; + __u8 retrans_window; + __le16 rx_pkt_len; + __le16 tx_pkt_len; + __u8 air_mode; +} __packed; + +#define HCI_EV_SYNC_CONN_CHANGED 0x2d +struct hci_ev_sync_conn_changed { + __u8 status; + __le16 handle; + __u8 tx_interval; + __u8 retrans_window; + __le16 rx_pkt_len; + __le16 tx_pkt_len; +} __packed; + +#define HCI_EV_SNIFF_SUBRATE 0x2e +struct hci_ev_sniff_subrate { + __u8 status; + __le16 handle; + __le16 max_tx_latency; + __le16 max_rx_latency; + __le16 max_remote_timeout; + __le16 max_local_timeout; +} __packed; + +#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f +struct extended_inquiry_info { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; + __u8 data[240]; +} __packed; + +#define HCI_EV_IO_CAPA_REQUEST 0x31 +struct hci_ev_io_capa_request { + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 +struct hci_ev_simple_pair_complete { + __u8 status; + bdaddr_t bdaddr; +} __packed; + +#define HCI_EV_REMOTE_HOST_FEATURES 0x3d +struct hci_ev_remote_host_features { + bdaddr_t bdaddr; + __u8 features[8]; +} __packed; + +/* Internal events generated by Bluetooth stack */ +#define HCI_EV_STACK_INTERNAL 0xfd +struct hci_ev_stack_internal { + __u16 type; + __u8 data[0]; +} __packed; + +#define HCI_EV_SI_DEVICE 0x01 +struct hci_ev_si_device { + __u16 event; + __u16 dev_id; +} __packed; + +#define HCI_EV_SI_SECURITY 0x02 +struct hci_ev_si_security { + __u16 event; + __u16 proto; + __u16 subproto; + __u8 incoming; +} __packed; + +/* ---- HCI Packet structures ---- */ +#define HCI_COMMAND_HDR_SIZE 3 +#define HCI_EVENT_HDR_SIZE 2 +#define HCI_ACL_HDR_SIZE 4 +#define HCI_SCO_HDR_SIZE 3 + +struct hci_command_hdr { + __le16 opcode; /* OCF & OGF */ + __u8 plen; +} __packed; + +struct hci_event_hdr { + __u8 evt; + __u8 plen; +} __packed; + +struct hci_acl_hdr { + __le16 handle; /* Handle & Flags(PB, BC) */ + __le16 dlen; +} __packed; + +struct hci_sco_hdr { + __le16 handle; + __u8 dlen; +} __packed; + +#ifdef __KERNEL__ +#include <linux/skbuff.h> +static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb) +{ + return (struct hci_event_hdr *) skb->data; +} + +static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb) +{ + return (struct hci_acl_hdr *) skb->data; +} + +static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) +{ + return (struct hci_sco_hdr *) skb->data; +} +#endif + +/* Command opcode pack/unpack */ +#define hci_opcode_pack(ogf, ocf) (__u16) ((ocf & 0x03ff)|(ogf << 10)) +#define hci_opcode_ogf(op) (op >> 10) +#define hci_opcode_ocf(op) (op & 0x03ff) + +/* ACL handle and flags pack/unpack */ +#define hci_handle_pack(h, f) (__u16) ((h & 0x0fff)|(f << 12)) +#define hci_handle(h) (h & 0x0fff) +#define hci_flags(h) (h >> 12) + +/* ---- HCI Sockets ---- */ + +/* Socket options */ +#define HCI_DATA_DIR 1 +#define HCI_FILTER 2 +#define HCI_TIME_STAMP 3 + +/* CMSG flags */ +#define HCI_CMSG_DIR 0x0001 +#define HCI_CMSG_TSTAMP 0x0002 + +struct sockaddr_hci { + sa_family_t hci_family; + unsigned short hci_dev; +}; +#define HCI_DEV_NONE 0xffff + +struct hci_filter { + unsigned long type_mask; + unsigned long event_mask[2]; + __le16 opcode; +}; + +struct hci_ufilter { + __u32 type_mask; + __u32 event_mask[2]; + __le16 opcode; +}; + +#define HCI_FLT_TYPE_BITS 31 +#define HCI_FLT_EVENT_BITS 63 +#define HCI_FLT_OGF_BITS 63 +#define HCI_FLT_OCF_BITS 127 + +/* ---- HCI Ioctl requests structures ---- */ +struct hci_dev_stats { + __u32 err_rx; + __u32 err_tx; + __u32 cmd_tx; + __u32 evt_rx; + __u32 acl_tx; + __u32 acl_rx; + __u32 sco_tx; + __u32 sco_rx; + __u32 byte_rx; + __u32 byte_tx; +}; + +struct hci_dev_info { + __u16 dev_id; + char name[8]; + + bdaddr_t bdaddr; + + __u32 flags; + __u8 type; + + __u8 features[8]; + + __u32 pkt_type; + __u32 link_policy; + __u32 link_mode; + + __u16 acl_mtu; + __u16 acl_pkts; + __u16 sco_mtu; + __u16 sco_pkts; + + struct hci_dev_stats stat; +}; + +struct hci_conn_info { + __u16 handle; + bdaddr_t bdaddr; + __u8 type; + __u8 out; + __u16 state; + __u32 link_mode; +}; + +struct hci_dev_req { + __u16 dev_id; + __u32 dev_opt; +}; + +struct hci_dev_list_req { + __u16 dev_num; + struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ +}; + +struct hci_conn_list_req { + __u16 dev_id; + __u16 conn_num; + struct hci_conn_info conn_info[0]; +}; + +struct hci_conn_info_req { + bdaddr_t bdaddr; + __u8 type; + struct hci_conn_info conn_info[0]; +}; + +struct hci_auth_info_req { + bdaddr_t bdaddr; + __u8 type; +}; + +struct hci_inquiry_req { + __u16 dev_id; + __u16 flags; + __u8 lap[3]; + __u8 length; + __u8 num_rsp; +}; +#define IREQ_CACHE_FLUSH 0x0001 + +#endif /* __HCI_H */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h new file mode 100644 index 00000000..ebec8c9a --- /dev/null +++ b/include/net/bluetooth/hci_core.h @@ -0,0 +1,692 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. + + Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_CORE_H +#define __HCI_CORE_H + +#include <net/bluetooth/hci.h> + +/* HCI upper protocols */ +#define HCI_PROTO_L2CAP 0 +#define HCI_PROTO_SCO 1 + +/* HCI Core structures */ +struct inquiry_data { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; + __u8 dev_class[3]; + __le16 clock_offset; + __s8 rssi; + __u8 ssp_mode; +}; + +struct inquiry_entry { + struct inquiry_entry *next; + __u32 timestamp; + struct inquiry_data data; +}; + +struct inquiry_cache { + spinlock_t lock; + __u32 timestamp; + struct inquiry_entry *list; +}; + +struct hci_conn_hash { + struct list_head list; + spinlock_t lock; + unsigned int acl_num; + unsigned int sco_num; +}; + +struct bdaddr_list { + struct list_head list; + bdaddr_t bdaddr; +}; +#define NUM_REASSEMBLY 4 +struct hci_dev { + struct list_head list; + spinlock_t lock; + atomic_t refcnt; + + char name[8]; + unsigned long flags; + __u16 id; + __u8 bus; + __u8 dev_type; + bdaddr_t bdaddr; + __u8 dev_name[248]; + __u8 dev_class[3]; + __u8 features[8]; + __u8 commands[64]; + __u8 ssp_mode; + __u8 hci_ver; + __u16 hci_rev; + __u16 manufacturer; + __u16 voice_setting; + + __u16 pkt_type; + __u16 esco_type; + __u16 link_policy; + __u16 link_mode; + + __u32 idle_timeout; + __u16 sniff_min_interval; + __u16 sniff_max_interval; + + unsigned long quirks; + + atomic_t cmd_cnt; + unsigned int acl_cnt; + unsigned int sco_cnt; + + unsigned int acl_mtu; + unsigned int sco_mtu; + unsigned int acl_pkts; + unsigned int sco_pkts; + + unsigned long cmd_last_tx; + unsigned long acl_last_tx; + unsigned long sco_last_tx; + + struct workqueue_struct *workqueue; + + struct tasklet_struct cmd_task; + struct tasklet_struct rx_task; + struct tasklet_struct tx_task; + + struct sk_buff_head rx_q; + struct sk_buff_head raw_q; + struct sk_buff_head cmd_q; + + struct sk_buff *sent_cmd; + struct sk_buff *reassembly[NUM_REASSEMBLY]; + + struct mutex req_lock; + wait_queue_head_t req_wait_q; + __u32 req_status; + __u32 req_result; + + struct inquiry_cache inq_cache; + struct hci_conn_hash conn_hash; + struct list_head blacklist; + + struct hci_dev_stats stat; + + struct sk_buff_head driver_init; + + void *driver_data; + void *core_data; + + atomic_t promisc; + + struct dentry *debugfs; + + struct device *parent; + struct device dev; + + struct rfkill *rfkill; + + struct module *owner; + + int (*open)(struct hci_dev *hdev); + int (*close)(struct hci_dev *hdev); + int (*flush)(struct hci_dev *hdev); + int (*send)(struct sk_buff *skb); + void (*destruct)(struct hci_dev *hdev); + void (*notify)(struct hci_dev *hdev, unsigned int evt); + int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); +}; + +struct hci_conn { + struct list_head list; + + atomic_t refcnt; + spinlock_t lock; + + bdaddr_t dst; + __u16 handle; + __u16 state; + __u8 mode; + __u8 type; + __u8 out; + __u8 attempt; + __u8 dev_class[3]; + __u8 features[8]; + __u8 ssp_mode; + __u16 interval; + __u16 pkt_type; + __u16 link_policy; + __u32 link_mode; + __u8 auth_type; + __u8 sec_level; + __u8 power_save; + __u16 disc_timeout; + unsigned long pend; + + unsigned int sent; + + struct sk_buff_head data_q; + + struct timer_list disc_timer; + struct timer_list idle_timer; + + struct work_struct work_add; + struct work_struct work_del; + + struct device dev; + atomic_t devref; + + struct hci_dev *hdev; + void *l2cap_data; + void *sco_data; + void *priv; + + struct hci_conn *link; +}; + +extern struct hci_proto *hci_proto[]; +extern struct list_head hci_dev_list; +extern struct list_head hci_cb_list; +extern rwlock_t hci_dev_list_lock; +extern rwlock_t hci_cb_list_lock; + +/* ----- Inquiry cache ----- */ +#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds +#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds + +#define inquiry_cache_lock(c) spin_lock(&c->lock) +#define inquiry_cache_unlock(c) spin_unlock(&c->lock) +#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock) +#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock) + +static inline void inquiry_cache_init(struct hci_dev *hdev) +{ + struct inquiry_cache *c = &hdev->inq_cache; + spin_lock_init(&c->lock); + c->list = NULL; +} + +static inline int inquiry_cache_empty(struct hci_dev *hdev) +{ + struct inquiry_cache *c = &hdev->inq_cache; + return c->list == NULL; +} + +static inline long inquiry_cache_age(struct hci_dev *hdev) +{ + struct inquiry_cache *c = &hdev->inq_cache; + return jiffies - c->timestamp; +} + +static inline long inquiry_entry_age(struct inquiry_entry *e) +{ + return jiffies - e->timestamp; +} + +struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); +void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data); + +/* ----- HCI Connections ----- */ +enum { + HCI_CONN_AUTH_PEND, + HCI_CONN_ENCRYPT_PEND, + HCI_CONN_RSWITCH_PEND, + HCI_CONN_MODE_CHANGE_PEND, + HCI_CONN_SCO_SETUP_PEND, +}; + +static inline void hci_conn_hash_init(struct hci_dev *hdev) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + INIT_LIST_HEAD(&h->list); + spin_lock_init(&h->lock); + h->acl_num = 0; + h->sco_num = 0; +} + +static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + list_add(&c->list, &h->list); + if (c->type == ACL_LINK) + h->acl_num++; + else + h->sco_num++; +} + +static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + list_del(&c->list); + if (c->type == ACL_LINK) + h->acl_num--; + else + h->sco_num--; +} + +static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, + __u16 handle) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct list_head *p; + struct hci_conn *c; + + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->handle == handle) + return c; + } + return NULL; +} + +static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, + __u8 type, bdaddr_t *ba) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct list_head *p; + struct hci_conn *c; + + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->type == type && !bacmp(&c->dst, ba)) + return c; + } + return NULL; +} + +static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, + __u8 type, __u16 state) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct list_head *p; + struct hci_conn *c; + + list_for_each(p, &h->list) { + c = list_entry(p, struct hci_conn, list); + if (c->type == type && c->state == state) + return c; + } + return NULL; +} + +void hci_acl_connect(struct hci_conn *conn); +void hci_acl_disconn(struct hci_conn *conn, __u8 reason); +void hci_add_sco(struct hci_conn *conn, __u16 handle); +void hci_setup_sync(struct hci_conn *conn, __u16 handle); +void hci_sco_setup(struct hci_conn *conn, __u8 status); + +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); +int hci_conn_del(struct hci_conn *conn); +void hci_conn_hash_flush(struct hci_dev *hdev); +void hci_conn_check_pending(struct hci_dev *hdev); + +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type); +int hci_conn_check_link_mode(struct hci_conn *conn); +int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); +int hci_conn_change_link_key(struct hci_conn *conn); +int hci_conn_switch_role(struct hci_conn *conn, __u8 role); + +void hci_conn_enter_active_mode(struct hci_conn *conn); +void hci_conn_enter_sniff_mode(struct hci_conn *conn); + +void hci_conn_hold_device(struct hci_conn *conn); +void hci_conn_put_device(struct hci_conn *conn); + +static inline void hci_conn_hold(struct hci_conn *conn) +{ + atomic_inc(&conn->refcnt); + del_timer(&conn->disc_timer); +} + +static inline void hci_conn_put(struct hci_conn *conn) +{ + if (atomic_dec_and_test(&conn->refcnt)) { + unsigned long timeo; + if (conn->type == ACL_LINK) { + del_timer(&conn->idle_timer); + if (conn->state == BT_CONNECTED) { + timeo = msecs_to_jiffies(conn->disc_timeout); + if (!conn->out) + timeo *= 2; + } else + timeo = msecs_to_jiffies(10); + } else + timeo = msecs_to_jiffies(10); + mod_timer(&conn->disc_timer, jiffies + timeo); + } +} + +/* ----- HCI Devices ----- */ +static inline void __hci_dev_put(struct hci_dev *d) +{ + if (atomic_dec_and_test(&d->refcnt)) + d->destruct(d); +} + +static inline void hci_dev_put(struct hci_dev *d) +{ + __hci_dev_put(d); + module_put(d->owner); +} + +static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) +{ + atomic_inc(&d->refcnt); + return d; +} + +static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) +{ + if (try_module_get(d->owner)) + return __hci_dev_hold(d); + return NULL; +} + +#define hci_dev_lock(d) spin_lock(&d->lock) +#define hci_dev_unlock(d) spin_unlock(&d->lock) +#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock) +#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock) + +struct hci_dev *hci_dev_get(int index); +struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); + +struct hci_dev *hci_alloc_dev(void); +void hci_free_dev(struct hci_dev *hdev); +int hci_register_dev(struct hci_dev *hdev); +int hci_unregister_dev(struct hci_dev *hdev); +int hci_suspend_dev(struct hci_dev *hdev); +int hci_resume_dev(struct hci_dev *hdev); +int hci_dev_open(__u16 dev); +int hci_dev_close(__u16 dev); +int hci_dev_reset(__u16 dev); +int hci_dev_reset_stat(__u16 dev); +int hci_dev_cmd(unsigned int cmd, void __user *arg); +int hci_get_dev_list(void __user *arg); +int hci_get_dev_info(void __user *arg); +int hci_get_conn_list(void __user *arg); +int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); +int hci_get_auth_info(struct hci_dev *hdev, void __user *arg); +int hci_inquiry(void __user *arg); + +struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_blacklist_clear(struct hci_dev *hdev); + +void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); + +int hci_recv_frame(struct sk_buff *skb); +int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count); +int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count); + +int hci_register_sysfs(struct hci_dev *hdev); +void hci_unregister_sysfs(struct hci_dev *hdev); +void hci_conn_init_sysfs(struct hci_conn *conn); +void hci_conn_add_sysfs(struct hci_conn *conn); +void hci_conn_del_sysfs(struct hci_conn *conn); + +#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) + +/* ----- LMP capabilities ----- */ +#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) +#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT) +#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) +#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) +#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) +#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) + +/* ----- HCI protocols ----- */ +struct hci_proto { + char *name; + unsigned int id; + unsigned long flags; + + void *priv; + + int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); + int (*connect_cfm) (struct hci_conn *conn, __u8 status); + int (*disconn_ind) (struct hci_conn *conn); + int (*disconn_cfm) (struct hci_conn *conn, __u8 reason); + int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); + int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); + int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); +}; + +static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) +{ + register struct hci_proto *hp; + int mask = 0; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->connect_ind) + mask |= hp->connect_ind(hdev, bdaddr, type); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->connect_ind) + mask |= hp->connect_ind(hdev, bdaddr, type); + + return mask; +} + +static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->connect_cfm) + hp->connect_cfm(conn, status); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->connect_cfm) + hp->connect_cfm(conn, status); +} + +static inline int hci_proto_disconn_ind(struct hci_conn *conn) +{ + register struct hci_proto *hp; + int reason = 0x13; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->disconn_ind) + reason = hp->disconn_ind(conn); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->disconn_ind) + reason = hp->disconn_ind(conn); + + return reason; +} + +static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->disconn_cfm) + hp->disconn_cfm(conn, reason); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->disconn_cfm) + hp->disconn_cfm(conn, reason); +} + +static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) +{ + register struct hci_proto *hp; + __u8 encrypt; + + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + return; + + encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); +} + +static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt) +{ + register struct hci_proto *hp; + + hp = hci_proto[HCI_PROTO_L2CAP]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); + + hp = hci_proto[HCI_PROTO_SCO]; + if (hp && hp->security_cfm) + hp->security_cfm(conn, status, encrypt); +} + +int hci_register_proto(struct hci_proto *hproto); +int hci_unregister_proto(struct hci_proto *hproto); + +/* ----- HCI callbacks ----- */ +struct hci_cb { + struct list_head list; + + char *name; + + void (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt); + void (*key_change_cfm) (struct hci_conn *conn, __u8 status); + void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role); +}; + +static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) +{ + struct list_head *p; + __u8 encrypt; + + hci_proto_auth_cfm(conn, status); + + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + return; + + encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->security_cfm) + cb->security_cfm(conn, status, encrypt); + } + read_unlock_bh(&hci_cb_list_lock); +} + +static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt) +{ + struct list_head *p; + + if (conn->sec_level == BT_SECURITY_SDP) + conn->sec_level = BT_SECURITY_LOW; + + hci_proto_encrypt_cfm(conn, status, encrypt); + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->security_cfm) + cb->security_cfm(conn, status, encrypt); + } + read_unlock_bh(&hci_cb_list_lock); +} + +static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status) +{ + struct list_head *p; + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->key_change_cfm) + cb->key_change_cfm(conn, status); + } + read_unlock_bh(&hci_cb_list_lock); +} + +static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, __u8 role) +{ + struct list_head *p; + + read_lock_bh(&hci_cb_list_lock); + list_for_each(p, &hci_cb_list) { + struct hci_cb *cb = list_entry(p, struct hci_cb, list); + if (cb->role_switch_cfm) + cb->role_switch_cfm(conn, status, role); + } + read_unlock_bh(&hci_cb_list_lock); +} + +int hci_register_cb(struct hci_cb *hcb); +int hci_unregister_cb(struct hci_cb *hcb); + +int hci_register_notifier(struct notifier_block *nb); +int hci_unregister_notifier(struct notifier_block *nb); + +int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); +void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); +void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); + +void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); + +void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); + +/* ----- HCI Sockets ----- */ +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); + +/* HCI info for socket */ +#define hci_pi(sk) ((struct hci_pinfo *) sk) + +struct hci_pinfo { + struct bt_sock bt; + struct hci_dev *hdev; + struct hci_filter filter; + __u32 cmsg_mask; +}; + +/* HCI security filter */ +#define HCI_SFLT_MAX_OGF 5 + +struct hci_sec_filter { + __u32 type_mask; + __u32 event_mask[2]; + __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; +}; + +/* ----- HCI requests ----- */ +#define HCI_REQ_DONE 0 +#define HCI_REQ_PEND 1 +#define HCI_REQ_CANCELED 2 + +#define hci_req_lock(d) mutex_lock(&d->req_lock) +#define hci_req_unlock(d) mutex_unlock(&d->req_lock) + +void hci_req_complete(struct hci_dev *hdev, int result); + +#endif /* __HCI_CORE_H */ diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h new file mode 100644 index 00000000..c819c8bf --- /dev/null +++ b/include/net/bluetooth/l2cap.h @@ -0,0 +1,428 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> + Copyright (C) 2010 Google Inc. + + Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __L2CAP_H +#define __L2CAP_H + +/* L2CAP defaults */ +#define L2CAP_DEFAULT_MTU 672 +#define L2CAP_DEFAULT_MIN_MTU 48 +#define L2CAP_DEFAULT_FLUSH_TO 0xffff +#define L2CAP_DEFAULT_TX_WINDOW 63 +#define L2CAP_DEFAULT_MAX_TX 3 +#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */ +#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ +#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ +#define L2CAP_DEFAULT_ACK_TO 200 +#define L2CAP_LOCAL_BUSY_TRIES 12 + +#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ +#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ + +/* L2CAP socket address */ +struct sockaddr_l2 { + sa_family_t l2_family; + __le16 l2_psm; + bdaddr_t l2_bdaddr; + __le16 l2_cid; +}; + +/* L2CAP socket options */ +#define L2CAP_OPTIONS 0x01 +struct l2cap_options { + __u16 omtu; + __u16 imtu; + __u16 flush_to; + __u8 mode; + __u8 fcs; + __u8 max_tx; + __u16 txwin_size; +}; + +#define L2CAP_CONNINFO 0x02 +struct l2cap_conninfo { + __u16 hci_handle; + __u8 dev_class[3]; +}; + +#define L2CAP_LM 0x03 +#define L2CAP_LM_MASTER 0x0001 +#define L2CAP_LM_AUTH 0x0002 +#define L2CAP_LM_ENCRYPT 0x0004 +#define L2CAP_LM_TRUSTED 0x0008 +#define L2CAP_LM_RELIABLE 0x0010 +#define L2CAP_LM_SECURE 0x0020 + +/* L2CAP command codes */ +#define L2CAP_COMMAND_REJ 0x01 +#define L2CAP_CONN_REQ 0x02 +#define L2CAP_CONN_RSP 0x03 +#define L2CAP_CONF_REQ 0x04 +#define L2CAP_CONF_RSP 0x05 +#define L2CAP_DISCONN_REQ 0x06 +#define L2CAP_DISCONN_RSP 0x07 +#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_INFO_REQ 0x0a +#define L2CAP_INFO_RSP 0x0b + +/* L2CAP feature mask */ +#define L2CAP_FEAT_FLOWCTL 0x00000001 +#define L2CAP_FEAT_RETRANS 0x00000002 +#define L2CAP_FEAT_ERTM 0x00000008 +#define L2CAP_FEAT_STREAMING 0x00000010 +#define L2CAP_FEAT_FCS 0x00000020 +#define L2CAP_FEAT_FIXED_CHAN 0x00000080 + +/* L2CAP checksum option */ +#define L2CAP_FCS_NONE 0x00 +#define L2CAP_FCS_CRC16 0x01 + +/* L2CAP Control Field bit masks */ +#define L2CAP_CTRL_SAR 0xC000 +#define L2CAP_CTRL_REQSEQ 0x3F00 +#define L2CAP_CTRL_TXSEQ 0x007E +#define L2CAP_CTRL_RETRANS 0x0080 +#define L2CAP_CTRL_FINAL 0x0080 +#define L2CAP_CTRL_POLL 0x0010 +#define L2CAP_CTRL_SUPERVISE 0x000C +#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */ + +#define L2CAP_CTRL_TXSEQ_SHIFT 1 +#define L2CAP_CTRL_REQSEQ_SHIFT 8 +#define L2CAP_CTRL_SAR_SHIFT 14 + +/* L2CAP Supervisory Function */ +#define L2CAP_SUPER_RCV_READY 0x0000 +#define L2CAP_SUPER_REJECT 0x0004 +#define L2CAP_SUPER_RCV_NOT_READY 0x0008 +#define L2CAP_SUPER_SELECT_REJECT 0x000C + +/* L2CAP Segmentation and Reassembly */ +#define L2CAP_SDU_UNSEGMENTED 0x0000 +#define L2CAP_SDU_START 0x4000 +#define L2CAP_SDU_END 0x8000 +#define L2CAP_SDU_CONTINUE 0xC000 + +/* L2CAP structures */ +struct l2cap_hdr { + __le16 len; + __le16 cid; +} __packed; +#define L2CAP_HDR_SIZE 4 + +struct l2cap_cmd_hdr { + __u8 code; + __u8 ident; + __le16 len; +} __packed; +#define L2CAP_CMD_HDR_SIZE 4 + +struct l2cap_cmd_rej { + __le16 reason; +} __packed; + +struct l2cap_conn_req { + __le16 psm; + __le16 scid; +} __packed; + +struct l2cap_conn_rsp { + __le16 dcid; + __le16 scid; + __le16 result; + __le16 status; +} __packed; + +/* channel indentifier */ +#define L2CAP_CID_SIGNALING 0x0001 +#define L2CAP_CID_CONN_LESS 0x0002 +#define L2CAP_CID_DYN_START 0x0040 +#define L2CAP_CID_DYN_END 0xffff + +/* connect result */ +#define L2CAP_CR_SUCCESS 0x0000 +#define L2CAP_CR_PEND 0x0001 +#define L2CAP_CR_BAD_PSM 0x0002 +#define L2CAP_CR_SEC_BLOCK 0x0003 +#define L2CAP_CR_NO_MEM 0x0004 + +/* connect status */ +#define L2CAP_CS_NO_INFO 0x0000 +#define L2CAP_CS_AUTHEN_PEND 0x0001 +#define L2CAP_CS_AUTHOR_PEND 0x0002 + +struct l2cap_conf_req { + __le16 dcid; + __le16 flags; + __u8 data[0]; +} __packed; + +struct l2cap_conf_rsp { + __le16 scid; + __le16 flags; + __le16 result; + __u8 data[0]; +} __packed; + +#define L2CAP_CONF_SUCCESS 0x0000 +#define L2CAP_CONF_UNACCEPT 0x0001 +#define L2CAP_CONF_REJECT 0x0002 +#define L2CAP_CONF_UNKNOWN 0x0003 + +struct l2cap_conf_opt { + __u8 type; + __u8 len; + __u8 val[0]; +} __packed; +#define L2CAP_CONF_OPT_SIZE 2 + +#define L2CAP_CONF_HINT 0x80 +#define L2CAP_CONF_MASK 0x7f + +#define L2CAP_CONF_MTU 0x01 +#define L2CAP_CONF_FLUSH_TO 0x02 +#define L2CAP_CONF_QOS 0x03 +#define L2CAP_CONF_RFC 0x04 +#define L2CAP_CONF_FCS 0x05 + +#define L2CAP_CONF_MAX_SIZE 22 + +struct l2cap_conf_rfc { + __u8 mode; + __u8 txwin_size; + __u8 max_transmit; + __le16 retrans_timeout; + __le16 monitor_timeout; + __le16 max_pdu_size; +} __packed; + +#define L2CAP_MODE_BASIC 0x00 +#define L2CAP_MODE_RETRANS 0x01 +#define L2CAP_MODE_FLOWCTL 0x02 +#define L2CAP_MODE_ERTM 0x03 +#define L2CAP_MODE_STREAMING 0x04 + +struct l2cap_disconn_req { + __le16 dcid; + __le16 scid; +} __packed; + +struct l2cap_disconn_rsp { + __le16 dcid; + __le16 scid; +} __packed; + +struct l2cap_info_req { + __le16 type; +} __packed; + +struct l2cap_info_rsp { + __le16 type; + __le16 result; + __u8 data[0]; +} __packed; + +/* info type */ +#define L2CAP_IT_CL_MTU 0x0001 +#define L2CAP_IT_FEAT_MASK 0x0002 +#define L2CAP_IT_FIXED_CHAN 0x0003 + +/* info result */ +#define L2CAP_IR_SUCCESS 0x0000 +#define L2CAP_IR_NOTSUPP 0x0001 + +/* ----- L2CAP connections ----- */ +struct l2cap_chan_list { + struct sock *head; + rwlock_t lock; + long num; +}; + +struct l2cap_conn { + struct hci_conn *hcon; + + bdaddr_t *dst; + bdaddr_t *src; + + unsigned int mtu; + + __u32 feat_mask; + + __u8 info_state; + __u8 info_ident; + + struct timer_list info_timer; + + spinlock_t lock; + + struct sk_buff *rx_skb; + __u32 rx_len; + __u8 rx_ident; + __u8 tx_ident; + + __u8 disc_reason; + + struct l2cap_chan_list chan_list; +}; + +struct sock_del_list { + struct sock *sk; + struct list_head list; +}; + +#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 +#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 +#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 + +/* ----- L2CAP channel and socket info ----- */ +#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) +#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) +#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) +#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue) +#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) + +struct srej_list { + __u8 tx_seq; + struct list_head list; +}; + +struct l2cap_pinfo { + struct bt_sock bt; + __le16 psm; + __u16 dcid; + __u16 scid; + + __u16 imtu; + __u16 omtu; + __u16 flush_to; + __u8 mode; + __u8 num_conf_req; + __u8 num_conf_rsp; + + __u8 fcs; + __u8 sec_level; + __u8 role_switch; + __u8 force_reliable; + + __u8 conf_req[64]; + __u8 conf_len; + __u8 conf_state; + __u16 conn_state; + + __u8 next_tx_seq; + __u8 expected_ack_seq; + __u8 expected_tx_seq; + __u8 buffer_seq; + __u8 buffer_seq_srej; + __u8 srej_save_reqseq; + __u8 frames_sent; + __u8 unacked_frames; + __u8 retry_count; + __u8 num_acked; + __u16 sdu_len; + __u16 partial_sdu_len; + struct sk_buff *sdu; + + __u8 ident; + + __u8 tx_win; + __u8 max_tx; + __u8 remote_tx_win; + __u8 remote_max_tx; + __u16 retrans_timeout; + __u16 monitor_timeout; + __u16 remote_mps; + __u16 mps; + + __le16 sport; + + struct timer_list retrans_timer; + struct timer_list monitor_timer; + struct timer_list ack_timer; + struct sk_buff_head tx_queue; + struct sk_buff_head srej_queue; + struct sk_buff_head busy_queue; + struct work_struct busy_work; + struct srej_list srej_l; + struct l2cap_conn *conn; + struct sock *next_c; + struct sock *prev_c; +}; + +#define L2CAP_CONF_REQ_SENT 0x01 +#define L2CAP_CONF_INPUT_DONE 0x02 +#define L2CAP_CONF_OUTPUT_DONE 0x04 +#define L2CAP_CONF_MTU_DONE 0x08 +#define L2CAP_CONF_MODE_DONE 0x10 +#define L2CAP_CONF_CONNECT_PEND 0x20 +#define L2CAP_CONF_NO_FCS_RECV 0x40 +#define L2CAP_CONF_STATE2_DEVICE 0x80 + +#define L2CAP_CONF_MAX_CONF_REQ 2 +#define L2CAP_CONF_MAX_CONF_RSP 2 + +#define L2CAP_CONN_SAR_SDU 0x0001 +#define L2CAP_CONN_SREJ_SENT 0x0002 +#define L2CAP_CONN_WAIT_F 0x0004 +#define L2CAP_CONN_SREJ_ACT 0x0008 +#define L2CAP_CONN_SEND_PBIT 0x0010 +#define L2CAP_CONN_REMOTE_BUSY 0x0020 +#define L2CAP_CONN_LOCAL_BUSY 0x0040 +#define L2CAP_CONN_REJ_ACT 0x0080 +#define L2CAP_CONN_SEND_FBIT 0x0100 +#define L2CAP_CONN_RNR_SENT 0x0200 +#define L2CAP_CONN_SAR_RETRY 0x0400 + +#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); +#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); +#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); + +static inline int l2cap_tx_window_full(struct sock *sk) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int sub; + + sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64; + + if (sub < 0) + sub += 64; + + return sub == pi->remote_tx_win; +} + +#define __get_txseq(ctrl) ((ctrl) & L2CAP_CTRL_TXSEQ) >> 1 +#define __get_reqseq(ctrl) ((ctrl) & L2CAP_CTRL_REQSEQ) >> 8 +#define __is_iframe(ctrl) !((ctrl) & L2CAP_CTRL_FRAME_TYPE) +#define __is_sframe(ctrl) (ctrl) & L2CAP_CTRL_FRAME_TYPE +#define __is_sar_start(ctrl) ((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START + +void l2cap_load(void); + +#endif /* __L2CAP_H */ diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h new file mode 100644 index 00000000..71047bc0 --- /dev/null +++ b/include/net/bluetooth/rfcomm.h @@ -0,0 +1,368 @@ +/* + RFCOMM implementation for Linux Bluetooth stack (BlueZ). + Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> + Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __RFCOMM_H +#define __RFCOMM_H + +#define RFCOMM_PSM 3 + +#define RFCOMM_CONN_TIMEOUT (HZ * 30) +#define RFCOMM_DISC_TIMEOUT (HZ * 20) +#define RFCOMM_AUTH_TIMEOUT (HZ * 25) +#define RFCOMM_IDLE_TIMEOUT (HZ * 2) + +#define RFCOMM_DEFAULT_MTU 127 +#define RFCOMM_DEFAULT_CREDITS 7 + +#define RFCOMM_MAX_L2CAP_MTU 1013 +#define RFCOMM_MAX_CREDITS 40 + +#define RFCOMM_SKB_HEAD_RESERVE 8 +#define RFCOMM_SKB_TAIL_RESERVE 2 +#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE) + +#define RFCOMM_SABM 0x2f +#define RFCOMM_DISC 0x43 +#define RFCOMM_UA 0x63 +#define RFCOMM_DM 0x0f +#define RFCOMM_UIH 0xef + +#define RFCOMM_TEST 0x08 +#define RFCOMM_FCON 0x28 +#define RFCOMM_FCOFF 0x18 +#define RFCOMM_MSC 0x38 +#define RFCOMM_RPN 0x24 +#define RFCOMM_RLS 0x14 +#define RFCOMM_PN 0x20 +#define RFCOMM_NSC 0x04 + +#define RFCOMM_V24_FC 0x02 +#define RFCOMM_V24_RTC 0x04 +#define RFCOMM_V24_RTR 0x08 +#define RFCOMM_V24_IC 0x40 +#define RFCOMM_V24_DV 0x80 + +#define RFCOMM_RPN_BR_2400 0x0 +#define RFCOMM_RPN_BR_4800 0x1 +#define RFCOMM_RPN_BR_7200 0x2 +#define RFCOMM_RPN_BR_9600 0x3 +#define RFCOMM_RPN_BR_19200 0x4 +#define RFCOMM_RPN_BR_38400 0x5 +#define RFCOMM_RPN_BR_57600 0x6 +#define RFCOMM_RPN_BR_115200 0x7 +#define RFCOMM_RPN_BR_230400 0x8 + +#define RFCOMM_RPN_DATA_5 0x0 +#define RFCOMM_RPN_DATA_6 0x1 +#define RFCOMM_RPN_DATA_7 0x2 +#define RFCOMM_RPN_DATA_8 0x3 + +#define RFCOMM_RPN_STOP_1 0 +#define RFCOMM_RPN_STOP_15 1 + +#define RFCOMM_RPN_PARITY_NONE 0x0 +#define RFCOMM_RPN_PARITY_ODD 0x1 +#define RFCOMM_RPN_PARITY_EVEN 0x3 +#define RFCOMM_RPN_PARITY_MARK 0x5 +#define RFCOMM_RPN_PARITY_SPACE 0x7 + +#define RFCOMM_RPN_FLOW_NONE 0x00 + +#define RFCOMM_RPN_XON_CHAR 0x11 +#define RFCOMM_RPN_XOFF_CHAR 0x13 + +#define RFCOMM_RPN_PM_BITRATE 0x0001 +#define RFCOMM_RPN_PM_DATA 0x0002 +#define RFCOMM_RPN_PM_STOP 0x0004 +#define RFCOMM_RPN_PM_PARITY 0x0008 +#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010 +#define RFCOMM_RPN_PM_XON 0x0020 +#define RFCOMM_RPN_PM_XOFF 0x0040 +#define RFCOMM_RPN_PM_FLOW 0x3F00 + +#define RFCOMM_RPN_PM_ALL 0x3F7F + +struct rfcomm_hdr { + u8 addr; + u8 ctrl; + u8 len; // Actual size can be 2 bytes +} __packed; + +struct rfcomm_cmd { + u8 addr; + u8 ctrl; + u8 len; + u8 fcs; +} __packed; + +struct rfcomm_mcc { + u8 type; + u8 len; +} __packed; + +struct rfcomm_pn { + u8 dlci; + u8 flow_ctrl; + u8 priority; + u8 ack_timer; + __le16 mtu; + u8 max_retrans; + u8 credits; +} __packed; + +struct rfcomm_rpn { + u8 dlci; + u8 bit_rate; + u8 line_settings; + u8 flow_ctrl; + u8 xon_char; + u8 xoff_char; + __le16 param_mask; +} __packed; + +struct rfcomm_rls { + u8 dlci; + u8 status; +} __packed; + +struct rfcomm_msc { + u8 dlci; + u8 v24_sig; +} __packed; + +/* ---- Core structures, flags etc ---- */ + +struct rfcomm_session { + struct list_head list; + struct socket *sock; + struct timer_list timer; + unsigned long state; + unsigned long flags; + atomic_t refcnt; + int initiator; + + /* Default DLC parameters */ + int cfc; + uint mtu; + + struct list_head dlcs; +}; + +struct rfcomm_dlc { + struct list_head list; + struct rfcomm_session *session; + struct sk_buff_head tx_queue; + struct timer_list timer; + + spinlock_t lock; + unsigned long state; + unsigned long flags; + atomic_t refcnt; + u8 dlci; + u8 addr; + u8 priority; + u8 v24_sig; + u8 remote_v24_sig; + u8 mscex; + u8 out; + u8 sec_level; + u8 role_switch; + u32 defer_setup; + + uint mtu; + uint cfc; + uint rx_credits; + uint tx_credits; + + void *owner; + + void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb); + void (*state_change)(struct rfcomm_dlc *d, int err); + void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig); +}; + +/* DLC and session flags */ +#define RFCOMM_RX_THROTTLED 0 +#define RFCOMM_TX_THROTTLED 1 +#define RFCOMM_TIMED_OUT 2 +#define RFCOMM_MSC_PENDING 3 +#define RFCOMM_SEC_PENDING 4 +#define RFCOMM_AUTH_PENDING 5 +#define RFCOMM_AUTH_ACCEPT 6 +#define RFCOMM_AUTH_REJECT 7 +#define RFCOMM_DEFER_SETUP 8 + +/* Scheduling flags and events */ +#define RFCOMM_SCHED_WAKEUP 31 + +/* MSC exchange flags */ +#define RFCOMM_MSCEX_TX 1 +#define RFCOMM_MSCEX_RX 2 +#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) + +/* CFC states */ +#define RFCOMM_CFC_UNKNOWN -1 +#define RFCOMM_CFC_DISABLED 0 +#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS + +/* ---- RFCOMM SEND RPN ---- */ +int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, + u8 bit_rate, u8 data_bits, u8 stop_bits, + u8 parity, u8 flow_ctrl_settings, + u8 xon_char, u8 xoff_char, u16 param_mask); + +/* ---- RFCOMM DLCs (channels) ---- */ +struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio); +void rfcomm_dlc_free(struct rfcomm_dlc *d); +int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel); +int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason); +int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); +int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); +int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); +void rfcomm_dlc_accept(struct rfcomm_dlc *d); + +#define rfcomm_dlc_lock(d) spin_lock(&d->lock) +#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) + +static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) +{ + atomic_inc(&d->refcnt); +} + +static inline void rfcomm_dlc_put(struct rfcomm_dlc *d) +{ + if (atomic_dec_and_test(&d->refcnt)) + rfcomm_dlc_free(d); +} + +extern void __rfcomm_dlc_throttle(struct rfcomm_dlc *d); +extern void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d); + +static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d) +{ + if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags)) + __rfcomm_dlc_throttle(d); +} + +static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +{ + if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags)) + __rfcomm_dlc_unthrottle(d); +} + +/* ---- RFCOMM sessions ---- */ +void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst); + +static inline void rfcomm_session_hold(struct rfcomm_session *s) +{ + atomic_inc(&s->refcnt); +} + +/* ---- RFCOMM sockets ---- */ +struct sockaddr_rc { + sa_family_t rc_family; + bdaddr_t rc_bdaddr; + u8 rc_channel; +}; + +#define RFCOMM_CONNINFO 0x02 +struct rfcomm_conninfo { + __u16 hci_handle; + __u8 dev_class[3]; +}; + +#define RFCOMM_LM 0x03 +#define RFCOMM_LM_MASTER 0x0001 +#define RFCOMM_LM_AUTH 0x0002 +#define RFCOMM_LM_ENCRYPT 0x0004 +#define RFCOMM_LM_TRUSTED 0x0008 +#define RFCOMM_LM_RELIABLE 0x0010 +#define RFCOMM_LM_SECURE 0x0020 + +#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk) + +struct rfcomm_pinfo { + struct bt_sock bt; + struct rfcomm_dlc *dlc; + u8 channel; + u8 sec_level; + u8 role_switch; +}; + +int rfcomm_init_sockets(void); +void rfcomm_cleanup_sockets(void); + +int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d); + +/* ---- RFCOMM TTY ---- */ +#define RFCOMM_MAX_DEV 256 + +#define RFCOMMCREATEDEV _IOW('R', 200, int) +#define RFCOMMRELEASEDEV _IOW('R', 201, int) +#define RFCOMMGETDEVLIST _IOR('R', 210, int) +#define RFCOMMGETDEVINFO _IOR('R', 211, int) +#define RFCOMMSTEALDLC _IOW('R', 220, int) + +#define RFCOMM_REUSE_DLC 0 +#define RFCOMM_RELEASE_ONHUP 1 +#define RFCOMM_HANGUP_NOW 2 +#define RFCOMM_TTY_ATTACHED 3 +#define RFCOMM_TTY_RELEASED 4 + +struct rfcomm_dev_req { + s16 dev_id; + u32 flags; + bdaddr_t src; + bdaddr_t dst; + u8 channel; +}; + +struct rfcomm_dev_info { + s16 id; + u32 flags; + u16 state; + bdaddr_t src; + bdaddr_t dst; + u8 channel; +}; + +struct rfcomm_dev_list_req { + u16 dev_num; + struct rfcomm_dev_info dev_info[0]; +}; + +int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); + +#ifdef CONFIG_BT_RFCOMM_TTY +int rfcomm_init_ttys(void); +void rfcomm_cleanup_ttys(void); +#else +static inline int rfcomm_init_ttys(void) +{ + return 0; +} +static inline void rfcomm_cleanup_ttys(void) +{ +} +#endif +#endif /* __RFCOMM_H */ diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h new file mode 100644 index 00000000..e28a2a77 --- /dev/null +++ b/include/net/bluetooth/sco.h @@ -0,0 +1,79 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL 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. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __SCO_H +#define __SCO_H + +/* SCO defaults */ +#define SCO_DEFAULT_MTU 500 +#define SCO_DEFAULT_FLUSH_TO 0xFFFF + +#define SCO_CONN_TIMEOUT (HZ * 40) +#define SCO_DISCONN_TIMEOUT (HZ * 2) +#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) + +/* SCO socket address */ +struct sockaddr_sco { + sa_family_t sco_family; + bdaddr_t sco_bdaddr; +}; + +/* SCO socket options */ +#define SCO_OPTIONS 0x01 +struct sco_options { + __u16 mtu; +}; + +#define SCO_CONNINFO 0x02 +struct sco_conninfo { + __u16 hci_handle; + __u8 dev_class[3]; +}; + +/* ---- SCO connections ---- */ +struct sco_conn { + struct hci_conn *hcon; + + bdaddr_t *dst; + bdaddr_t *src; + + spinlock_t lock; + struct sock *sk; + + unsigned int mtu; +}; + +#define sco_conn_lock(c) spin_lock(&c->lock); +#define sco_conn_unlock(c) spin_unlock(&c->lock); + +/* ----- SCO socket info ----- */ +#define sco_pi(sk) ((struct sco_pinfo *) sk) + +struct sco_pinfo { + struct bt_sock bt; + __u32 flags; + struct sco_conn *conn; +}; + +#endif /* __SCO_H */ diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h new file mode 100644 index 00000000..6da573c7 --- /dev/null +++ b/include/net/caif/caif_dev.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CAIF_DEV_H_ +#define CAIF_DEV_H_ + +#include <net/caif/caif_layer.h> +#include <net/caif/cfcnfg.h> +#include <linux/caif/caif_socket.h> +#include <linux/if.h> + +/** + * struct caif_param - CAIF parameters. + * @size: Length of data + * @data: Binary Data Blob + */ +struct caif_param { + u16 size; + u8 data[256]; +}; + +/** + * struct caif_connect_request - Request data for CAIF channel setup. + * @protocol: Type of CAIF protocol to use (at, datagram etc) + * @sockaddr: Socket address to connect. + * @priority: Priority of the connection. + * @link_selector: Link selector (high bandwidth or low latency) + * @link_name: Name of the CAIF Link Layer to use. + * @param: Connect Request parameters (CAIF_SO_REQ_PARAM). + * + * This struct is used when connecting a CAIF channel. + * It contains all CAIF channel configuration options. + */ +struct caif_connect_request { + enum caif_protocol_type protocol; + struct sockaddr_caif sockaddr; + enum caif_channel_priority priority; + enum caif_link_selector link_selector; + char link_name[16]; + struct caif_param param; +}; + +/** + * caif_connect_client - Connect a client to CAIF Core Stack. + * @config: Channel setup parameters, specifying what address + * to connect on the Modem. + * @client_layer: User implementation of client layer. This layer + * MUST have receive and control callback functions + * implemented. + * @ifindex: Link layer interface index used for this connection. + * @headroom: Head room needed by CAIF protocol. + * @tailroom: Tail room needed by CAIF protocol. + * + * This function connects a CAIF channel. The Client must implement + * the struct cflayer. This layer represents the Client layer and holds + * receive functions and control callback functions. Control callback + * function will receive information about connect/disconnect responses, + * flow control etc (see enum caif_control). + * E.g. CAIF Socket will call this function for each socket it connects + * and have one client_layer instance for each socket. + */ +int caif_connect_client(struct caif_connect_request *conn_req, + struct cflayer *client_layer, int *ifindex, + int *headroom, int *tailroom); + +/** + * caif_disconnect_client - Disconnects a client from the CAIF stack. + * + * @client_layer: Client layer to be removed. + */ +int caif_disconnect_client(struct cflayer *client_layer); + +/** + * caif_release_client - Release adaptation layer reference to client. + * + * @client_layer: Client layer. + * + * Releases a client/adaptation layer use of the caif stack. + * This function must be used after caif_disconnect_client to + * decrease the reference count of the service layer. + */ +void caif_release_client(struct cflayer *client_layer); + +/** + * connect_req_to_link_param - Translate configuration parameters + * from socket format to internal format. + * @cnfg: Pointer to configuration handler + * @con_req: Configuration parameters supplied in function + * caif_connect_client + * @channel_setup_param: Parameters supplied to the CAIF Core stack for + * setting up channels. + * + */ +int connect_req_to_link_param(struct cfcnfg *cnfg, + struct caif_connect_request *con_req, + struct cfctrl_link_param *channel_setup_param); + +/** + * get_caif_conf() - Get the configuration handler. + */ +struct cfcnfg *get_caif_conf(void); + + +#endif /* CAIF_DEV_H_ */ diff --git a/include/net/caif/caif_device.h b/include/net/caif/caif_device.h new file mode 100644 index 00000000..d02f044a --- /dev/null +++ b/include/net/caif/caif_device.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CAIF_DEVICE_H_ +#define CAIF_DEVICE_H_ +#include <linux/kernel.h> +#include <linux/net.h> +#include <linux/netdevice.h> +#include <linux/caif/caif_socket.h> +#include <net/caif/caif_device.h> + +/** + * struct caif_dev_common - data shared between CAIF drivers and stack. + * @flowctrl: Flow Control callback function. This function is + * supplied by CAIF Core Stack and is used by CAIF + * Link Layer to send flow-stop to CAIF Core. + * The flow information will be distributed to all + * clients of CAIF. + * + * @link_select: Profile of device, either high-bandwidth or + * low-latency. This member is set by CAIF Link + * Layer Device in order to indicate if this device + * is a high bandwidth or low latency device. + * + * @use_frag: CAIF Frames may be fragmented. + * Is set by CAIF Link Layer in order to indicate if the + * interface receives fragmented frames that must be + * assembled by CAIF Core Layer. + * + * @use_fcs: Indicate if Frame CheckSum (fcs) is used. + * Is set if the physical interface is + * using Frame Checksum on the CAIF Frames. + * + * @use_stx: Indicate STart of frame eXtension (stx) in use. + * Is set if the CAIF Link Layer expects + * CAIF Frames to start with the STX byte. + * + * This structure is shared between the CAIF drivers and the CAIF stack. + * It is used by the device to register its behavior. + * CAIF Core layer must set the member flowctrl in order to supply + * CAIF Link Layer with the flow control function. + * + */ + struct caif_dev_common { + void (*flowctrl)(struct net_device *net, int on); + enum caif_link_selector link_select; + int use_frag; + int use_fcs; + int use_stx; +}; + +#endif /* CAIF_DEVICE_H_ */ diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h new file mode 100644 index 00000000..c8b07a90 --- /dev/null +++ b/include/net/caif/caif_layer.h @@ -0,0 +1,277 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland / sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CAIF_LAYER_H_ +#define CAIF_LAYER_H_ + +#include <linux/list.h> + +struct cflayer; +struct cfpkt; +struct cfpktq; +struct caif_payload_info; +struct caif_packet_funcs; + + +#define CAIF_LAYER_NAME_SZ 16 + +/** + * caif_assert() - Assert function for CAIF. + * @assert: expression to evaluate. + * + * This function will print a error message and a do WARN_ON if the + * assertion failes. Normally this will do a stack up at the current location. + */ +#define caif_assert(assert) \ +do { \ + if (!(assert)) { \ + pr_err("caif:Assert detected:'%s'\n", #assert); \ + WARN_ON(!(assert)); \ + } \ +} while (0) + + +/** + * enum caif_ctrlcmd - CAIF Stack Control Signaling sent in layer.ctrlcmd(). + * + * @CAIF_CTRLCMD_FLOW_OFF_IND: Flow Control is OFF, transmit function + * should stop sending data + * + * @CAIF_CTRLCMD_FLOW_ON_IND: Flow Control is ON, transmit function + * can start sending data + * + * @CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND: Remote end modem has decided to close + * down channel + * + * @CAIF_CTRLCMD_INIT_RSP: Called initially when the layer below + * has finished initialization + * + * @CAIF_CTRLCMD_DEINIT_RSP: Called when de-initialization is + * complete + * + * @CAIF_CTRLCMD_INIT_FAIL_RSP: Called if initialization fails + * + * @_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: CAIF Link layer temporarily cannot + * send more packets. + * @_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND: Called if CAIF Link layer is able + * to send packets again. + * @_CAIF_CTRLCMD_PHYIF_DOWN_IND: Called if CAIF Link layer is going + * down. + * + * These commands are sent upwards in the CAIF stack to the CAIF Client. + * They are used for signaling originating from the modem or CAIF Link Layer. + * These are either responses (*_RSP) or events (*_IND). + */ +enum caif_ctrlcmd { + CAIF_CTRLCMD_FLOW_OFF_IND, + CAIF_CTRLCMD_FLOW_ON_IND, + CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, + CAIF_CTRLCMD_INIT_RSP, + CAIF_CTRLCMD_DEINIT_RSP, + CAIF_CTRLCMD_INIT_FAIL_RSP, + _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, + _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND, + _CAIF_CTRLCMD_PHYIF_DOWN_IND, +}; + +/** + * enum caif_modemcmd - Modem Control Signaling, sent from CAIF Client + * to the CAIF Link Layer or modem. + * + * @CAIF_MODEMCMD_FLOW_ON_REQ: Flow Control is ON, transmit function + * can start sending data. + * + * @CAIF_MODEMCMD_FLOW_OFF_REQ: Flow Control is OFF, transmit function + * should stop sending data. + * + * @_CAIF_MODEMCMD_PHYIF_USEFULL: Notify physical layer that it is in use + * + * @_CAIF_MODEMCMD_PHYIF_USELESS: Notify physical layer that it is + * no longer in use. + * + * These are requests sent 'downwards' in the stack. + * Flow ON, OFF can be indicated to the modem. + */ +enum caif_modemcmd { + CAIF_MODEMCMD_FLOW_ON_REQ = 0, + CAIF_MODEMCMD_FLOW_OFF_REQ = 1, + _CAIF_MODEMCMD_PHYIF_USEFULL = 3, + _CAIF_MODEMCMD_PHYIF_USELESS = 4 +}; + +/** + * enum caif_direction - CAIF Packet Direction. + * Indicate if a packet is to be sent out or to be received in. + * @CAIF_DIR_IN: Incoming packet received. + * @CAIF_DIR_OUT: Outgoing packet to be transmitted. + */ +enum caif_direction { + CAIF_DIR_IN = 0, + CAIF_DIR_OUT = 1 +}; + +/** + * struct cflayer - CAIF Stack layer. + * Defines the framework for the CAIF Core Stack. + * @up: Pointer up to the layer above. + * @dn: Pointer down to the layer below. + * @node: List node used when layer participate in a list. + * @receive: Packet receive function. + * @transmit: Packet transmit funciton. + * @ctrlcmd: Used for control signalling upwards in the stack. + * @modemcmd: Used for control signaling downwards in the stack. + * @prio: Priority of this layer. + * @id: The identity of this layer + * @type: The type of this layer + * @name: Name of the layer. + * + * This structure defines the layered structure in CAIF. + * + * It defines CAIF layering structure, used by all CAIF Layers and the + * layers interfacing CAIF. + * + * In order to integrate with CAIF an adaptation layer on top of the CAIF stack + * and PHY layer below the CAIF stack + * must be implemented. These layer must follow the design principles below. + * + * Principles for layering of protocol layers: + * - All layers must use this structure. If embedding it, then place this + * structure first in the layer specific structure. + * + * - Each layer should not depend on any others layer private data. + * + * - In order to send data upwards do + * layer->up->receive(layer->up, packet); + * + * - In order to send data downwards do + * layer->dn->transmit(layer->dn, info, packet); + */ +struct cflayer { + struct cflayer *up; + struct cflayer *dn; + struct list_head node; + + /* + * receive() - Receive Function. + * Contract: Each layer must implement a receive function passing the + * CAIF packets upwards in the stack. + * Packet handling rules: + * - The CAIF packet (cfpkt) cannot be accessed after + * passing it to the next layer using up->receive(). + * - If parsing of the packet fails, the packet must be + * destroyed and -1 returned from the function. + * - If parsing succeeds (and above layers return OK) then + * the function must return a value > 0. + * + * Returns result < 0 indicates an error, 0 or positive value + * indicates success. + * + * @layr: Pointer to the current layer the receive function is + * implemented for (this pointer). + * @cfpkt: Pointer to CaifPacket to be handled. + */ + int (*receive)(struct cflayer *layr, struct cfpkt *cfpkt); + + /* + * transmit() - Transmit Function. + * Contract: Each layer must implement a transmit function passing the + * CAIF packet downwards in the stack. + * Packet handling rules: + * - The CAIF packet (cfpkt) ownership is passed to the + * transmit function. This means that the the packet + * cannot be accessed after passing it to the below + * layer using dn->transmit(). + * + * - If transmit fails, however, the ownership is returned + * to thecaller. The caller of "dn->transmit()" must + * destroy or resend packet. + * + * - Return value less than zero means error, zero or + * greater than zero means OK. + * + * result < 0 indicates an error, 0 or positive value + * indicate success. + * + * @layr: Pointer to the current layer the receive function + * isimplemented for (this pointer). + * @cfpkt: Pointer to CaifPacket to be handled. + */ + int (*transmit) (struct cflayer *layr, struct cfpkt *cfpkt); + + /* + * cttrlcmd() - Control Function upwards in CAIF Stack. + * Used for signaling responses (CAIF_CTRLCMD_*_RSP) + * and asynchronous events from the modem (CAIF_CTRLCMD_*_IND) + * + * @layr: Pointer to the current layer the receive function + * is implemented for (this pointer). + * @ctrl: Control Command. + */ + void (*ctrlcmd) (struct cflayer *layr, enum caif_ctrlcmd ctrl, + int phyid); + + /* + * modemctrl() - Control Function used for controlling the modem. + * Used to signal down-wards in the CAIF stack. + * Returns 0 on success, < 0 upon failure. + * + * @layr: Pointer to the current layer the receive function + * is implemented for (this pointer). + * @ctrl: Control Command. + */ + int (*modemcmd) (struct cflayer *layr, enum caif_modemcmd ctrl); + + unsigned short prio; + unsigned int id; + unsigned int type; + char name[CAIF_LAYER_NAME_SZ]; +}; + +/** + * layer_set_up() - Set the up pointer for a specified layer. + * @layr: Layer where up pointer shall be set. + * @above: Layer above. + */ +#define layer_set_up(layr, above) ((layr)->up = (struct cflayer *)(above)) + +/** + * layer_set_dn() - Set the down pointer for a specified layer. + * @layr: Layer where down pointer shall be set. + * @below: Layer below. + */ +#define layer_set_dn(layr, below) ((layr)->dn = (struct cflayer *)(below)) + +/** + * struct dev_info - Physical Device info information about physical layer. + * @dev: Pointer to native physical device. + * @id: Physical ID of the physical connection used by the + * logical CAIF connection. Used by service layers to + * identify their physical id to Caif MUX (CFMUXL)so + * that the MUX can add the correct physical ID to the + * packet. + */ +struct dev_info { + void *dev; + unsigned int id; +}; + +/** + * struct caif_payload_info - Payload information embedded in packet (sk_buff). + * + * @dev_info: Information about the receiving device. + * + * @hdr_len: Header length, used to align pay load on 32bit boundary. + * + * @channel_id: Channel ID of the logical CAIF connection. + * Used by mux to insert channel id into the caif packet. + */ +struct caif_payload_info { + struct dev_info *dev_info; + unsigned short hdr_len; + unsigned short channel_id; +}; + +#endif /* CAIF_LAYER_H_ */ diff --git a/include/net/caif/caif_spi.h b/include/net/caif/caif_spi.h new file mode 100644 index 00000000..ce4570df --- /dev/null +++ b/include/net/caif/caif_spi.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Daniel Martensson / Daniel.Martensson@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CAIF_SPI_H_ +#define CAIF_SPI_H_ + +#include <net/caif/caif_device.h> + +#define SPI_CMD_WR 0x00 +#define SPI_CMD_RD 0x01 +#define SPI_CMD_EOT 0x02 +#define SPI_CMD_IND 0x04 + +#define SPI_DMA_BUF_LEN 8192 + +#define WL_SZ 2 /* 16 bits. */ +#define SPI_CMD_SZ 4 /* 32 bits. */ +#define SPI_IND_SZ 4 /* 32 bits. */ + +#define SPI_XFER 0 +#define SPI_SS_ON 1 +#define SPI_SS_OFF 2 +#define SPI_TERMINATE 3 + +/* Minimum time between different levels is 50 microseconds. */ +#define MIN_TRANSITION_TIME_USEC 50 + +/* Defines for calculating duration of SPI transfers for a particular + * number of bytes. + */ +#define SPI_MASTER_CLK_MHZ 13 +#define SPI_XFER_TIME_USEC(bytes, clk) (((bytes) * 8) / clk) + +/* Normally this should be aligned on the modem in order to benefit from full + * duplex transfers. However a size of 8188 provokes errors when running with + * the modem. These errors occur when packet sizes approaches 4 kB of data. + */ +#define CAIF_MAX_SPI_FRAME 4092 + +/* Maximum number of uplink CAIF frames that can reside in the same SPI frame. + * This number should correspond with the modem setting. The application side + * CAIF accepts any number of embedded downlink CAIF frames. + */ +#define CAIF_MAX_SPI_PKTS 9 + +/* Decides if SPI buffers should be prefilled with 0xFF pattern for easier + * debugging. Both TX and RX buffers will be filled before the transfer. + */ +#define CFSPI_DBG_PREFILL 0 + +/* Structure describing a SPI transfer. */ +struct cfspi_xfer { + u16 tx_dma_len; + u16 rx_dma_len; + void *va_tx; + dma_addr_t pa_tx; + void *va_rx; + dma_addr_t pa_rx; +}; + +/* Structure implemented by the SPI interface. */ +struct cfspi_ifc { + void (*ss_cb) (bool assert, struct cfspi_ifc *ifc); + void (*xfer_done_cb) (struct cfspi_ifc *ifc); + void *priv; +}; + +/* Structure implemented by SPI clients. */ +struct cfspi_dev { + int (*init_xfer) (struct cfspi_xfer *xfer, struct cfspi_dev *dev); + void (*sig_xfer) (bool xfer, struct cfspi_dev *dev); + struct cfspi_ifc *ifc; + char *name; + u32 clk_mhz; + void *priv; +}; + +/* Enumeration describing the CAIF SPI state. */ +enum cfspi_state { + CFSPI_STATE_WAITING = 0, + CFSPI_STATE_AWAKE, + CFSPI_STATE_FETCH_PKT, + CFSPI_STATE_GET_NEXT, + CFSPI_STATE_INIT_XFER, + CFSPI_STATE_WAIT_ACTIVE, + CFSPI_STATE_SIG_ACTIVE, + CFSPI_STATE_WAIT_XFER_DONE, + CFSPI_STATE_XFER_DONE, + CFSPI_STATE_WAIT_INACTIVE, + CFSPI_STATE_SIG_INACTIVE, + CFSPI_STATE_DELIVER_PKT, + CFSPI_STATE_MAX, +}; + +/* Structure implemented by SPI physical interfaces. */ +struct cfspi { + struct caif_dev_common cfdev; + struct net_device *ndev; + struct platform_device *pdev; + struct sk_buff_head qhead; + struct sk_buff_head chead; + u16 cmd; + u16 tx_cpck_len; + u16 tx_npck_len; + u16 rx_cpck_len; + u16 rx_npck_len; + struct cfspi_ifc ifc; + struct cfspi_xfer xfer; + struct cfspi_dev *dev; + unsigned long state; + struct work_struct work; + struct workqueue_struct *wq; + struct list_head list; + int flow_off_sent; + u32 qd_low_mark; + u32 qd_high_mark; + struct completion comp; + wait_queue_head_t wait; + spinlock_t lock; + bool flow_stop; +#ifdef CONFIG_DEBUG_FS + enum cfspi_state dbg_state; + u16 pcmd; + u16 tx_ppck_len; + u16 rx_ppck_len; + struct dentry *dbgfs_dir; + struct dentry *dbgfs_state; + struct dentry *dbgfs_frame; +#endif /* CONFIG_DEBUG_FS */ +}; + +extern int spi_frm_align; +extern int spi_up_head_align; +extern int spi_up_tail_align; +extern int spi_down_head_align; +extern int spi_down_tail_align; +extern struct platform_driver cfspi_spi_driver; + +void cfspi_dbg_state(struct cfspi *cfspi, int state); +int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len); +int cfspi_xmitlen(struct cfspi *cfspi); +int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len); +int cfspi_spi_remove(struct platform_device *pdev); +int cfspi_spi_probe(struct platform_device *pdev); +int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len); +int cfspi_xmitlen(struct cfspi *cfspi); +int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len); +void cfspi_xfer(struct work_struct *work); + +#endif /* CAIF_SPI_H_ */ diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h new file mode 100644 index 00000000..bd646faf --- /dev/null +++ b/include/net/caif/cfcnfg.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFCNFG_H_ +#define CFCNFG_H_ +#include <linux/spinlock.h> +#include <linux/netdevice.h> +#include <net/caif/caif_layer.h> +#include <net/caif/cfctrl.h> + +struct cfcnfg; + +/** + * enum cfcnfg_phy_type - Types of physical layers defined in CAIF Stack + * + * @CFPHYTYPE_FRAG: Fragmented frames physical interface. + * @CFPHYTYPE_CAIF: Generic CAIF physical interface + */ +enum cfcnfg_phy_type { + CFPHYTYPE_FRAG = 1, + CFPHYTYPE_CAIF, + CFPHYTYPE_MAX +}; + +/** + * enum cfcnfg_phy_preference - Physical preference HW Abstraction + * + * @CFPHYPREF_UNSPECIFIED: Default physical interface + * + * @CFPHYPREF_LOW_LAT: Default physical interface for low-latency + * traffic + * @CFPHYPREF_HIGH_BW: Default physical interface for high-bandwidth + * traffic + * @CFPHYPREF_LOOP: TEST only Loopback interface simulating modem + * responses. + * + */ +enum cfcnfg_phy_preference { + CFPHYPREF_UNSPECIFIED, + CFPHYPREF_LOW_LAT, + CFPHYPREF_HIGH_BW, + CFPHYPREF_LOOP +}; + +/** + * cfcnfg_create() - Create the CAIF configuration object. + */ +struct cfcnfg *cfcnfg_create(void); + +/** + * cfcnfg_remove() - Remove the CFCNFG object + * @cfg: config object + */ +void cfcnfg_remove(struct cfcnfg *cfg); + +/** + * cfcnfg_add_phy_layer() - Adds a physical layer to the CAIF stack. + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @phy_type: Specifies the type of physical interface, e.g. + * CFPHYTYPE_FRAG. + * @dev: Pointer to link layer device + * @phy_layer: Specify the physical layer. The transmit function + * MUST be set in the structure. + * @phyid: The assigned physical ID for this layer, used in + * cfcnfg_add_adapt_layer to specify PHY for the link. + * @pref: The phy (link layer) preference. + * @fcs: Specify if checksum is used in CAIF Framing Layer. + * @stx: Specify if Start Of Frame eXtention is used. + */ + +void +cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, + struct net_device *dev, struct cflayer *phy_layer, + u16 *phyid, enum cfcnfg_phy_preference pref, + bool fcs, bool stx); + +/** + * cfcnfg_del_phy_layer - Deletes an phy layer from the CAIF stack. + * + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @phy_layer: Adaptation layer to be removed. + */ +int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer); + +/** + * cfcnfg_disconn_adapt_layer - Disconnects an adaptation layer. + * + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @adap_layer: Adaptation layer to be removed. + */ +int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, + struct cflayer *adap_layer); + +/** + * cfcnfg_release_adap_layer - Used by client to release the adaptation layer. + * + * @adap_layer: Adaptation layer. + */ +void cfcnfg_release_adap_layer(struct cflayer *adap_layer); + +/** + * cfcnfg_add_adaptation_layer - Add an adaptation layer to the CAIF stack. + * + * The adaptation Layer is where the interface to application or higher-level + * driver functionality is implemented. + * + * @cnfg: Pointer to a CAIF configuration object, created by + * cfcnfg_create(). + * @param: Link setup parameters. + * @adap_layer: Specify the adaptation layer; the receive and + * flow-control functions MUST be set in the structure. + * @ifindex: Link layer interface index used for this connection. + * @proto_head: Protocol head-space needed by CAIF protocol, + * excluding link layer. + * @proto_tail: Protocol tail-space needed by CAIF protocol, + * excluding link layer. + */ +int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, + struct cfctrl_link_param *param, + struct cflayer *adap_layer, + int *ifindex, + int *proto_head, + int *proto_tail); + +/** + * cfcnfg_get_phyid() - Get physical ID, given type. + * Returns one of the physical interfaces matching the given type. + * Zero if no match is found. + * @cnfg: Configuration object + * @phy_pref: Caif Link Layer preference + */ +struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, + enum cfcnfg_phy_preference phy_pref); + +/** + * cfcnfg_get_named() - Get the Physical Identifier of CAIF Link Layer + * @cnfg: Configuration object + * @name: Name of the Physical Layer (Caif Link Layer) + */ +int cfcnfg_get_named(struct cfcnfg *cnfg, char *name); + +#endif /* CFCNFG_H_ */ diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h new file mode 100644 index 00000000..9402543f --- /dev/null +++ b/include/net/caif/cfctrl.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFCTRL_H_ +#define CFCTRL_H_ +#include <net/caif/caif_layer.h> +#include <net/caif/cfsrvl.h> + +/* CAIF Control packet commands */ +enum cfctrl_cmd { + CFCTRL_CMD_LINK_SETUP = 0, + CFCTRL_CMD_LINK_DESTROY = 1, + CFCTRL_CMD_LINK_ERR = 2, + CFCTRL_CMD_ENUM = 3, + CFCTRL_CMD_SLEEP = 4, + CFCTRL_CMD_WAKE = 5, + CFCTRL_CMD_LINK_RECONF = 6, + CFCTRL_CMD_START_REASON = 7, + CFCTRL_CMD_RADIO_SET = 8, + CFCTRL_CMD_MODEM_SET = 9, + CFCTRL_CMD_MASK = 0xf +}; + +/* Channel types */ +enum cfctrl_srv { + CFCTRL_SRV_DECM = 0, + CFCTRL_SRV_VEI = 1, + CFCTRL_SRV_VIDEO = 2, + CFCTRL_SRV_DBG = 3, + CFCTRL_SRV_DATAGRAM = 4, + CFCTRL_SRV_RFM = 5, + CFCTRL_SRV_UTIL = 6, + CFCTRL_SRV_MASK = 0xf +}; + +#define CFCTRL_RSP_BIT 0x20 +#define CFCTRL_ERR_BIT 0x10 + +struct cfctrl_rsp { + void (*linksetup_rsp)(struct cflayer *layer, u8 linkid, + enum cfctrl_srv serv, u8 phyid, + struct cflayer *adapt_layer); + void (*linkdestroy_rsp)(struct cflayer *layer, u8 linkid); + void (*linkerror_ind)(void); + void (*enum_rsp)(void); + void (*sleep_rsp)(void); + void (*wake_rsp)(void); + void (*restart_rsp)(void); + void (*radioset_rsp)(void); + void (*reject_rsp)(struct cflayer *layer, u8 linkid, + struct cflayer *client_layer);; +}; + +/* Link Setup Parameters for CAIF-Links. */ +struct cfctrl_link_param { + enum cfctrl_srv linktype;/* (T3,T0) Type of Channel */ + u8 priority; /* (P4,P0) Priority of the channel */ + u8 phyid; /* (U2-U0) Physical interface to connect */ + u8 endpoint; /* (E1,E0) Endpoint for data channels */ + u8 chtype; /* (H1,H0) Channel-Type, applies to + * VEI, DEBUG */ + union { + struct { + u8 connid; /* (D7,D0) Video LinkId */ + } video; + + struct { + u32 connid; /* (N31,Ngit0) Connection ID used + * for Datagram */ + } datagram; + + struct { + u32 connid; /* Connection ID used for RFM */ + char volume[20]; /* Volume to mount for RFM */ + } rfm; /* Configuration for RFM */ + + struct { + u16 fifosize_kb; /* Psock FIFO size in KB */ + u16 fifosize_bufs; /* Psock # signal buffers */ + char name[16]; /* Name of the PSOCK service */ + u8 params[255]; /* Link setup Parameters> */ + u16 paramlen; /* Length of Link Setup + * Parameters */ + } utility; /* Configuration for Utility Links (Psock) */ + } u; +}; + +/* This structure is used internally in CFCTRL */ +struct cfctrl_request_info { + int sequence_no; + enum cfctrl_cmd cmd; + u8 channel_id; + struct cfctrl_link_param param; + struct cflayer *client_layer; + struct list_head list; +}; + +struct cfctrl { + struct cfsrvl serv; + struct cfctrl_rsp res; + atomic_t req_seq_no; + atomic_t rsp_seq_no; + struct list_head list; + /* Protects from simultaneous access to first_req list */ + spinlock_t info_list_lock; +#ifndef CAIF_NO_LOOP + u8 loop_linkid; + int loop_linkused[256]; + /* Protects simultaneous access to loop_linkid and loop_linkused */ + spinlock_t loop_linkid_lock; +#endif + +}; + +void cfctrl_enum_req(struct cflayer *cfctrl, u8 physlinkid); +int cfctrl_linkup_request(struct cflayer *cfctrl, + struct cfctrl_link_param *param, + struct cflayer *user_layer); +int cfctrl_linkdown_req(struct cflayer *cfctrl, u8 linkid, + struct cflayer *client); +void cfctrl_sleep_req(struct cflayer *cfctrl); +void cfctrl_wake_req(struct cflayer *cfctrl); +void cfctrl_getstartreason_req(struct cflayer *cfctrl); +struct cflayer *cfctrl_create(void); +void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn); +void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up); +struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer); +bool cfctrl_req_eq(struct cfctrl_request_info *r1, + struct cfctrl_request_info *r2); +void cfctrl_insert_req(struct cfctrl *ctrl, + struct cfctrl_request_info *req); +struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, + struct cfctrl_request_info *req); +void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer); + +#endif /* CFCTRL_H_ */ diff --git a/include/net/caif/cffrml.h b/include/net/caif/cffrml.h new file mode 100644 index 00000000..3f14d2e1 --- /dev/null +++ b/include/net/caif/cffrml.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFFRML_H_ +#define CFFRML_H_ +#include <net/caif/caif_layer.h> + +struct cffrml; +struct cflayer *cffrml_create(u16 phyid, bool DoFCS); +void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up); +void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn); + +#endif /* CFFRML_H_ */ diff --git a/include/net/caif/cfmuxl.h b/include/net/caif/cfmuxl.h new file mode 100644 index 00000000..4e1b4f33 --- /dev/null +++ b/include/net/caif/cfmuxl.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFMUXL_H_ +#define CFMUXL_H_ +#include <net/caif/caif_layer.h> + +struct cfsrvl; +struct cffrml; + +struct cflayer *cfmuxl_create(void); +int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid); +struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid); +int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *up, u8 phyid); +struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 linkid); +bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid); +u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id); + +#endif /* CFMUXL_H_ */ diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h new file mode 100644 index 00000000..fbc681be --- /dev/null +++ b/include/net/caif/cfpkt.h @@ -0,0 +1,274 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFPKT_H_ +#define CFPKT_H_ +#include <net/caif/caif_layer.h> +#include <linux/types.h> +struct cfpkt; + +/* Create a CAIF packet. + * len: Length of packet to be created + * @return New packet. + */ +struct cfpkt *cfpkt_create(u16 len); + +/* Create a CAIF packet. + * data Data to copy. + * len Length of packet to be created + * @return New packet. + */ +struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len); +/* + * Destroy a CAIF Packet. + * pkt Packet to be destoyed. + */ +void cfpkt_destroy(struct cfpkt *pkt); + +/* + * Extract header from packet. + * + * pkt Packet to extract header data from. + * data Pointer to copy the header data into. + * len Length of head data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len); + +/* + * Peek header from packet. + * Reads data from packet without changing packet. + * + * pkt Packet to extract header data from. + * data Pointer to copy the header data into. + * len Length of head data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len); + +/* + * Extract header from trailer (end of packet). + * + * pkt Packet to extract header data from. + * data Pointer to copy the trailer data into. + * len Length of header data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_extr_trail(struct cfpkt *pkt, void *data, u16 len); + +/* + * Add header to packet. + * + * + * pkt Packet to add header data to. + * data Pointer to data to copy into the header. + * len Length of header data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_add_head(struct cfpkt *pkt, const void *data, u16 len); + +/* + * Add trailer to packet. + * + * + * pkt Packet to add trailer data to. + * data Pointer to data to copy into the trailer. + * len Length of trailer data to copy. + * @return zero on success and error code upon failure + */ +int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len); + +/* + * Pad trailer on packet. + * Moves data pointer in packet, no content copied. + * + * pkt Packet in which to pad trailer. + * len Length of padding to add. + * @return zero on success and error code upon failure + */ +int cfpkt_pad_trail(struct cfpkt *pkt, u16 len); + +/* + * Add a single byte to packet body (tail). + * + * pkt Packet in which to add byte. + * data Byte to add. + * @return zero on success and error code upon failure + */ +int cfpkt_addbdy(struct cfpkt *pkt, const u8 data); + +/* + * Add a data to packet body (tail). + * + * pkt Packet in which to add data. + * data Pointer to data to copy into the packet body. + * len Length of data to add. + * @return zero on success and error code upon failure + */ +int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len); + +/* + * Checks whether there are more data to process in packet. + * pkt Packet to check. + * @return true if more data are available in packet false otherwise + */ +bool cfpkt_more(struct cfpkt *pkt); + +/* + * Checks whether the packet is erroneous, + * i.e. if it has been attempted to extract more data than available in packet + * or writing more data than has been allocated in cfpkt_create(). + * pkt Packet to check. + * @return true on error false otherwise + */ +bool cfpkt_erroneous(struct cfpkt *pkt); + +/* + * Get the packet length. + * pkt Packet to get length from. + * @return Number of bytes in packet. + */ +u16 cfpkt_getlen(struct cfpkt *pkt); + +/* + * Set the packet length, by adjusting the trailer pointer according to length. + * pkt Packet to set length. + * len Packet length. + * @return Number of bytes in packet. + */ +int cfpkt_setlen(struct cfpkt *pkt, u16 len); + +/* + * cfpkt_append - Appends a packet's data to another packet. + * dstpkt: Packet to append data into, WILL BE FREED BY THIS FUNCTION + * addpkt: Packet to be appended and automatically released, + * WILL BE FREED BY THIS FUNCTION. + * expectlen: Packet's expected total length. This should be considered + * as a hint. + * NB: Input packets will be destroyed after appending and cannot be used + * after calling this function. + * @return The new appended packet. + */ +struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt, + u16 expectlen); + +/* + * cfpkt_split - Split a packet into two packets at the specified split point. + * pkt: Packet to be split (will contain the first part of the data on exit) + * pos: Position to split packet in two parts. + * @return The new packet, containing the second part of the data. + */ +struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos); + +/* + * Iteration function, iterates the packet buffers from start to end. + * + * Checksum iteration function used to iterate buffers + * (we may have packets consisting of a chain of buffers) + * pkt: Packet to calculate checksum for + * iter_func: Function pointer to iteration function + * chks: Checksum calculated so far. + * buf: Pointer to the buffer to checksum + * len: Length of buf. + * data: Initial checksum value. + * @return Checksum of buffer. + */ + +u16 cfpkt_iterate(struct cfpkt *pkt, + u16 (*iter_func)(u16 chks, void *buf, u16 len), + u16 data); + +/* Append by giving user access to packet buffer + * cfpkt Packet to append to + * buf Buffer inside pkt that user shall copy data into + * buflen Length of buffer and number of bytes added to packet + * @return 0 on error, 1 on success + */ +int cfpkt_raw_append(struct cfpkt *cfpkt, void **buf, unsigned int buflen); + +/* Extract by giving user access to packet buffer + * cfpkt Packet to extract from + * buf Buffer inside pkt that user shall copy data from + * buflen Length of buffer and number of bytes removed from packet + * @return 0 on error, 1 on success + */ +int cfpkt_raw_extract(struct cfpkt *cfpkt, void **buf, unsigned int buflen); + +/* Map from a "native" packet (e.g. Linux Socket Buffer) to a CAIF packet. + * dir - Direction indicating whether this packet is to be sent or received. + * nativepkt - The native packet to be transformed to a CAIF packet + * @return The mapped CAIF Packet CFPKT. + */ +struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt); + +/* Map from a CAIF packet to a "native" packet (e.g. Linux Socket Buffer). + * pkt - The CAIF packet to be transformed into a "native" packet. + * @return The native packet transformed from a CAIF packet. + */ +void *cfpkt_tonative(struct cfpkt *pkt); + +/* + * Insert a packet in the packet queue. + * pktq Packet queue to insert into + * pkt Packet to be inserted in queue + * prio Priority of packet + */ +void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, + unsigned short prio); + +/* + * Remove a packet from the packet queue. + * pktq Packet queue to fetch packets from. + * @return Dequeued packet. + */ +struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq); + +/* + * Peek into a packet from the packet queue. + * pktq Packet queue to fetch packets from. + * @return Peeked packet. + */ +struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq); + +/* + * Initiates the packet queue. + * @return Pointer to new packet queue. + */ +struct cfpktq *cfpktq_create(void); + +/* + * Get the number of packets in the queue. + * pktq Packet queue to fetch count from. + * @return Number of packets in queue. + */ +int cfpkt_qcount(struct cfpktq *pktq); + +/* + * Put content of packet into buffer for debuging purposes. + * pkt Packet to copy data from + * buf Buffer to copy data into + * buflen Length of data to copy + * @return Pointer to copied data + */ +char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen); + +/* + * Clones a packet and releases the original packet. + * This is used for taking ownership of a packet e.g queueing. + * pkt Packet to clone and release. + * @return Cloned packet. + */ +struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt); + + +/* + * Returns packet information for a packet. + * pkt Packet to get info from; + * @return Packet information + */ +struct caif_payload_info *cfpkt_info(struct cfpkt *pkt); +/*! @} */ +#endif /* CFPKT_H_ */ diff --git a/include/net/caif/cfserl.h b/include/net/caif/cfserl.h new file mode 100644 index 00000000..b8374321 --- /dev/null +++ b/include/net/caif/cfserl.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFSERL_H_ +#define CFSERL_H_ +#include <net/caif/caif_layer.h> + +struct cflayer *cfserl_create(int type, int instance, bool use_stx); +#endif /* CFSERL_H_ */ diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h new file mode 100644 index 00000000..b1fa87ee --- /dev/null +++ b/include/net/caif/cfsrvl.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Author: Sjur Brendeland/sjur.brandeland@stericsson.com + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef CFSRVL_H_ +#define CFSRVL_H_ +#include <linux/list.h> +#include <linux/stddef.h> +#include <linux/types.h> +#include <linux/kref.h> + +struct cfsrvl { + struct cflayer layer; + bool open; + bool phy_flow_on; + bool modem_flow_on; + bool supports_flowctrl; + void (*release)(struct kref *); + struct dev_info dev_info; + struct kref ref; +}; + +void cfsrvl_release(struct kref *kref); +struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info); +struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info, + int mtu_size); +struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info); +bool cfsrvl_phyid_match(struct cflayer *layer, int phyid); +void cfservl_destroy(struct cflayer *layer); +void cfsrvl_init(struct cfsrvl *service, + u8 channel_id, + struct dev_info *dev_info, + bool supports_flowctrl); +bool cfsrvl_ready(struct cfsrvl *service, int *err); +u8 cfsrvl_getphyid(struct cflayer *layer); + +static inline void cfsrvl_get(struct cflayer *layr) +{ + struct cfsrvl *s; + if (layr == NULL) + return; + s = container_of(layr, struct cfsrvl, layer); + kref_get(&s->ref); +} + +static inline void cfsrvl_put(struct cflayer *layr) +{ + struct cfsrvl *s; + if (layr == NULL) + return; + s = container_of(layr, struct cfsrvl, layer); + + WARN_ON(!s->release); + if (s->release) + kref_put(&s->ref, s->release); +} + +#endif /* CFSRVL_H_ */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h new file mode 100644 index 00000000..a1662a52 --- /dev/null +++ b/include/net/cfg80211.h @@ -0,0 +1,2487 @@ +#ifndef __NET_CFG80211_H +#define __NET_CFG80211_H +/* + * 802.11 device and configuration interface + * + * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/netdevice.h> +#include <linux/debugfs.h> +#include <linux/list.h> +#include <linux/netlink.h> +#include <linux/skbuff.h> +#include <linux/nl80211.h> +#include <linux/if_ether.h> +#include <linux/ieee80211.h> +#include <net/regulatory.h> + +/* remove once we remove the wext stuff */ +#include <net/iw_handler.h> +#include <linux/wireless.h> + + +/* + * wireless hardware capability structures + */ + +/** + * enum ieee80211_band - supported frequency bands + * + * The bands are assigned this way because the supported + * bitrates differ in these bands. + * + * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band + * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) + * @IEEE80211_NUM_BANDS: number of defined bands + */ +enum ieee80211_band { + IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, + IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, + + /* keep last */ + IEEE80211_NUM_BANDS +}; + +/** + * enum ieee80211_channel_flags - channel flags + * + * Channel flags set by the regulatory control code. + * + * @IEEE80211_CHAN_DISABLED: This channel is disabled. + * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted + * on this channel. + * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. + * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. + * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel + * is not permitted. + * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel + * is not permitted. + */ +enum ieee80211_channel_flags { + IEEE80211_CHAN_DISABLED = 1<<0, + IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, + IEEE80211_CHAN_NO_IBSS = 1<<2, + IEEE80211_CHAN_RADAR = 1<<3, + IEEE80211_CHAN_NO_HT40PLUS = 1<<4, + IEEE80211_CHAN_NO_HT40MINUS = 1<<5, +}; + +#define IEEE80211_CHAN_NO_HT40 \ + (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) + +/** + * struct ieee80211_channel - channel definition + * + * This structure describes a single channel for use + * with cfg80211. + * + * @center_freq: center frequency in MHz + * @hw_value: hardware-specific value for the channel + * @flags: channel flags from &enum ieee80211_channel_flags. + * @orig_flags: channel flags at registration time, used by regulatory + * code to support devices with additional restrictions + * @band: band this channel belongs to. + * @max_antenna_gain: maximum antenna gain in dBi + * @max_power: maximum transmission power (in dBm) + * @beacon_found: helper to regulatory code to indicate when a beacon + * has been found on this channel. Use regulatory_hint_found_beacon() + * to enable this, this is useful only on 5 GHz band. + * @orig_mag: internal use + * @orig_mpwr: internal use + */ +struct ieee80211_channel { + enum ieee80211_band band; + u16 center_freq; + u16 hw_value; + u32 flags; + int max_antenna_gain; + int max_power; + bool beacon_found; + u32 orig_flags; + int orig_mag, orig_mpwr; +}; + +/** + * enum ieee80211_rate_flags - rate flags + * + * Hardware/specification flags for rates. These are structured + * in a way that allows using the same bitrate structure for + * different bands/PHY modes. + * + * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short + * preamble on this bitrate; only relevant in 2.4GHz band and + * with CCK rates. + * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate + * when used with 802.11a (on the 5 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate + * when used with 802.11b (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate + * when used with 802.11g (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. + */ +enum ieee80211_rate_flags { + IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, + IEEE80211_RATE_MANDATORY_A = 1<<1, + IEEE80211_RATE_MANDATORY_B = 1<<2, + IEEE80211_RATE_MANDATORY_G = 1<<3, + IEEE80211_RATE_ERP_G = 1<<4, +}; + +/** + * struct ieee80211_rate - bitrate definition + * + * This structure describes a bitrate that an 802.11 PHY can + * operate with. The two values @hw_value and @hw_value_short + * are only for driver use when pointers to this structure are + * passed around. + * + * @flags: rate-specific flags + * @bitrate: bitrate in units of 100 Kbps + * @hw_value: driver/hardware value for this rate + * @hw_value_short: driver/hardware value for this rate when + * short preamble is used + */ +struct ieee80211_rate { + u32 flags; + u16 bitrate; + u16 hw_value, hw_value_short; +}; + +/** + * struct ieee80211_sta_ht_cap - STA's HT capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11n HT capabilities for an STA. + * + * @ht_supported: is HT supported by the STA + * @cap: HT capabilities map as described in 802.11n spec + * @ampdu_factor: Maximum A-MPDU length factor + * @ampdu_density: Minimum A-MPDU spacing + * @mcs: Supported MCS rates + */ +struct ieee80211_sta_ht_cap { + u16 cap; /* use IEEE80211_HT_CAP_ */ + bool ht_supported; + u8 ampdu_factor; + u8 ampdu_density; + struct ieee80211_mcs_info mcs; +}; + +/** + * struct ieee80211_supported_band - frequency band definition + * + * This structure describes a frequency band a wiphy + * is able to operate in. + * + * @channels: Array of channels the hardware can operate in + * in this band. + * @band: the band this structure represents + * @n_channels: Number of channels in @channels + * @bitrates: Array of bitrates the hardware can operate with + * in this band. Must be sorted to give a valid "supported + * rates" IE, i.e. CCK rates first, then OFDM. + * @n_bitrates: Number of bitrates in @bitrates + * @ht_cap: HT capabilities in this band + */ +struct ieee80211_supported_band { + struct ieee80211_channel *channels; + struct ieee80211_rate *bitrates; + enum ieee80211_band band; + int n_channels; + int n_bitrates; + struct ieee80211_sta_ht_cap ht_cap; +}; + +/* + * Wireless hardware/device configuration structures and methods + */ + +/** + * struct vif_params - describes virtual interface parameters + * @mesh_id: mesh ID to use + * @mesh_id_len: length of the mesh ID + * @use_4addr: use 4-address frames + */ +struct vif_params { + u8 *mesh_id; + int mesh_id_len; + int use_4addr; +}; + +/** + * struct key_params - key information + * + * Information about a key + * + * @key: key material + * @key_len: length of key material + * @cipher: cipher suite selector + * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used + * with the get_key() callback, must be in little endian, + * length given by @seq_len. + * @seq_len: length of @seq. + */ +struct key_params { + u8 *key; + u8 *seq; + int key_len; + int seq_len; + u32 cipher; +}; + +/** + * enum survey_info_flags - survey information flags + * + * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in + * + * Used by the driver to indicate which info in &struct survey_info + * it has filled in during the get_survey(). + */ +enum survey_info_flags { + SURVEY_INFO_NOISE_DBM = 1<<0, +}; + +/** + * struct survey_info - channel survey response + * + * @channel: the channel this survey record reports, mandatory + * @filled: bitflag of flags from &enum survey_info_flags + * @noise: channel noise in dBm. This and all following fields are + * optional + * + * Used by dump_survey() to report back per-channel survey information. + * + * This structure can later be expanded with things like + * channel duty cycle etc. + */ +struct survey_info { + struct ieee80211_channel *channel; + u32 filled; + s8 noise; +}; + +/** + * struct beacon_parameters - beacon parameters + * + * Used to configure the beacon for an interface. + * + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed + * @tail: tail portion of beacon (after TIM IE) + * or %NULL if not changed + * @interval: beacon interval or zero if not changed + * @dtim_period: DTIM period or zero if not changed + * @head_len: length of @head + * @tail_len: length of @tail + */ +struct beacon_parameters { + u8 *head, *tail; + int interval, dtim_period; + int head_len, tail_len; +}; + +/** + * enum plink_action - actions to perform in mesh peers + * + * @PLINK_ACTION_INVALID: action 0 is reserved + * @PLINK_ACTION_OPEN: start mesh peer link establishment + * @PLINK_ACTION_BLOCK: block traffic from this mesh peer + */ +enum plink_actions { + PLINK_ACTION_INVALID, + PLINK_ACTION_OPEN, + PLINK_ACTION_BLOCK, +}; + +/** + * struct station_parameters - station parameters + * + * Used to change and create a new station. + * + * @vlan: vlan interface station should belong to + * @supported_rates: supported rates in IEEE 802.11 format + * (or NULL for no change) + * @supported_rates_len: number of supported rates + * @sta_flags_mask: station flags that changed + * (bitmask of BIT(NL80211_STA_FLAG_...)) + * @sta_flags_set: station flags values + * (bitmask of BIT(NL80211_STA_FLAG_...)) + * @listen_interval: listen interval or -1 for no change + * @aid: AID or zero for no change + * @plink_action: plink action to take + * @ht_capa: HT capabilities of station + */ +struct station_parameters { + u8 *supported_rates; + struct net_device *vlan; + u32 sta_flags_mask, sta_flags_set; + int listen_interval; + u16 aid; + u8 supported_rates_len; + u8 plink_action; + struct ieee80211_ht_cap *ht_capa; +}; + +/** + * enum station_info_flags - station information flags + * + * Used by the driver to indicate which info in &struct station_info + * it has filled in during get_station() or dump_station(). + * + * @STATION_INFO_INACTIVE_TIME: @inactive_time filled + * @STATION_INFO_RX_BYTES: @rx_bytes filled + * @STATION_INFO_TX_BYTES: @tx_bytes filled + * @STATION_INFO_LLID: @llid filled + * @STATION_INFO_PLID: @plid filled + * @STATION_INFO_PLINK_STATE: @plink_state filled + * @STATION_INFO_SIGNAL: @signal filled + * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled + * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) + * @STATION_INFO_RX_PACKETS: @rx_packets filled + * @STATION_INFO_TX_PACKETS: @tx_packets filled + */ +enum station_info_flags { + STATION_INFO_INACTIVE_TIME = 1<<0, + STATION_INFO_RX_BYTES = 1<<1, + STATION_INFO_TX_BYTES = 1<<2, + STATION_INFO_LLID = 1<<3, + STATION_INFO_PLID = 1<<4, + STATION_INFO_PLINK_STATE = 1<<5, + STATION_INFO_SIGNAL = 1<<6, + STATION_INFO_TX_BITRATE = 1<<7, + STATION_INFO_RX_PACKETS = 1<<8, + STATION_INFO_TX_PACKETS = 1<<9, +}; + +/** + * enum station_info_rate_flags - bitrate info flags + * + * Used by the driver to indicate the specific rate transmission + * type for 802.11n transmissions. + * + * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled + * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission + * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval + */ +enum rate_info_flags { + RATE_INFO_FLAGS_MCS = 1<<0, + RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, + RATE_INFO_FLAGS_SHORT_GI = 1<<2, +}; + +/** + * struct rate_info - bitrate information + * + * Information about a receiving or transmitting bitrate + * + * @flags: bitflag of flags from &enum rate_info_flags + * @mcs: mcs index if struct describes a 802.11n bitrate + * @legacy: bitrate in 100kbit/s for 802.11abg + */ +struct rate_info { + u8 flags; + u8 mcs; + u16 legacy; +}; + +/** + * struct station_info - station information + * + * Station information filled by driver for get_station() and dump_station. + * + * @filled: bitflag of flags from &enum station_info_flags + * @inactive_time: time since last station activity (tx/rx) in milliseconds + * @rx_bytes: bytes received from this station + * @tx_bytes: bytes transmitted to this station + * @llid: mesh local link id + * @plid: mesh peer link id + * @plink_state: mesh peer link state + * @signal: signal strength of last received packet in dBm + * @txrate: current unicast bitrate to this station + * @rx_packets: packets received from this station + * @tx_packets: packets transmitted to this station + * @generation: generation number for nl80211 dumps. + * This number should increase every time the list of stations + * changes, i.e. when a station is added or removed, so that + * userspace can tell whether it got a consistent snapshot. + */ +struct station_info { + u32 filled; + u32 inactive_time; + u32 rx_bytes; + u32 tx_bytes; + u16 llid; + u16 plid; + u8 plink_state; + s8 signal; + struct rate_info txrate; + u32 rx_packets; + u32 tx_packets; + + int generation; +}; + +/** + * enum monitor_flags - monitor flags + * + * Monitor interface configuration flags. Note that these must be the bits + * according to the nl80211 flags. + * + * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS + * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @MONITOR_FLAG_CONTROL: pass control frames + * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering + * @MONITOR_FLAG_COOK_FRAMES: report frames after processing + */ +enum monitor_flags { + MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, + MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL, + MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, + MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, + MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, +}; + +/** + * enum mpath_info_flags - mesh path information flags + * + * Used by the driver to indicate which info in &struct mpath_info it has filled + * in during get_station() or dump_station(). + * + * @MPATH_INFO_FRAME_QLEN: @frame_qlen filled + * @MPATH_INFO_SN: @sn filled + * @MPATH_INFO_METRIC: @metric filled + * @MPATH_INFO_EXPTIME: @exptime filled + * @MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled + * @MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled + * @MPATH_INFO_FLAGS: @flags filled + */ +enum mpath_info_flags { + MPATH_INFO_FRAME_QLEN = BIT(0), + MPATH_INFO_SN = BIT(1), + MPATH_INFO_METRIC = BIT(2), + MPATH_INFO_EXPTIME = BIT(3), + MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), + MPATH_INFO_DISCOVERY_RETRIES = BIT(5), + MPATH_INFO_FLAGS = BIT(6), +}; + +/** + * struct mpath_info - mesh path information + * + * Mesh path information filled by driver for get_mpath() and dump_mpath(). + * + * @filled: bitfield of flags from &enum mpath_info_flags + * @frame_qlen: number of queued frames for this destination + * @sn: target sequence number + * @metric: metric (cost) of this mesh path + * @exptime: expiration time for the mesh path from now, in msecs + * @flags: mesh path flags + * @discovery_timeout: total mesh path discovery timeout, in msecs + * @discovery_retries: mesh path discovery retries + * @generation: generation number for nl80211 dumps. + * This number should increase every time the list of mesh paths + * changes, i.e. when a station is added or removed, so that + * userspace can tell whether it got a consistent snapshot. + */ +struct mpath_info { + u32 filled; + u32 frame_qlen; + u32 sn; + u32 metric; + u32 exptime; + u32 discovery_timeout; + u8 discovery_retries; + u8 flags; + + int generation; +}; + +/** + * struct bss_parameters - BSS parameters + * + * Used to change BSS parameters (mainly for AP mode). + * + * @use_cts_prot: Whether to use CTS protection + * (0 = no, 1 = yes, -1 = do not change) + * @use_short_preamble: Whether the use of short preambles is allowed + * (0 = no, 1 = yes, -1 = do not change) + * @use_short_slot_time: Whether the use of short slot time is allowed + * (0 = no, 1 = yes, -1 = do not change) + * @basic_rates: basic rates in IEEE 802.11 format + * (or NULL for no change) + * @basic_rates_len: number of basic rates + * @ap_isolate: do not forward packets between connected stations + */ +struct bss_parameters { + int use_cts_prot; + int use_short_preamble; + int use_short_slot_time; + u8 *basic_rates; + u8 basic_rates_len; + int ap_isolate; +}; + +struct mesh_config { + /* Timeouts in ms */ + /* Mesh plink management parameters */ + u16 dot11MeshRetryTimeout; + u16 dot11MeshConfirmTimeout; + u16 dot11MeshHoldingTimeout; + u16 dot11MeshMaxPeerLinks; + u8 dot11MeshMaxRetries; + u8 dot11MeshTTL; + bool auto_open_plinks; + /* HWMP parameters */ + u8 dot11MeshHWMPmaxPREQretries; + u32 path_refresh_time; + u16 min_discovery_timeout; + u32 dot11MeshHWMPactivePathTimeout; + u16 dot11MeshHWMPpreqMinInterval; + u16 dot11MeshHWMPnetDiameterTraversalTime; + u8 dot11MeshHWMPRootMode; +}; + +/** + * struct ieee80211_txq_params - TX queue parameters + * @queue: TX queue identifier (NL80211_TXQ_Q_*) + * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled + * @cwmin: Minimum contention window [a value of the form 2^n-1 in the range + * 1..32767] + * @cwmax: Maximum contention window [a value of the form 2^n-1 in the range + * 1..32767] + * @aifs: Arbitration interframe space [0..255] + */ +struct ieee80211_txq_params { + enum nl80211_txq_q queue; + u16 txop; + u16 cwmin; + u16 cwmax; + u8 aifs; +}; + +/* from net/wireless.h */ +struct wiphy; + +/* from net/ieee80211.h */ +struct ieee80211_channel; + +/** + * struct cfg80211_ssid - SSID description + * @ssid: the SSID + * @ssid_len: length of the ssid + */ +struct cfg80211_ssid { + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; +}; + +/** + * struct cfg80211_scan_request - scan request description + * + * @ssids: SSIDs to scan for (active scan only) + * @n_ssids: number of SSIDs + * @channels: channels to scan on. + * @n_channels: total number of channels to scan + * @ie: optional information element(s) to add into Probe Request or %NULL + * @ie_len: length of ie in octets + * @wiphy: the wiphy this was for + * @dev: the interface + * @aborted: (internal) scan request was notified as aborted + */ +struct cfg80211_scan_request { + struct cfg80211_ssid *ssids; + int n_ssids; + u32 n_channels; + const u8 *ie; + size_t ie_len; + + /* internal */ + struct wiphy *wiphy; + struct net_device *dev; + bool aborted; + + /* keep last */ + struct ieee80211_channel *channels[0]; +}; + +/** + * enum cfg80211_signal_type - signal type + * + * @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available + * @CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm) + * @CFG80211_SIGNAL_TYPE_UNSPEC: signal strength, increasing from 0 through 100 + */ +enum cfg80211_signal_type { + CFG80211_SIGNAL_TYPE_NONE, + CFG80211_SIGNAL_TYPE_MBM, + CFG80211_SIGNAL_TYPE_UNSPEC, +}; + +/** + * struct cfg80211_bss - BSS description + * + * This structure describes a BSS (which may also be a mesh network) + * for use in scan results and similar. + * + * @channel: channel this BSS is on + * @bssid: BSSID of the BSS + * @tsf: timestamp of last received update + * @beacon_interval: the beacon interval as from the frame + * @capability: the capability field in host byte order + * @information_elements: the information elements (Note that there + * is no guarantee that these are well-formed!); this is a pointer to + * either the beacon_ies or proberesp_ies depending on whether Probe + * Response frame has been received + * @len_information_elements: total length of the information elements + * @beacon_ies: the information elements from the last Beacon frame + * @len_beacon_ies: total length of the beacon_ies + * @proberesp_ies: the information elements from the last Probe Response frame + * @len_proberesp_ies: total length of the proberesp_ies + * @signal: signal strength value (type depends on the wiphy's signal_type) + * @free_priv: function pointer to free private data + * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes + */ +struct cfg80211_bss { + struct ieee80211_channel *channel; + + u8 bssid[ETH_ALEN]; + u64 tsf; + u16 beacon_interval; + u16 capability; + u8 *information_elements; + size_t len_information_elements; + u8 *beacon_ies; + size_t len_beacon_ies; + u8 *proberesp_ies; + size_t len_proberesp_ies; + + s32 signal; + + void (*free_priv)(struct cfg80211_bss *bss); + u8 priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + +/** + * ieee80211_bss_get_ie - find IE with given ID + * @bss: the bss to search + * @ie: the IE ID + * Returns %NULL if not found. + */ +const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); + + +/** + * struct cfg80211_crypto_settings - Crypto settings + * @wpa_versions: indicates which, if any, WPA versions are enabled + * (from enum nl80211_wpa_versions) + * @cipher_group: group key cipher suite (or 0 if unset) + * @n_ciphers_pairwise: number of AP supported unicast ciphers + * @ciphers_pairwise: unicast key cipher suites + * @n_akm_suites: number of AKM suites + * @akm_suites: AKM suites + * @control_port: Whether user space controls IEEE 802.1X port, i.e., + * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is + * required to assume that the port is unauthorized until authorized by + * user space. Otherwise, port is marked authorized by default. + */ +struct cfg80211_crypto_settings { + u32 wpa_versions; + u32 cipher_group; + int n_ciphers_pairwise; + u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES]; + int n_akm_suites; + u32 akm_suites[NL80211_MAX_NR_AKM_SUITES]; + bool control_port; +}; + +/** + * struct cfg80211_auth_request - Authentication request data + * + * This structure provides information needed to complete IEEE 802.11 + * authentication. + * + * @bss: The BSS to authenticate with. + * @auth_type: Authentication type (algorithm) + * @ie: Extra IEs to add to Authentication frame or %NULL + * @ie_len: Length of ie buffer in octets + * @key_len: length of WEP key for shared key authentication + * @key_idx: index of WEP key for shared key authentication + * @key: WEP key for shared key authentication + * @local_state_change: This is a request for a local state only, i.e., no + * Authentication frame is to be transmitted and authentication state is + * to be changed without having to wait for a response from the peer STA + * (AP). + */ +struct cfg80211_auth_request { + struct cfg80211_bss *bss; + const u8 *ie; + size_t ie_len; + enum nl80211_auth_type auth_type; + const u8 *key; + u8 key_len, key_idx; + bool local_state_change; +}; + +/** + * struct cfg80211_assoc_request - (Re)Association request data + * + * This structure provides information needed to complete IEEE 802.11 + * (re)association. + * @bss: The BSS to associate with. + * @ie: Extra IEs to add to (Re)Association Request frame or %NULL + * @ie_len: Length of ie buffer in octets + * @use_mfp: Use management frame protection (IEEE 802.11w) in this association + * @crypto: crypto settings + * @prev_bssid: previous BSSID, if not %NULL use reassociate frame + */ +struct cfg80211_assoc_request { + struct cfg80211_bss *bss; + const u8 *ie, *prev_bssid; + size_t ie_len; + struct cfg80211_crypto_settings crypto; + bool use_mfp; +}; + +/** + * struct cfg80211_deauth_request - Deauthentication request data + * + * This structure provides information needed to complete IEEE 802.11 + * deauthentication. + * + * @bss: the BSS to deauthenticate from + * @ie: Extra IEs to add to Deauthentication frame or %NULL + * @ie_len: Length of ie buffer in octets + * @reason_code: The reason code for the deauthentication + * @local_state_change: This is a request for a local state only, i.e., no + * Deauthentication frame is to be transmitted. + */ +struct cfg80211_deauth_request { + struct cfg80211_bss *bss; + const u8 *ie; + size_t ie_len; + u16 reason_code; + bool local_state_change; +}; + +/** + * struct cfg80211_disassoc_request - Disassociation request data + * + * This structure provides information needed to complete IEEE 802.11 + * disassocation. + * + * @bss: the BSS to disassociate from + * @ie: Extra IEs to add to Disassociation frame or %NULL + * @ie_len: Length of ie buffer in octets + * @reason_code: The reason code for the disassociation + * @local_state_change: This is a request for a local state only, i.e., no + * Disassociation frame is to be transmitted. + */ +struct cfg80211_disassoc_request { + struct cfg80211_bss *bss; + const u8 *ie; + size_t ie_len; + u16 reason_code; + bool local_state_change; +}; + +/** + * struct cfg80211_ibss_params - IBSS parameters + * + * This structure defines the IBSS parameters for the join_ibss() + * method. + * + * @ssid: The SSID, will always be non-null. + * @ssid_len: The length of the SSID, will always be non-zero. + * @bssid: Fixed BSSID requested, maybe be %NULL, if set do not + * search for IBSSs with a different BSSID. + * @channel: The channel to use if no IBSS can be found to join. + * @channel_fixed: The channel should be fixed -- do not search for + * IBSSs to join on other channels. + * @ie: information element(s) to include in the beacon + * @ie_len: length of that + * @beacon_interval: beacon interval to use + * @privacy: this is a protected network, keys will be configured + * after joining + * @basic_rates: bitmap of basic rates to use when creating the IBSS + */ +struct cfg80211_ibss_params { + u8 *ssid; + u8 *bssid; + struct ieee80211_channel *channel; + u8 *ie; + u8 ssid_len, ie_len; + u16 beacon_interval; + u32 basic_rates; + bool channel_fixed; + bool privacy; +}; + +/** + * struct cfg80211_connect_params - Connection parameters + * + * This structure provides information needed to complete IEEE 802.11 + * authentication and association. + * + * @channel: The channel to use or %NULL if not specified (auto-select based + * on scan results) + * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan + * results) + * @ssid: SSID + * @ssid_len: Length of ssid in octets + * @auth_type: Authentication type (algorithm) + * @ie: IEs for association request + * @ie_len: Length of assoc_ie in octets + * @privacy: indicates whether privacy-enabled APs should be used + * @crypto: crypto settings + * @key_len: length of WEP key for shared key authentication + * @key_idx: index of WEP key for shared key authentication + * @key: WEP key for shared key authentication + */ +struct cfg80211_connect_params { + struct ieee80211_channel *channel; + u8 *bssid; + u8 *ssid; + size_t ssid_len; + enum nl80211_auth_type auth_type; + u8 *ie; + size_t ie_len; + bool privacy; + struct cfg80211_crypto_settings crypto; + const u8 *key; + u8 key_len, key_idx; +}; + +/** + * enum wiphy_params_flags - set_wiphy_params bitfield values + * @WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed + * @WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed + * @WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed + * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed + * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed + */ +enum wiphy_params_flags { + WIPHY_PARAM_RETRY_SHORT = 1 << 0, + WIPHY_PARAM_RETRY_LONG = 1 << 1, + WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, + WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, + WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, +}; + +/* + * cfg80211_bitrate_mask - masks for bitrate control + */ +struct cfg80211_bitrate_mask { + struct { + u32 legacy; + /* TODO: add support for masking MCS rates; e.g.: */ + /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */ + } control[IEEE80211_NUM_BANDS]; +}; +/** + * struct cfg80211_pmksa - PMK Security Association + * + * This structure is passed to the set/del_pmksa() method for PMKSA + * caching. + * + * @bssid: The AP's BSSID. + * @pmkid: The PMK material itself. + */ +struct cfg80211_pmksa { + u8 *bssid; + u8 *pmkid; +}; + +/** + * struct cfg80211_ops - backend description for wireless configuration + * + * This struct is registered by fullmac card drivers and/or wireless stacks + * in order to handle configuration requests on their interfaces. + * + * All callbacks except where otherwise noted should return 0 + * on success or a negative error code. + * + * All operations are currently invoked under rtnl for consistency with the + * wireless extensions but this is subject to reevaluation as soon as this + * code is used more widely and we have a first user without wext. + * + * @suspend: wiphy device needs to be suspended + * @resume: wiphy device needs to be resumed + * + * @add_virtual_intf: create a new virtual interface with the given name, + * must set the struct wireless_dev's iftype. Beware: You must create + * the new netdev in the wiphy's network namespace! + * + * @del_virtual_intf: remove the virtual interface determined by ifindex. + * + * @change_virtual_intf: change type/configuration of virtual interface, + * keep the struct wireless_dev's iftype updated. + * + * @add_key: add a key with the given parameters. @mac_addr will be %NULL + * when adding a group key. + * + * @get_key: get information about the key with the given parameters. + * @mac_addr will be %NULL when requesting information for a group + * key. All pointers given to the @callback function need not be valid + * after it returns. This function should return an error if it is + * not possible to retrieve the key, -ENOENT if it doesn't exist. + * + * @del_key: remove a key given the @mac_addr (%NULL for a group key) + * and @key_index, return -ENOENT if the key doesn't exist. + * + * @set_default_key: set the default key on an interface + * + * @set_default_mgmt_key: set the default management frame key on an interface + * + * @add_beacon: Add a beacon with given parameters, @head, @interval + * and @dtim_period will be valid, @tail is optional. + * @set_beacon: Change the beacon parameters for an access point mode + * interface. This should reject the call when no beacon has been + * configured. + * @del_beacon: Remove beacon configuration and stop sending the beacon. + * + * @add_station: Add a new station. + * @del_station: Remove a station; @mac may be NULL to remove all stations. + * @change_station: Modify a given station. + * @get_station: get station information for the station identified by @mac + * @dump_station: dump station callback -- resume dump at index @idx + * + * @add_mpath: add a fixed mesh path + * @del_mpath: delete a given mesh path + * @change_mpath: change a given mesh path + * @get_mpath: get a mesh path for the given parameters + * @dump_mpath: dump mesh path callback -- resume dump at index @idx + * + * @get_mesh_params: Put the current mesh parameters into *params + * + * @set_mesh_params: Set mesh parameters. + * The mask is a bitfield which tells us which parameters to + * set, and which to leave alone. + * + * @change_bss: Modify parameters for a given BSS. + * + * @set_txq_params: Set TX queue parameters + * + * @set_channel: Set channel for a given wireless interface. Some devices + * may support multi-channel operation (by channel hopping) so cfg80211 + * doesn't verify much. Note, however, that the passed netdev may be + * %NULL as well if the user requested changing the channel for the + * device itself, or for a monitor interface. + * + * @scan: Request to do a scan. If returning zero, the scan request is given + * the driver, and will be valid until passed to cfg80211_scan_done(). + * For scan results, call cfg80211_inform_bss(); you can call this outside + * the scan/scan_done bracket too. + * + * @auth: Request to authenticate with the specified peer + * @assoc: Request to (re)associate with the specified peer + * @deauth: Request to deauthenticate from the specified peer + * @disassoc: Request to disassociate from the specified peer + * + * @connect: Connect to the ESS with the specified parameters. When connected, + * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. + * If the connection fails for some reason, call cfg80211_connect_result() + * with the status from the AP. + * @disconnect: Disconnect from the BSS/ESS. + * + * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call + * cfg80211_ibss_joined(), also call that function when changing BSSID due + * to a merge. + * @leave_ibss: Leave the IBSS. + * + * @set_wiphy_params: Notify that wiphy parameters have changed; + * @changed bitfield (see &enum wiphy_params_flags) describes which values + * have changed. The actual parameter values are available in + * struct wiphy. If returning an error, no value should be changed. + * + * @set_tx_power: set the transmit power according to the parameters + * @get_tx_power: store the current TX power into the dbm variable; + * return 0 if successful + * + * @set_wds_peer: set the WDS peer for a WDS interface + * + * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting + * functions to adjust rfkill hw state + * + * @dump_survey: get site survey information. + * + * @remain_on_channel: Request the driver to remain awake on the specified + * channel for the specified duration to complete an off-channel + * operation (e.g., public action frame exchange). When the driver is + * ready on the requested channel, it must indicate this with an event + * notification by calling cfg80211_ready_on_channel(). + * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. + * This allows the operation to be terminated prior to timeout based on + * the duration value. + * @action: Transmit an action frame + * + * @testmode_cmd: run a test mode command + * + * @set_bitrate_mask: set the bitrate mask configuration + * + * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac + * devices running firmwares capable of generating the (re) association + * RSN IE. It allows for faster roaming between WPA2 BSSIDs. + * @del_pmksa: Delete a cached PMKID. + * @flush_pmksa: Flush all cached PMKIDs. + * @set_power_mgmt: Configure WLAN power management. A timeout value of -1 + * allows the driver to adjust the dynamic ps timeout value. + * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. + * + */ +struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy); + int (*resume)(struct wiphy *wiphy); + + int (*add_virtual_intf)(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params); + int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev); + int (*change_virtual_intf)(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params); + + int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr, + struct key_params *params); + int (*get_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params*)); + int (*del_key)(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr); + int (*set_default_key)(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index); + int (*set_default_mgmt_key)(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index); + + int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); + + + int (*add_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); + int (*del_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac); + int (*change_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); + int (*get_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo); + int (*dump_station)(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo); + + int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop); + int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst); + int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop); + int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop, + struct mpath_info *pinfo); + int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *dst, u8 *next_hop, + struct mpath_info *pinfo); + int (*get_mesh_params)(struct wiphy *wiphy, + struct net_device *dev, + struct mesh_config *conf); + int (*set_mesh_params)(struct wiphy *wiphy, + struct net_device *dev, + const struct mesh_config *nconf, u32 mask); + int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params); + + int (*set_txq_params)(struct wiphy *wiphy, + struct ieee80211_txq_params *params); + + int (*set_channel)(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); + + int (*scan)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request); + + int (*auth)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_auth_request *req); + int (*assoc)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_assoc_request *req); + int (*deauth)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_deauth_request *req, + void *cookie); + int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_disassoc_request *req, + void *cookie); + + int (*connect)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); + int (*disconnect)(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); + + int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); + int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); + + int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); + + int (*set_tx_power)(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, int mbm); + int (*get_tx_power)(struct wiphy *wiphy, int *dbm); + + int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, + u8 *addr); + + void (*rfkill_poll)(struct wiphy *wiphy); + +#ifdef CONFIG_NL80211_TESTMODE + int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); +#endif + + int (*set_bitrate_mask)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask); + + int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, + int idx, struct survey_info *info); + + int (*set_pmksa)(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + int (*del_pmksa)(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); + + int (*remain_on_channel)(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, + u64 *cookie); + int (*cancel_remain_on_channel)(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie); + + int (*action)(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, + const u8 *buf, size_t len, u64 *cookie); + + int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout); + + int (*set_cqm_rssi_config)(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst); +}; + +/* + * wireless hardware and networking interfaces structures + * and registration/helper functions + */ + +/** + * enum wiphy_flags - wiphy capability flags + * + * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device + * has its own custom regulatory domain and cannot identify the + * ISO / IEC 3166 alpha2 it belongs to. When this is enabled + * we will disregard the first regulatory hint (when the + * initiator is %REGDOM_SET_BY_CORE). + * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will + * ignore regulatory domain settings until it gets its own regulatory + * domain via its regulatory_hint() unless the regulatory hint is + * from a country IE. After its gets its own regulatory domain it will + * only allow further regulatory domain settings to further enhance + * compliance. For example if channel 13 and 14 are disabled by this + * regulatory domain no user regulatory domain can enable these channels + * at a later time. This can be used for devices which do not have + * calibration information guaranteed for frequencies or settings + * outside of its regulatory domain. + * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure + * that passive scan flags and beaconing flags may not be lifted by + * cfg80211 due to regulatory beacon hints. For more information on beacon + * hints read the documenation for regulatory_hint_found_beacon() + * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this + * wiphy at all + * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled + * by default -- this flag will be set depending on the kernel's default + * on wiphy_new(), but can be changed by the driver if it has a good + * reason to override the default + * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station + * on a VLAN interface) + * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station + */ +enum wiphy_flags { + WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), + WIPHY_FLAG_STRICT_REGULATORY = BIT(1), + WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), + WIPHY_FLAG_NETNS_OK = BIT(3), + WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), + WIPHY_FLAG_4ADDR_AP = BIT(5), + WIPHY_FLAG_4ADDR_STATION = BIT(6), +}; + +struct mac_address { + u8 addr[ETH_ALEN]; +}; + +/** + * struct wiphy - wireless hardware description + * @reg_notifier: the driver's regulatory notification callback + * @regd: the driver's regulatory domain, if one was requested via + * the regulatory_hint() API. This can be used by the driver + * on the reg_notifier() if it chooses to ignore future + * regulatory domain changes caused by other drivers. + * @signal_type: signal type reported in &struct cfg80211_bss. + * @cipher_suites: supported cipher suites + * @n_cipher_suites: number of supported cipher suites + * @retry_short: Retry limit for short frames (dot11ShortRetryLimit) + * @retry_long: Retry limit for long frames (dot11LongRetryLimit) + * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); + * -1 = fragmentation disabled, only odd values >= 256 used + * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled + * @_net: the network namespace this wiphy currently lives in + * @perm_addr: permanent MAC address of this device + * @addr_mask: If the device supports multiple MAC addresses by masking, + * set this to a mask with variable bits set to 1, e.g. if the last + * four bits are variable then set it to 00:...:00:0f. The actual + * variable bits shall be determined by the interfaces added, with + * interfaces not matching the mask being rejected to be brought up. + * @n_addresses: number of addresses in @addresses. + * @addresses: If the device has more than one address, set this pointer + * to a list of addresses (6 bytes each). The first one will be used + * by default for perm_addr. In this case, the mask should be set to + * all-zeroes. In this case it is assumed that the device can handle + * the same number of arbitrary MAC addresses. + * @debugfsdir: debugfs directory used for this wiphy, will be renamed + * automatically on wiphy renames + * @dev: (virtual) struct device for this wiphy + * @wext: wireless extension handlers + * @priv: driver private data (sized according to wiphy_new() parameter) + * @interface_modes: bitmask of interfaces types valid for this wiphy, + * must be set by driver + * @flags: wiphy flags, see &enum wiphy_flags + * @bss_priv_size: each BSS struct has private data allocated with it, + * this variable determines its size + * @max_scan_ssids: maximum number of SSIDs the device can scan for in + * any given scan + * @max_scan_ie_len: maximum length of user-controlled IEs device can + * add to probe request frames transmitted during a scan, must not + * include fixed IEs like supported rates + * @coverage_class: current coverage class + * @fw_version: firmware version for ethtool reporting + * @hw_version: hardware version for ethtool reporting + * @max_num_pmkids: maximum number of PMKIDs supported by device + * @privid: a pointer that drivers can use to identify if an arbitrary + * wiphy is theirs, e.g. in global notifiers + * @bands: information about bands/channels supported by this device + */ +struct wiphy { + /* assign these fields before you register the wiphy */ + + /* permanent MAC address(es) */ + u8 perm_addr[ETH_ALEN]; + u8 addr_mask[ETH_ALEN]; + + u16 n_addresses; + struct mac_address *addresses; + + /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ + u16 interface_modes; + + u32 flags; + + enum cfg80211_signal_type signal_type; + + int bss_priv_size; + u8 max_scan_ssids; + u16 max_scan_ie_len; + + int n_cipher_suites; + const u32 *cipher_suites; + + u8 retry_short; + u8 retry_long; + u32 frag_threshold; + u32 rts_threshold; + u8 coverage_class; + + char fw_version[ETHTOOL_BUSINFO_LEN]; + u32 hw_version; + + u8 max_num_pmkids; + + /* If multiple wiphys are registered and you're handed e.g. + * a regular netdev with assigned ieee80211_ptr, you won't + * know whether it points to a wiphy your driver has registered + * or not. Assign this to something global to your driver to + * help determine whether you own this wiphy or not. */ + const void *privid; + + struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; + + /* Lets us get back the wiphy on the callback */ + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request); + + /* fields below are read-only, assigned by cfg80211 */ + + const struct ieee80211_regdomain *regd; + + /* the item in /sys/class/ieee80211/ points to this, + * you need use set_wiphy_dev() (see below) */ + struct device dev; + + /* dir in debugfs: ieee80211/<wiphyname> */ + struct dentry *debugfsdir; + +#ifdef CONFIG_NET_NS + /* the network namespace this phy lives in currently */ + struct net *_net; +#endif + +#ifdef CONFIG_CFG80211_WEXT + const struct iw_handler_def *wext; +#endif + + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +static inline struct net *wiphy_net(struct wiphy *wiphy) +{ + return read_pnet(&wiphy->_net); +} + +static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net) +{ + write_pnet(&wiphy->_net, net); +} + +/** + * wiphy_priv - return priv from wiphy + * + * @wiphy: the wiphy whose priv pointer to return + */ +static inline void *wiphy_priv(struct wiphy *wiphy) +{ + BUG_ON(!wiphy); + return &wiphy->priv; +} + +/** + * priv_to_wiphy - return the wiphy containing the priv + * + * @priv: a pointer previously returned by wiphy_priv + */ +static inline struct wiphy *priv_to_wiphy(void *priv) +{ + BUG_ON(!priv); + return container_of(priv, struct wiphy, priv); +} + +/** + * set_wiphy_dev - set device pointer for wiphy + * + * @wiphy: The wiphy whose device to bind + * @dev: The device to parent it to + */ +static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev) +{ + wiphy->dev.parent = dev; +} + +/** + * wiphy_dev - get wiphy dev pointer + * + * @wiphy: The wiphy whose device struct to look up + */ +static inline struct device *wiphy_dev(struct wiphy *wiphy) +{ + return wiphy->dev.parent; +} + +/** + * wiphy_name - get wiphy name + * + * @wiphy: The wiphy whose name to return + */ +static inline const char *wiphy_name(const struct wiphy *wiphy) +{ + return dev_name(&wiphy->dev); +} + +/** + * wiphy_new - create a new wiphy for use with cfg80211 + * + * @ops: The configuration operations for this device + * @sizeof_priv: The size of the private area to allocate + * + * Create a new wiphy and associate the given operations with it. + * @sizeof_priv bytes are allocated for private use. + * + * The returned pointer must be assigned to each netdev's + * ieee80211_ptr for proper operation. + */ +struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv); + +/** + * wiphy_register - register a wiphy with cfg80211 + * + * @wiphy: The wiphy to register. + * + * Returns a non-negative wiphy index or a negative error code. + */ +extern int wiphy_register(struct wiphy *wiphy); + +/** + * wiphy_unregister - deregister a wiphy from cfg80211 + * + * @wiphy: The wiphy to unregister. + * + * After this call, no more requests can be made with this priv + * pointer, but the call may sleep to wait for an outstanding + * request that is being handled. + */ +extern void wiphy_unregister(struct wiphy *wiphy); + +/** + * wiphy_free - free wiphy + * + * @wiphy: The wiphy to free + */ +extern void wiphy_free(struct wiphy *wiphy); + +/* internal structs */ +struct cfg80211_conn; +struct cfg80211_internal_bss; +struct cfg80211_cached_keys; + +#define MAX_AUTH_BSSES 4 + +/** + * struct wireless_dev - wireless per-netdev state + * + * This structure must be allocated by the driver/stack + * that uses the ieee80211_ptr field in struct net_device + * (this is intentional so it can be allocated along with + * the netdev.) + * + * @wiphy: pointer to hardware description + * @iftype: interface type + * @list: (private) Used to collect the interfaces + * @netdev: (private) Used to reference back to the netdev + * @current_bss: (private) Used by the internal configuration code + * @channel: (private) Used by the internal configuration code to track + * user-set AP, monitor and WDS channels for wireless extensions + * @bssid: (private) Used by the internal configuration code + * @ssid: (private) Used by the internal configuration code + * @ssid_len: (private) Used by the internal configuration code + * @wext: (private) Used by the internal wireless extensions compat code + * @use_4addr: indicates 4addr mode is used on this interface, must be + * set by driver (if supported) on add_interface BEFORE registering the + * netdev and may otherwise be used by driver read-only, will be update + * by cfg80211 on change_interface + * @action_registrations: list of registrations for action frames + * @action_registrations_lock: lock for the list + * @mtx: mutex used to lock data in this struct + * @cleanup_work: work struct used for cleanup that can't be done directly + */ +struct wireless_dev { + struct wiphy *wiphy; + enum nl80211_iftype iftype; + + /* the remainder of this struct should be private to cfg80211 */ + struct list_head list; + struct net_device *netdev; + + struct list_head action_registrations; + spinlock_t action_registrations_lock; + + struct mutex mtx; + + struct work_struct cleanup_work; + + bool use_4addr; + + /* currently used for IBSS and SME - might be rearranged later */ + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + enum { + CFG80211_SME_IDLE, + CFG80211_SME_CONNECTING, + CFG80211_SME_CONNECTED, + } sme_state; + struct cfg80211_conn *conn; + struct cfg80211_cached_keys *connect_keys; + + struct list_head event_list; + spinlock_t event_lock; + + struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; + struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; + struct cfg80211_internal_bss *current_bss; /* associated / joined */ + struct ieee80211_channel *channel; + + bool ps; + int ps_timeout; + +#ifdef CONFIG_CFG80211_WEXT + /* wext data */ + struct { + struct cfg80211_ibss_params ibss; + struct cfg80211_connect_params connect; + struct cfg80211_cached_keys *keys; + u8 *ie; + size_t ie_len; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + s8 default_key, default_mgmt_key; + bool prev_bssid_valid; + } wext; +#endif +}; + +/** + * wdev_priv - return wiphy priv from wireless_dev + * + * @wdev: The wireless device whose wiphy's priv pointer to return + */ +static inline void *wdev_priv(struct wireless_dev *wdev) +{ + BUG_ON(!wdev); + return wiphy_priv(wdev->wiphy); +} + +/* + * Utility functions + */ + +/** + * ieee80211_channel_to_frequency - convert channel number to frequency + * @chan: channel number + */ +extern int ieee80211_channel_to_frequency(int chan); + +/** + * ieee80211_frequency_to_channel - convert frequency to channel number + * @freq: center frequency + */ +extern int ieee80211_frequency_to_channel(int freq); + +/* + * Name indirection necessary because the ieee80211 code also has + * a function named "ieee80211_get_channel", so if you include + * cfg80211's header file you get cfg80211's version, if you try + * to include both header files you'll (rightfully!) get a symbol + * clash. + */ +extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, + int freq); +/** + * ieee80211_get_channel - get channel struct from wiphy for specified frequency + * @wiphy: the struct wiphy to get the channel for + * @freq: the center frequency of the channel + */ +static inline struct ieee80211_channel * +ieee80211_get_channel(struct wiphy *wiphy, int freq) +{ + return __ieee80211_get_channel(wiphy, freq); +} + +/** + * ieee80211_get_response_rate - get basic rate for a given rate + * + * @sband: the band to look for rates in + * @basic_rates: bitmap of basic rates + * @bitrate: the bitrate for which to find the basic rate + * + * This function returns the basic rate corresponding to a given + * bitrate, that is the next lower bitrate contained in the basic + * rate map, which is, for this function, given as a bitmap of + * indices of rates in the band's bitrate table. + */ +struct ieee80211_rate * +ieee80211_get_response_rate(struct ieee80211_supported_band *sband, + u32 basic_rates, int bitrate); + +/* + * Radiotap parsing functions -- for controlled injection support + * + * Implemented in net/wireless/radiotap.c + * Documentation in Documentation/networking/radiotap-headers.txt + */ + +struct radiotap_align_size { + uint8_t align:4, size:4; +}; + +struct ieee80211_radiotap_namespace { + const struct radiotap_align_size *align_size; + int n_bits; + uint32_t oui; + uint8_t subns; +}; + +struct ieee80211_radiotap_vendor_namespaces { + const struct ieee80211_radiotap_namespace *ns; + int n_ns; +}; + +/** + * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args + * @this_arg_index: index of current arg, valid after each successful call + * to ieee80211_radiotap_iterator_next() + * @this_arg: pointer to current radiotap arg; it is valid after each + * call to ieee80211_radiotap_iterator_next() but also after + * ieee80211_radiotap_iterator_init() where it will point to + * the beginning of the actual data portion + * @this_arg_size: length of the current arg, for convenience + * @current_namespace: pointer to the current namespace definition + * (or internally %NULL if the current namespace is unknown) + * @is_radiotap_ns: indicates whether the current namespace is the default + * radiotap namespace or not + * + * @_rtheader: pointer to the radiotap header we are walking through + * @_max_length: length of radiotap header in cpu byte ordering + * @_arg_index: next argument index + * @_arg: next argument pointer + * @_next_bitmap: internal pointer to next present u32 + * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present + * @_vns: vendor namespace definitions + * @_next_ns_data: beginning of the next namespace's data + * @_reset_on_ext: internal; reset the arg index to 0 when going to the + * next bitmap word + * + * Describes the radiotap parser state. Fields prefixed with an underscore + * must not be used by users of the parser, only by the parser internally. + */ + +struct ieee80211_radiotap_iterator { + struct ieee80211_radiotap_header *_rtheader; + const struct ieee80211_radiotap_vendor_namespaces *_vns; + const struct ieee80211_radiotap_namespace *current_namespace; + + unsigned char *_arg, *_next_ns_data; + __le32 *_next_bitmap; + + unsigned char *this_arg; + int this_arg_index; + int this_arg_size; + + int is_radiotap_ns; + + int _max_length; + int _arg_index; + uint32_t _bitmap_shifter; + int _reset_on_ext; +}; + +extern int ieee80211_radiotap_iterator_init( + struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, + int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns); + +extern int ieee80211_radiotap_iterator_next( + struct ieee80211_radiotap_iterator *iterator); + + +extern const unsigned char rfc1042_header[6]; +extern const unsigned char bridge_tunnel_header[6]; + +/** + * ieee80211_get_hdrlen_from_skb - get header length from data + * + * Given an skb with a raw 802.11 header at the data pointer this function + * returns the 802.11 header length in bytes (not including encryption + * headers). If the data in the sk_buff is too short to contain a valid 802.11 + * header the function returns 0. + * + * @skb: the frame + */ +unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); + +/** + * ieee80211_hdrlen - get header length in bytes from frame control + * @fc: frame control field in little-endian format + */ +unsigned int ieee80211_hdrlen(__le16 fc); + +/** + * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3 + * @skb: the 802.11 data frame + * @addr: the device MAC address + * @iftype: the virtual interface type + */ +int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, + enum nl80211_iftype iftype); + +/** + * ieee80211_data_from_8023 - convert an 802.3 frame to 802.11 + * @skb: the 802.3 frame + * @addr: the device MAC address + * @iftype: the virtual interface type + * @bssid: the network bssid (used only for iftype STATION and ADHOC) + * @qos: build 802.11 QoS data frame + */ +int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, + enum nl80211_iftype iftype, u8 *bssid, bool qos); + +/** + * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame + * + * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of + * 802.3 frames. The @list will be empty if the decode fails. The + * @skb is consumed after the function returns. + * + * @skb: The input IEEE 802.11n A-MSDU frame. + * @list: The output list of 802.3 frames. It must be allocated and + * initialized by by the caller. + * @addr: The device MAC address. + * @iftype: The device interface type. + * @extra_headroom: The hardware extra headroom for SKBs in the @list. + */ +void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, + const u8 *addr, enum nl80211_iftype iftype, + const unsigned int extra_headroom); + +/** + * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame + * @skb: the data frame + */ +unsigned int cfg80211_classify8021d(struct sk_buff *skb); + +/** + * cfg80211_find_ie - find information element in data + * + * @eid: element ID + * @ies: data consisting of IEs + * @len: length of data + * + * This function will return %NULL if the element ID could + * not be found or if the element is invalid (claims to be + * longer than the given data), or a pointer to the first byte + * of the requested element, that is the byte containing the + * element ID. There are no checks on the element length + * other than having to fit into the given data. + */ +const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len); + +/* + * Regulatory helper functions for wiphys + */ + +/** + * regulatory_hint - driver hint to the wireless core a regulatory domain + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) + * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain + * should be in. If @rd is set this should be NULL. Note that if you + * set this to NULL you should still set rd->alpha2 to some accepted + * alpha2. + * + * Wireless drivers can use this function to hint to the wireless core + * what it believes should be the current regulatory domain by + * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory + * domain should be in or by providing a completely build regulatory domain. + * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried + * for a regulatory domain structure for the respective country. + * + * The wiphy must have been registered to cfg80211 prior to this call. + * For cfg80211 drivers this means you must first use wiphy_register(), + * for mac80211 drivers you must first use ieee80211_register_hw(). + * + * Drivers should check the return value, its possible you can get + * an -ENOMEM. + */ +extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2); + +/** + * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain + * @wiphy: the wireless device we want to process the regulatory domain on + * @regd: the custom regulatory domain to use for this wiphy + * + * Drivers can sometimes have custom regulatory domains which do not apply + * to a specific country. Drivers can use this to apply such custom regulatory + * domains. This routine must be called prior to wiphy registration. The + * custom regulatory domain will be trusted completely and as such previous + * default channel settings will be disregarded. If no rule is found for a + * channel on the regulatory domain the channel will be disabled. + */ +extern void wiphy_apply_custom_regulatory( + struct wiphy *wiphy, + const struct ieee80211_regdomain *regd); + +/** + * freq_reg_info - get regulatory information for the given frequency + * @wiphy: the wiphy for which we want to process this rule for + * @center_freq: Frequency in KHz for which we want regulatory information for + * @desired_bw_khz: the desired max bandwidth you want to use per + * channel. Note that this is still 20 MHz if you want to use HT40 + * as HT40 makes use of two channels for its 40 MHz width bandwidth. + * If set to 0 we'll assume you want the standard 20 MHz. + * @reg_rule: the regulatory rule which we have for this frequency + * + * Use this function to get the regulatory rule for a specific frequency on + * a given wireless device. If the device has a specific regulatory domain + * it wants to follow we respect that unless a country IE has been received + * and processed already. + * + * Returns 0 if it was able to find a valid regulatory rule which does + * apply to the given center_freq otherwise it returns non-zero. It will + * also return -ERANGE if we determine the given center_freq does not even have + * a regulatory rule for a frequency range in the center_freq's band. See + * freq_in_rule_band() for our current definition of a band -- this is purely + * subjective and right now its 802.11 specific. + */ +extern int freq_reg_info(struct wiphy *wiphy, + u32 center_freq, + u32 desired_bw_khz, + const struct ieee80211_reg_rule **reg_rule); + +/* + * Temporary wext handlers & helper functions + * + * In the future cfg80211 will simply assign the entire wext handler + * structure to netdevs it manages, but we're not there yet. + */ +int cfg80211_wext_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra); +int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra); +int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra); +int cfg80211_wext_siwscan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int cfg80211_wext_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra); +int cfg80211_wext_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra); + +int cfg80211_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_wext_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra); +int cfg80211_wext_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra); + +int cfg80211_wext_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra); +int cfg80211_wext_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra); +int cfg80211_wext_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra); +int cfg80211_wext_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra); +int cfg80211_wext_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra); +int cfg80211_wext_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra); +int cfg80211_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra); +int cfg80211_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf); +int cfg80211_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf); +int cfg80211_wext_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *keybuf); +int cfg80211_wext_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *keybuf); +struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev); + +int cfg80211_wext_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra); +int cfg80211_wext_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra); + +int cfg80211_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); + +int cfg80211_wext_siwpmksa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); + +/* + * callbacks for asynchronous cfg80211 methods, notification + * functions and BSS handling helpers + */ + +/** + * cfg80211_scan_done - notify that scan finished + * + * @request: the corresponding scan request + * @aborted: set to true if the scan was aborted for any reason, + * userspace will be notified of that + */ +void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted); + +/** + * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame + * + * @wiphy: the wiphy reporting the BSS + * @channel: The channel the frame was received on + * @mgmt: the management frame (probe response or beacon) + * @len: length of the management frame + * @signal: the signal strength, type depends on the wiphy's signal_type + * @gfp: context flags + * + * This informs cfg80211 that BSS information was found and + * the BSS should be updated/added. + */ +struct cfg80211_bss* +cfg80211_inform_bss_frame(struct wiphy *wiphy, + struct ieee80211_channel *channel, + struct ieee80211_mgmt *mgmt, size_t len, + s32 signal, gfp_t gfp); + +/** + * cfg80211_inform_bss - inform cfg80211 of a new BSS + * + * @wiphy: the wiphy reporting the BSS + * @channel: The channel the frame was received on + * @bssid: the BSSID of the BSS + * @timestamp: the TSF timestamp sent by the peer + * @capability: the capability field sent by the peer + * @beacon_interval: the beacon interval announced by the peer + * @ie: additional IEs sent by the peer + * @ielen: length of the additional IEs + * @signal: the signal strength, type depends on the wiphy's signal_type + * @gfp: context flags + * + * This informs cfg80211 that BSS information was found and + * the BSS should be updated/added. + */ +struct cfg80211_bss* +cfg80211_inform_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + u64 timestamp, u16 capability, u16 beacon_interval, + const u8 *ie, size_t ielen, + s32 signal, gfp_t gfp); + +struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len, + u16 capa_mask, u16 capa_val); +static inline struct cfg80211_bss * +cfg80211_get_ibss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *ssid, size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len, + WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); +} + +struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *meshid, size_t meshidlen, + const u8 *meshcfg); +void cfg80211_put_bss(struct cfg80211_bss *bss); + +/** + * cfg80211_unlink_bss - unlink BSS from internal data structures + * @wiphy: the wiphy + * @bss: the bss to remove + * + * This function removes the given BSS from the internal data structures + * thereby making it no longer show up in scan results etc. Use this + * function when you detect a BSS is gone. Normally BSSes will also time + * out, so it is not necessary to use this function at all. + */ +void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); + +/** + * cfg80211_send_rx_auth - notification of processed authentication + * @dev: network device + * @buf: authentication frame (header + body) + * @len: length of the frame data + * + * This function is called whenever an authentication has been processed in + * station mode. The driver is required to call either this function or + * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth() + * call. This function may sleep. + */ +void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); + +/** + * cfg80211_send_auth_timeout - notification of timed out authentication + * @dev: network device + * @addr: The MAC address of the device with which the authentication timed out + * + * This function may sleep. + */ +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); + +/** + * __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled + * @dev: network device + * @addr: The MAC address of the device with which the authentication timed out + * + * When a pending authentication had no action yet, the driver may decide + * to not send a deauth frame, but in that case must calls this function + * to tell cfg80211 about this decision. It is only valid to call this + * function within the deauth() callback. + */ +void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr); + +/** + * cfg80211_send_rx_assoc - notification of processed association + * @dev: network device + * @buf: (re)association response frame (header + body) + * @len: length of the frame data + * + * This function is called whenever a (re)association response has been + * processed in station mode. The driver is required to call either this + * function or cfg80211_send_assoc_timeout() to indicate the result of + * cfg80211_ops::assoc() call. This function may sleep. + */ +void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); + +/** + * cfg80211_send_assoc_timeout - notification of timed out association + * @dev: network device + * @addr: The MAC address of the device with which the association timed out + * + * This function may sleep. + */ +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); + +/** + * cfg80211_send_deauth - notification of processed deauthentication + * @dev: network device + * @buf: deauthentication frame (header + body) + * @len: length of the frame data + * + * This function is called whenever deauthentication has been processed in + * station mode. This includes both received deauthentication frames and + * locally generated ones. This function may sleep. + */ +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); + +/** + * __cfg80211_send_deauth - notification of processed deauthentication + * @dev: network device + * @buf: deauthentication frame (header + body) + * @len: length of the frame data + * + * Like cfg80211_send_deauth(), but doesn't take the wdev lock. + */ +void __cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); + +/** + * cfg80211_send_disassoc - notification of processed disassociation + * @dev: network device + * @buf: disassociation response frame (header + body) + * @len: length of the frame data + * + * This function is called whenever disassociation has been processed in + * station mode. This includes both received disassociation frames and locally + * generated ones. This function may sleep. + */ +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); + +/** + * __cfg80211_send_disassoc - notification of processed disassociation + * @dev: network device + * @buf: disassociation response frame (header + body) + * @len: length of the frame data + * + * Like cfg80211_send_disassoc(), but doesn't take the wdev lock. + */ +void __cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, + size_t len); + +/** + * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) + * @dev: network device + * @addr: The source MAC address of the frame + * @key_type: The key type that the received frame used + * @key_id: Key identifier (0..3) + * @tsc: The TSC value of the frame that generated the MIC failure (6 octets) + * @gfp: allocation flags + * + * This function is called whenever the local MAC detects a MIC failure in a + * received frame. This matches with MLME-MICHAELMICFAILURE.indication() + * primitive. + */ +void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc, gfp_t gfp); + +/** + * cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS + * + * @dev: network device + * @bssid: the BSSID of the IBSS joined + * @gfp: allocation flags + * + * This function notifies cfg80211 that the device joined an IBSS or + * switched to a different BSSID. Before this function can be called, + * either a beacon has to have been received from the IBSS, or one of + * the cfg80211_inform_bss{,_frame} functions must have been called + * with the locally generated beacon -- this guarantees that there is + * always a scan result for this IBSS. cfg80211 will handle the rest. + */ +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); + +/** + * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state + * @wiphy: the wiphy + * @blocked: block status + */ +void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked); + +/** + * wiphy_rfkill_start_polling - start polling rfkill + * @wiphy: the wiphy + */ +void wiphy_rfkill_start_polling(struct wiphy *wiphy); + +/** + * wiphy_rfkill_stop_polling - stop polling rfkill + * @wiphy: the wiphy + */ +void wiphy_rfkill_stop_polling(struct wiphy *wiphy); + +#ifdef CONFIG_NL80211_TESTMODE +/** + * cfg80211_testmode_alloc_reply_skb - allocate testmode reply + * @wiphy: the wiphy + * @approxlen: an upper bound of the length of the data that will + * be put into the skb + * + * This function allocates and pre-fills an skb for a reply to + * the testmode command. Since it is intended for a reply, calling + * it outside of the @testmode_cmd operation is invalid. + * + * The returned skb (or %NULL if any errors happen) is pre-filled + * with the wiphy index and set up in a way that any data that is + * put into the skb (with skb_put(), nla_put() or similar) will end + * up being within the %NL80211_ATTR_TESTDATA attribute, so all that + * needs to be done with the skb is adding data for the corresponding + * userspace tool which can then read that data out of the testdata + * attribute. You must not modify the skb in any other way. + * + * When done, call cfg80211_testmode_reply() with the skb and return + * its error code as the result of the @testmode_cmd operation. + */ +struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, + int approxlen); + +/** + * cfg80211_testmode_reply - send the reply skb + * @skb: The skb, must have been allocated with + * cfg80211_testmode_alloc_reply_skb() + * + * Returns an error code or 0 on success, since calling this + * function will usually be the last thing before returning + * from the @testmode_cmd you should return the error code. + * Note that this function consumes the skb regardless of the + * return value. + */ +int cfg80211_testmode_reply(struct sk_buff *skb); + +/** + * cfg80211_testmode_alloc_event_skb - allocate testmode event + * @wiphy: the wiphy + * @approxlen: an upper bound of the length of the data that will + * be put into the skb + * @gfp: allocation flags + * + * This function allocates and pre-fills an skb for an event on the + * testmode multicast group. + * + * The returned skb (or %NULL if any errors happen) is set up in the + * same way as with cfg80211_testmode_alloc_reply_skb() but prepared + * for an event. As there, you should simply add data to it that will + * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must + * not modify the skb in any other way. + * + * When done filling the skb, call cfg80211_testmode_event() with the + * skb to send the event. + */ +struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, + int approxlen, gfp_t gfp); + +/** + * cfg80211_testmode_event - send the event + * @skb: The skb, must have been allocated with + * cfg80211_testmode_alloc_event_skb() + * @gfp: allocation flags + * + * This function sends the given @skb, which must have been allocated + * by cfg80211_testmode_alloc_event_skb(), as an event. It always + * consumes it. + */ +void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp); + +#define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd), +#else +#define CFG80211_TESTMODE_CMD(cmd) +#endif + +/** + * cfg80211_connect_result - notify cfg80211 of connection result + * + * @dev: network device + * @bssid: the BSSID of the AP + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @status: status code, 0 for successful connection, use + * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you + * the real status code for failures. + * @gfp: allocation flags + * + * It should be called by the underlying driver whenever connect() has + * succeeded. + */ +void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp); + +/** + * cfg80211_roamed - notify cfg80211 of roaming + * + * @dev: network device + * @bssid: the BSSID of the new AP + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @gfp: allocation flags + * + * It should be called by the underlying driver whenever it roamed + * from one AP to another while connected. + */ +void cfg80211_roamed(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); + +/** + * cfg80211_disconnected - notify cfg80211 that connection was dropped + * + * @dev: network device + * @ie: information elements of the deauth/disassoc frame (may be %NULL) + * @ie_len: length of IEs + * @reason: reason code for the disconnection, set it to 0 if unknown + * @gfp: allocation flags + * + * After it calls this function, the driver should enter an idle state + * and not try to connect to any AP any more. + */ +void cfg80211_disconnected(struct net_device *dev, u16 reason, + u8 *ie, size_t ie_len, gfp_t gfp); + +/** + * cfg80211_ready_on_channel - notification of remain_on_channel start + * @dev: network device + * @cookie: the request cookie + * @chan: The current channel (from remain_on_channel request) + * @channel_type: Channel type + * @duration: Duration in milliseconds that the driver intents to remain on the + * channel + * @gfp: allocation flags + */ +void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, gfp_t gfp); + +/** + * cfg80211_remain_on_channel_expired - remain_on_channel duration expired + * @dev: network device + * @cookie: the request cookie + * @chan: The current channel (from remain_on_channel request) + * @channel_type: Channel type + * @gfp: allocation flags + */ +void cfg80211_remain_on_channel_expired(struct net_device *dev, + u64 cookie, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + gfp_t gfp); + + +/** + * cfg80211_new_sta - notify userspace about station + * + * @dev: the netdev + * @mac_addr: the station's address + * @sinfo: the station information + * @gfp: allocation flags + */ +void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, + struct station_info *sinfo, gfp_t gfp); + +/** + * cfg80211_rx_action - notification of received, unprocessed Action frame + * @dev: network device + * @freq: Frequency on which the frame was received in MHz + * @buf: Action frame (header + body) + * @len: length of the frame data + * @gfp: context flags + * Returns %true if a user space application is responsible for rejecting the + * unrecognized Action frame; %false if no such application is registered + * (i.e., the driver is responsible for rejecting the unrecognized Action + * frame) + * + * This function is called whenever an Action frame is received for a station + * mode interface, but is not processed in kernel. + */ +bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, + size_t len, gfp_t gfp); + +/** + * cfg80211_action_tx_status - notification of TX status for Action frame + * @dev: network device + * @cookie: Cookie returned by cfg80211_ops::action() + * @buf: Action frame (header + body) + * @len: length of the frame data + * @ack: Whether frame was acknowledged + * @gfp: context flags + * + * This function is called whenever an Action frame was requested to be + * transmitted with cfg80211_ops::action() to report the TX status of the + * transmission attempt. + */ +void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, + const u8 *buf, size_t len, bool ack, gfp_t gfp); + + +/** + * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event + * @dev: network device + * @rssi_event: the triggered RSSI event + * @gfp: context flags + * + * This function is called when a configured connection quality monitoring + * rssi threshold reached event occurs. + */ +void cfg80211_cqm_rssi_notify(struct net_device *dev, + enum nl80211_cqm_rssi_threshold_event rssi_event, + gfp_t gfp); + +#ifdef __KERNEL__ + +/* Logging, debugging and troubleshooting/diagnostic helpers. */ + +/* wiphy_printk helpers, similar to dev_printk */ + +#define wiphy_printk(level, wiphy, format, args...) \ + printk(level "%s: " format, wiphy_name(wiphy), ##args) +#define wiphy_emerg(wiphy, format, args...) \ + wiphy_printk(KERN_EMERG, wiphy, format, ##args) +#define wiphy_alert(wiphy, format, args...) \ + wiphy_printk(KERN_ALERT, wiphy, format, ##args) +#define wiphy_crit(wiphy, format, args...) \ + wiphy_printk(KERN_CRIT, wiphy, format, ##args) +#define wiphy_err(wiphy, format, args...) \ + wiphy_printk(KERN_ERR, wiphy, format, ##args) +#define wiphy_warn(wiphy, format, args...) \ + wiphy_printk(KERN_WARNING, wiphy, format, ##args) +#define wiphy_notice(wiphy, format, args...) \ + wiphy_printk(KERN_NOTICE, wiphy, format, ##args) +#define wiphy_info(wiphy, format, args...) \ + wiphy_printk(KERN_INFO, wiphy, format, ##args) + +int wiphy_debug(const struct wiphy *wiphy, const char *format, ...) + __attribute__ ((format (printf, 2, 3))); + +#if defined(DEBUG) +#define wiphy_dbg(wiphy, format, args...) \ + wiphy_printk(KERN_DEBUG, wiphy, format, ##args) +#elif defined(CONFIG_DYNAMIC_DEBUG) +#define wiphy_dbg(wiphy, format, args...) \ + dynamic_pr_debug("%s: " format, wiphy_name(wiphy), ##args) +#else +#define wiphy_dbg(wiphy, format, args...) \ +({ \ + if (0) \ + wiphy_printk(KERN_DEBUG, wiphy, format, ##args); \ + 0; \ +}) +#endif + +#if defined(VERBOSE_DEBUG) +#define wiphy_vdbg wiphy_dbg +#else + +#define wiphy_vdbg(wiphy, format, args...) \ +({ \ + if (0) \ + wiphy_printk(KERN_DEBUG, wiphy, format, ##args); \ + 0; \ +}) +#endif + +/* + * wiphy_WARN() acts like wiphy_printk(), but with the key difference + * of using a WARN/WARN_ON to get the message out, including the + * file/line information and a backtrace. + */ +#define wiphy_WARN(wiphy, format, args...) \ + WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args); + +#endif + +#endif /* __NET_CFG80211_H */ diff --git a/include/net/checksum.h b/include/net/checksum.h new file mode 100644 index 00000000..ba55d8b8 --- /dev/null +++ b/include/net/checksum.h @@ -0,0 +1,121 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Checksumming functions for IP, TCP, UDP and so on + * + * Authors: Jorge Cwik, <jorge@laser.satlink.net> + * Arnt Gulbrandsen, <agulbra@nvg.unit.no> + * Borrows very liberally from tcp.c and ip.c, see those + * files for more names. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _CHECKSUM_H +#define _CHECKSUM_H + +#include <linux/errno.h> +#include <asm/types.h> +#include <asm/byteorder.h> +#include <asm/uaccess.h> +#include <asm/checksum.h> + +#ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER +static inline +__wsum csum_and_copy_from_user (const void __user *src, void *dst, + int len, __wsum sum, int *err_ptr) +{ + if (access_ok(VERIFY_READ, src, len)) + return csum_partial_copy_from_user(src, dst, len, sum, err_ptr); + + if (len) + *err_ptr = -EFAULT; + + return sum; +} +#endif + +#ifndef HAVE_CSUM_COPY_USER +static __inline__ __wsum csum_and_copy_to_user +(const void *src, void __user *dst, int len, __wsum sum, int *err_ptr) +{ + sum = csum_partial(src, len, sum); + + if (access_ok(VERIFY_WRITE, dst, len)) { + if (copy_to_user(dst, src, len) == 0) + return sum; + } + if (len) + *err_ptr = -EFAULT; + + return (__force __wsum)-1; /* invalid checksum */ +} +#endif + +static inline __wsum csum_add(__wsum csum, __wsum addend) +{ + u32 res = (__force u32)csum; + res += (__force u32)addend; + return (__force __wsum)(res + (res < (__force u32)addend)); +} + +static inline __wsum csum_sub(__wsum csum, __wsum addend) +{ + return csum_add(csum, ~addend); +} + +static inline __wsum +csum_block_add(__wsum csum, __wsum csum2, int offset) +{ + u32 sum = (__force u32)csum2; + if (offset&1) + sum = ((sum&0xFF00FF)<<8)+((sum>>8)&0xFF00FF); + return csum_add(csum, (__force __wsum)sum); +} + +static inline __wsum +csum_block_sub(__wsum csum, __wsum csum2, int offset) +{ + u32 sum = (__force u32)csum2; + if (offset&1) + sum = ((sum&0xFF00FF)<<8)+((sum>>8)&0xFF00FF); + return csum_sub(csum, (__force __wsum)sum); +} + +static inline __wsum csum_unfold(__sum16 n) +{ + return (__force __wsum)n; +} + +#define CSUM_MANGLED_0 ((__force __sum16)0xffff) + +static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to) +{ + __be32 diff[] = { ~from, to }; + + *sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum))); +} + +static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to) +{ + csum_replace4(sum, (__force __be32)from, (__force __be32)to); +} + +struct sk_buff; +extern void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, + __be32 from, __be32 to, int pseudohdr); + +static inline void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb, + __be16 from, __be16 to, + int pseudohdr) +{ + inet_proto_csum_replace4(sum, skb, (__force __be32)from, + (__force __be32)to, pseudohdr); +} + +#endif diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h new file mode 100644 index 00000000..abd44360 --- /dev/null +++ b/include/net/cipso_ipv4.h @@ -0,0 +1,292 @@ +/* + * CIPSO - Commercial IP Security Option + * + * This is an implementation of the CIPSO 2.2 protocol as specified in + * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in + * FIPS-188, copies of both documents can be found in the Documentation + * directory. While CIPSO never became a full IETF RFC standard many vendors + * have chosen to adopt the protocol and over the years it has become a + * de-facto standard for labeled networking. + * + * Author: Paul Moore <paul.moore@hp.com> + * + */ + +/* + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _CIPSO_IPV4_H +#define _CIPSO_IPV4_H + +#include <linux/types.h> +#include <linux/rcupdate.h> +#include <linux/list.h> +#include <linux/net.h> +#include <linux/skbuff.h> +#include <net/netlabel.h> +#include <net/request_sock.h> +#include <asm/atomic.h> + +/* known doi values */ +#define CIPSO_V4_DOI_UNKNOWN 0x00000000 + +/* standard tag types */ +#define CIPSO_V4_TAG_INVALID 0 +#define CIPSO_V4_TAG_RBITMAP 1 +#define CIPSO_V4_TAG_ENUM 2 +#define CIPSO_V4_TAG_RANGE 5 +#define CIPSO_V4_TAG_PBITMAP 6 +#define CIPSO_V4_TAG_FREEFORM 7 + +/* non-standard tag types (tags > 127) */ +#define CIPSO_V4_TAG_LOCAL 128 + +/* doi mapping types */ +#define CIPSO_V4_MAP_UNKNOWN 0 +#define CIPSO_V4_MAP_TRANS 1 +#define CIPSO_V4_MAP_PASS 2 +#define CIPSO_V4_MAP_LOCAL 3 + +/* limits */ +#define CIPSO_V4_MAX_REM_LVLS 255 +#define CIPSO_V4_INV_LVL 0x80000000 +#define CIPSO_V4_MAX_LOC_LVLS (CIPSO_V4_INV_LVL - 1) +#define CIPSO_V4_MAX_REM_CATS 65534 +#define CIPSO_V4_INV_CAT 0x80000000 +#define CIPSO_V4_MAX_LOC_CATS (CIPSO_V4_INV_CAT - 1) + +/* + * CIPSO DOI definitions + */ + +/* DOI definition struct */ +#define CIPSO_V4_TAG_MAXCNT 5 +struct cipso_v4_doi { + u32 doi; + u32 type; + union { + struct cipso_v4_std_map_tbl *std; + } map; + u8 tags[CIPSO_V4_TAG_MAXCNT]; + + atomic_t refcount; + struct list_head list; + struct rcu_head rcu; +}; + +/* Standard CIPSO mapping table */ +/* NOTE: the highest order bit (i.e. 0x80000000) is an 'invalid' flag, if the + * bit is set then consider that value as unspecified, meaning the + * mapping for that particular level/category is invalid */ +struct cipso_v4_std_map_tbl { + struct { + u32 *cipso; + u32 *local; + u32 cipso_size; + u32 local_size; + } lvl; + struct { + u32 *cipso; + u32 *local; + u32 cipso_size; + u32 local_size; + } cat; +}; + +/* + * Sysctl Variables + */ + +#ifdef CONFIG_NETLABEL +extern int cipso_v4_cache_enabled; +extern int cipso_v4_cache_bucketsize; +extern int cipso_v4_rbm_optfmt; +extern int cipso_v4_rbm_strictvalid; +#endif + +/* + * Helper Functions + */ + +#define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0) +#define CIPSO_V4_OPTPTR(x) (skb_network_header(x) + IPCB(x)->opt.cipso) + +/* + * DOI List Functions + */ + +#ifdef CONFIG_NETLABEL +int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, + struct netlbl_audit *audit_info); +void cipso_v4_doi_free(struct cipso_v4_doi *doi_def); +int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info); +struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); +void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def); +int cipso_v4_doi_walk(u32 *skip_cnt, + int (*callback) (struct cipso_v4_doi *doi_def, void *arg), + void *cb_arg); +#else +static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, + struct netlbl_audit *audit_info) +{ + return -ENOSYS; +} + +static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def) +{ + return; +} + +static inline int cipso_v4_doi_remove(u32 doi, + struct netlbl_audit *audit_info) +{ + return 0; +} + +static inline struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) +{ + return NULL; +} + +static inline int cipso_v4_doi_walk(u32 *skip_cnt, + int (*callback) (struct cipso_v4_doi *doi_def, void *arg), + void *cb_arg) +{ + return 0; +} + +static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, + const char *domain) +{ + return -ENOSYS; +} + +static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, + const char *domain) +{ + return 0; +} +#endif /* CONFIG_NETLABEL */ + +/* + * Label Mapping Cache Functions + */ + +#ifdef CONFIG_NETLABEL +void cipso_v4_cache_invalidate(void); +int cipso_v4_cache_add(const struct sk_buff *skb, + const struct netlbl_lsm_secattr *secattr); +#else +static inline void cipso_v4_cache_invalidate(void) +{ + return; +} + +static inline int cipso_v4_cache_add(const struct sk_buff *skb, + const struct netlbl_lsm_secattr *secattr) +{ + return 0; +} +#endif /* CONFIG_NETLABEL */ + +/* + * Protocol Handling Functions + */ + +#ifdef CONFIG_NETLABEL +void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); +int cipso_v4_sock_setattr(struct sock *sk, + const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr); +void cipso_v4_sock_delattr(struct sock *sk); +int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); +int cipso_v4_req_setattr(struct request_sock *req, + const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr); +void cipso_v4_req_delattr(struct request_sock *req); +int cipso_v4_skbuff_setattr(struct sk_buff *skb, + const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr); +int cipso_v4_skbuff_delattr(struct sk_buff *skb); +int cipso_v4_skbuff_getattr(const struct sk_buff *skb, + struct netlbl_lsm_secattr *secattr); +int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option); +#else +static inline void cipso_v4_error(struct sk_buff *skb, + int error, + u32 gateway) +{ + return; +} + +static inline int cipso_v4_sock_setattr(struct sock *sk, + const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} + +static inline void cipso_v4_sock_delattr(struct sock *sk) +{ +} + +static inline int cipso_v4_sock_getattr(struct sock *sk, + struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} + +static inline int cipso_v4_req_setattr(struct request_sock *req, + const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} + +static inline void cipso_v4_req_delattr(struct request_sock *req) +{ + return; +} + +static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb, + const struct cipso_v4_doi *doi_def, + const struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} + +static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb) +{ + return -ENOSYS; +} + +static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, + struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} + +static inline int cipso_v4_validate(const struct sk_buff *skb, + unsigned char **option) +{ + return -ENOSYS; +} +#endif /* CONFIG_NETLABEL */ + +#endif /* _CIPSO_IPV4_H */ diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h new file mode 100644 index 00000000..ef6c24a5 --- /dev/null +++ b/include/net/cls_cgroup.h @@ -0,0 +1,69 @@ +/* + * cls_cgroup.h Control Group Classifier + * + * Authors: Thomas Graf <tgraf@suug.ch> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _NET_CLS_CGROUP_H +#define _NET_CLS_CGROUP_H + +#include <linux/cgroup.h> +#include <linux/hardirq.h> +#include <linux/rcupdate.h> + +#ifdef CONFIG_CGROUPS +struct cgroup_cls_state +{ + struct cgroup_subsys_state css; + u32 classid; +}; + +#ifdef CONFIG_NET_CLS_CGROUP +static inline u32 task_cls_classid(struct task_struct *p) +{ + int classid; + + if (in_interrupt()) + return 0; + + rcu_read_lock(); + classid = container_of(task_subsys_state(p, net_cls_subsys_id), + struct cgroup_cls_state, css)->classid; + rcu_read_unlock(); + + return classid; +} +#else +extern int net_cls_subsys_id; + +static inline u32 task_cls_classid(struct task_struct *p) +{ + int id; + u32 classid = 0; + + if (in_interrupt()) + return 0; + + rcu_read_lock(); + id = rcu_dereference(net_cls_subsys_id); + if (id >= 0) + classid = container_of(task_subsys_state(p, id), + struct cgroup_cls_state, css)->classid; + rcu_read_unlock(); + + return classid; +} +#endif +#else +static inline u32 task_cls_classid(struct task_struct *p) +{ + return 0; +} +#endif +#endif /* _NET_CLS_CGROUP_H */ diff --git a/include/net/compat.h b/include/net/compat.h new file mode 100644 index 00000000..28d5428e --- /dev/null +++ b/include/net/compat.h @@ -0,0 +1,61 @@ +#ifndef NET_COMPAT_H +#define NET_COMPAT_H + + +struct sock; + +#if defined(CONFIG_COMPAT) + +#include <linux/compat.h> + +struct compat_msghdr { + compat_uptr_t msg_name; /* void * */ + compat_int_t msg_namelen; + compat_uptr_t msg_iov; /* struct compat_iovec * */ + compat_size_t msg_iovlen; + compat_uptr_t msg_control; /* void * */ + compat_size_t msg_controllen; + compat_uint_t msg_flags; +}; + +struct compat_mmsghdr { + struct compat_msghdr msg_hdr; + compat_uint_t msg_len; +}; + +struct compat_cmsghdr { + compat_size_t cmsg_len; + compat_int_t cmsg_level; + compat_int_t cmsg_type; +}; + +extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *); +extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *); + +#else /* defined(CONFIG_COMPAT) */ +/* + * To avoid compiler warnings: + */ +#define compat_msghdr msghdr +#define compat_mmsghdr mmsghdr +#endif /* defined(CONFIG_COMPAT) */ + +extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); +extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr *, int); +extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned); +extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned); +extern asmlinkage long compat_sys_recvmmsg(int, struct compat_mmsghdr __user *, + unsigned, unsigned, + struct compat_timespec __user *); +extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *); +extern int put_cmsg_compat(struct msghdr*, int, int, int, void *); + +extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int); + +extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, unsigned int, + int (*)(struct sock *, int, int, char __user *, unsigned int)); +extern int compat_mc_getsockopt(struct sock *, int, int, char __user *, + int __user *, int (*)(struct sock *, int, int, char __user *, + int __user *)); + +#endif /* NET_COMPAT_H */ diff --git a/include/net/datalink.h b/include/net/datalink.h new file mode 100644 index 00000000..deb7ca75 --- /dev/null +++ b/include/net/datalink.h @@ -0,0 +1,18 @@ +#ifndef _NET_INET_DATALINK_H_ +#define _NET_INET_DATALINK_H_ + +struct datalink_proto { + unsigned char type[8]; + + struct llc_sap *sap; + + unsigned short header_length; + + int (*rcvfunc)(struct sk_buff *, struct net_device *, + struct packet_type *, struct net_device *); + int (*request)(struct datalink_proto *, struct sk_buff *, + unsigned char *); + struct list_head node; +}; + +#endif diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h new file mode 100644 index 00000000..b36ac7e0 --- /dev/null +++ b/include/net/dcbnl.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Author: Lucy Liu <lucy.liu@intel.com> + */ + +#ifndef __NET_DCBNL_H__ +#define __NET_DCBNL_H__ + +/* + * Ops struct for the netlink callbacks. Used by DCB-enabled drivers through + * the netdevice struct. + */ +struct dcbnl_rtnl_ops { + u8 (*getstate)(struct net_device *); + u8 (*setstate)(struct net_device *, u8); + void (*getpermhwaddr)(struct net_device *, u8 *); + void (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8); + void (*setpgbwgcfgtx)(struct net_device *, int, u8); + void (*setpgtccfgrx)(struct net_device *, int, u8, u8, u8, u8); + void (*setpgbwgcfgrx)(struct net_device *, int, u8); + void (*getpgtccfgtx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); + void (*getpgbwgcfgtx)(struct net_device *, int, u8 *); + void (*getpgtccfgrx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); + void (*getpgbwgcfgrx)(struct net_device *, int, u8 *); + void (*setpfccfg)(struct net_device *, int, u8); + void (*getpfccfg)(struct net_device *, int, u8 *); + u8 (*setall)(struct net_device *); + u8 (*getcap)(struct net_device *, int, u8 *); + u8 (*getnumtcs)(struct net_device *, int, u8 *); + u8 (*setnumtcs)(struct net_device *, int, u8); + u8 (*getpfcstate)(struct net_device *); + void (*setpfcstate)(struct net_device *, u8); + void (*getbcncfg)(struct net_device *, int, u32 *); + void (*setbcncfg)(struct net_device *, int, u32); + void (*getbcnrp)(struct net_device *, int, u8 *); + void (*setbcnrp)(struct net_device *, int, u8); + u8 (*setapp)(struct net_device *, u8, u16, u8); + u8 (*getapp)(struct net_device *, u8, u16); +}; + +#endif /* __NET_DCBNL_H__ */ diff --git a/include/net/dn.h b/include/net/dn.h new file mode 100644 index 00000000..e5469f7b --- /dev/null +++ b/include/net/dn.h @@ -0,0 +1,232 @@ +#ifndef _NET_DN_H +#define _NET_DN_H + +#include <linux/dn.h> +#include <net/sock.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> + +struct dn_scp /* Session Control Port */ +{ + unsigned char state; +#define DN_O 1 /* Open */ +#define DN_CR 2 /* Connect Receive */ +#define DN_DR 3 /* Disconnect Reject */ +#define DN_DRC 4 /* Discon. Rej. Complete*/ +#define DN_CC 5 /* Connect Confirm */ +#define DN_CI 6 /* Connect Initiate */ +#define DN_NR 7 /* No resources */ +#define DN_NC 8 /* No communication */ +#define DN_CD 9 /* Connect Delivery */ +#define DN_RJ 10 /* Rejected */ +#define DN_RUN 11 /* Running */ +#define DN_DI 12 /* Disconnect Initiate */ +#define DN_DIC 13 /* Disconnect Complete */ +#define DN_DN 14 /* Disconnect Notificat */ +#define DN_CL 15 /* Closed */ +#define DN_CN 16 /* Closed Notification */ + + __le16 addrloc; + __le16 addrrem; + __u16 numdat; + __u16 numoth; + __u16 numoth_rcv; + __u16 numdat_rcv; + __u16 ackxmt_dat; + __u16 ackxmt_oth; + __u16 ackrcv_dat; + __u16 ackrcv_oth; + __u8 flowrem_sw; + __u8 flowloc_sw; +#define DN_SEND 2 +#define DN_DONTSEND 1 +#define DN_NOCHANGE 0 + __u16 flowrem_dat; + __u16 flowrem_oth; + __u16 flowloc_dat; + __u16 flowloc_oth; + __u8 services_rem; + __u8 services_loc; + __u8 info_rem; + __u8 info_loc; + + __u16 segsize_rem; + __u16 segsize_loc; + + __u8 nonagle; + __u8 multi_ireq; + __u8 accept_mode; + unsigned long seg_total; /* Running total of current segment */ + + struct optdata_dn conndata_in; + struct optdata_dn conndata_out; + struct optdata_dn discdata_in; + struct optdata_dn discdata_out; + struct accessdata_dn accessdata; + + struct sockaddr_dn addr; /* Local address */ + struct sockaddr_dn peer; /* Remote address */ + + /* + * In this case the RTT estimation is not specified in the + * docs, nor is any back off algorithm. Here we follow well + * known tcp algorithms with a few small variations. + * + * snd_window: Max number of packets we send before we wait for + * an ack to come back. This will become part of a + * more complicated scheme when we support flow + * control. + * + * nsp_srtt: Round-Trip-Time (x8) in jiffies. This is a rolling + * average. + * nsp_rttvar: Round-Trip-Time-Varience (x4) in jiffies. This is the + * varience of the smoothed average (but calculated in + * a simpler way than for normal statistical varience + * calculations). + * + * nsp_rxtshift: Backoff counter. Value is zero normally, each time + * a packet is lost is increases by one until an ack + * is received. Its used to index an array of backoff + * multipliers. + */ +#define NSP_MIN_WINDOW 1 +#define NSP_MAX_WINDOW (0x07fe) + unsigned long max_window; + unsigned long snd_window; +#define NSP_INITIAL_SRTT (HZ) + unsigned long nsp_srtt; +#define NSP_INITIAL_RTTVAR (HZ*3) + unsigned long nsp_rttvar; +#define NSP_MAXRXTSHIFT 12 + unsigned long nsp_rxtshift; + + /* + * Output queues, one for data, one for otherdata/linkservice + */ + struct sk_buff_head data_xmit_queue; + struct sk_buff_head other_xmit_queue; + + /* + * Input queue for other data + */ + struct sk_buff_head other_receive_queue; + int other_report; + + /* + * Stuff to do with the slow timer + */ + unsigned long stamp; /* time of last transmit */ + unsigned long persist; + int (*persist_fxn)(struct sock *sk); + unsigned long keepalive; + void (*keepalive_fxn)(struct sock *sk); + + /* + * This stuff is for the fast timer for delayed acks + */ + struct timer_list delack_timer; + int delack_pending; + void (*delack_fxn)(struct sock *sk); + +}; + +static inline struct dn_scp *DN_SK(struct sock *sk) +{ + return (struct dn_scp *)(sk + 1); +} + +/* + * src,dst : Source and Destination DECnet addresses + * hops : Number of hops through the network + * dst_port, src_port : NSP port numbers + * services, info : Useful data extracted from conninit messages + * rt_flags : Routing flags byte + * nsp_flags : NSP layer flags byte + * segsize : Size of segment + * segnum : Number, for data, otherdata and linkservice + * xmit_count : Number of times we've transmitted this skb + * stamp : Time stamp of most recent transmission, used in RTT calculations + * iif: Input interface number + * + * As a general policy, this structure keeps all addresses in network + * byte order, and all else in host byte order. Thus dst, src, dst_port + * and src_port are in network order. All else is in host order. + * + */ +#define DN_SKB_CB(skb) ((struct dn_skb_cb *)(skb)->cb) +struct dn_skb_cb { + __le16 dst; + __le16 src; + __u16 hops; + __le16 dst_port; + __le16 src_port; + __u8 services; + __u8 info; + __u8 rt_flags; + __u8 nsp_flags; + __u16 segsize; + __u16 segnum; + __u16 xmit_count; + unsigned long stamp; + int iif; +}; + +static inline __le16 dn_eth2dn(unsigned char *ethaddr) +{ + return get_unaligned((__le16 *)(ethaddr + 4)); +} + +static inline __le16 dn_saddr2dn(struct sockaddr_dn *saddr) +{ + return *(__le16 *)saddr->sdn_nodeaddr; +} + +static inline void dn_dn2eth(unsigned char *ethaddr, __le16 addr) +{ + __u16 a = le16_to_cpu(addr); + ethaddr[0] = 0xAA; + ethaddr[1] = 0x00; + ethaddr[2] = 0x04; + ethaddr[3] = 0x00; + ethaddr[4] = (__u8)(a & 0xff); + ethaddr[5] = (__u8)(a >> 8); +} + +static inline void dn_sk_ports_copy(struct flowi *fl, struct dn_scp *scp) +{ + fl->uli_u.dnports.sport = scp->addrloc; + fl->uli_u.dnports.dport = scp->addrrem; +} + +extern unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu); + +#define DN_MENUVER_ACC 0x01 +#define DN_MENUVER_USR 0x02 +#define DN_MENUVER_PRX 0x04 +#define DN_MENUVER_UIC 0x08 + +extern struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr); +extern struct sock *dn_find_by_skb(struct sk_buff *skb); +#define DN_ASCBUF_LEN 9 +extern char *dn_addr2asc(__u16, char *); +extern int dn_destroy_timer(struct sock *sk); + +extern int dn_sockaddr2username(struct sockaddr_dn *addr, unsigned char *buf, unsigned char type); +extern int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *addr, unsigned char *type); + +extern void dn_start_slow_timer(struct sock *sk); +extern void dn_stop_slow_timer(struct sock *sk); + +extern __le16 decnet_address; +extern int decnet_debug_level; +extern int decnet_time_wait; +extern int decnet_dn_count; +extern int decnet_di_count; +extern int decnet_dr_count; +extern int decnet_no_fc_max_cwnd; + +extern int sysctl_decnet_mem[3]; +extern int sysctl_decnet_wmem[3]; +extern int sysctl_decnet_rmem[3]; + +#endif /* _NET_DN_H */ diff --git a/include/net/dn_dev.h b/include/net/dn_dev.h new file mode 100644 index 00000000..0916bbf3 --- /dev/null +++ b/include/net/dn_dev.h @@ -0,0 +1,189 @@ +#ifndef _NET_DN_DEV_H +#define _NET_DN_DEV_H + + +struct dn_dev; + +struct dn_ifaddr { + struct dn_ifaddr *ifa_next; + struct dn_dev *ifa_dev; + __le16 ifa_local; + __le16 ifa_address; + __u8 ifa_flags; + __u8 ifa_scope; + char ifa_label[IFNAMSIZ]; +}; + +#define DN_DEV_S_RU 0 /* Run - working normally */ +#define DN_DEV_S_CR 1 /* Circuit Rejected */ +#define DN_DEV_S_DS 2 /* Data Link Start */ +#define DN_DEV_S_RI 3 /* Routing Layer Initialize */ +#define DN_DEV_S_RV 4 /* Routing Layer Verify */ +#define DN_DEV_S_RC 5 /* Routing Layer Complete */ +#define DN_DEV_S_OF 6 /* Off */ +#define DN_DEV_S_HA 7 /* Halt */ + + +/* + * The dn_dev_parms structure contains the set of parameters + * for each device (hence inclusion in the dn_dev structure) + * and an array is used to store the default types of supported + * device (in dn_dev.c). + * + * The type field matches the ARPHRD_ constants and is used in + * searching the list for supported devices when new devices + * come up. + * + * The mode field is used to find out if a device is broadcast, + * multipoint, or pointopoint. Please note that DECnet thinks + * different ways about devices to the rest of the kernel + * so the normal IFF_xxx flags are invalid here. For devices + * which can be any combination of the previously mentioned + * attributes, you can set this on a per device basis by + * installing an up() routine. + * + * The device state field, defines the initial state in which the + * device will come up. In the dn_dev structure, it is the actual + * state. + * + * Things have changed here. I've killed timer1 since it's a user space + * issue for a user space routing deamon to sort out. The kernel does + * not need to be bothered with it. + * + * Timers: + * t2 - Rate limit timer, min time between routing and hello messages + * t3 - Hello timer, send hello messages when it expires + * + * Callbacks: + * up() - Called to initialize device, return value can veto use of + * device with DECnet. + * down() - Called to turn device off when it goes down + * timer3() - Called once for each ifaddr when timer 3 goes off + * + * sysctl - Hook for sysctl things + * + */ +struct dn_dev_parms { + int type; /* ARPHRD_xxx */ + int mode; /* Broadcast, Unicast, Mulitpoint */ +#define DN_DEV_BCAST 1 +#define DN_DEV_UCAST 2 +#define DN_DEV_MPOINT 4 + int state; /* Initial state */ + int forwarding; /* 0=EndNode, 1=L1Router, 2=L2Router */ + unsigned long t2; /* Default value of t2 */ + unsigned long t3; /* Default value of t3 */ + int priority; /* Priority to be a router */ + char *name; /* Name for sysctl */ + int (*up)(struct net_device *); + void (*down)(struct net_device *); + void (*timer3)(struct net_device *, struct dn_ifaddr *ifa); + void *sysctl; +}; + + +struct dn_dev { + struct dn_ifaddr *ifa_list; + struct net_device *dev; + struct dn_dev_parms parms; + char use_long; + struct timer_list timer; + unsigned long t3; + struct neigh_parms *neigh_parms; + __u8 addr[ETH_ALEN]; + struct neighbour *router; /* Default router on circuit */ + struct neighbour *peer; /* Peer on pointopoint links */ + unsigned long uptime; /* Time device went up in jiffies */ +}; + +struct dn_short_packet { + __u8 msgflg; + __le16 dstnode; + __le16 srcnode; + __u8 forward; +} __packed; + +struct dn_long_packet { + __u8 msgflg; + __u8 d_area; + __u8 d_subarea; + __u8 d_id[6]; + __u8 s_area; + __u8 s_subarea; + __u8 s_id[6]; + __u8 nl2; + __u8 visit_ct; + __u8 s_class; + __u8 pt; +} __packed; + +/*------------------------- DRP - Routing messages ---------------------*/ + +struct endnode_hello_message { + __u8 msgflg; + __u8 tiver[3]; + __u8 id[6]; + __u8 iinfo; + __le16 blksize; + __u8 area; + __u8 seed[8]; + __u8 neighbor[6]; + __le16 timer; + __u8 mpd; + __u8 datalen; + __u8 data[2]; +} __packed; + +struct rtnode_hello_message { + __u8 msgflg; + __u8 tiver[3]; + __u8 id[6]; + __u8 iinfo; + __le16 blksize; + __u8 priority; + __u8 area; + __le16 timer; + __u8 mpd; +} __packed; + + +extern void dn_dev_init(void); +extern void dn_dev_cleanup(void); + +extern int dn_dev_ioctl(unsigned int cmd, void __user *arg); + +extern void dn_dev_devices_off(void); +extern void dn_dev_devices_on(void); + +extern void dn_dev_init_pkt(struct sk_buff *skb); +extern void dn_dev_veri_pkt(struct sk_buff *skb); +extern void dn_dev_hello(struct sk_buff *skb); + +extern void dn_dev_up(struct net_device *); +extern void dn_dev_down(struct net_device *); + +extern int dn_dev_set_default(struct net_device *dev, int force); +extern struct net_device *dn_dev_get_default(void); +extern int dn_dev_bind_default(__le16 *addr); + +extern int register_dnaddr_notifier(struct notifier_block *nb); +extern int unregister_dnaddr_notifier(struct notifier_block *nb); + +static inline int dn_dev_islocal(struct net_device *dev, __le16 addr) +{ + struct dn_dev *dn_db = dev->dn_ptr; + struct dn_ifaddr *ifa; + + if (dn_db == NULL) { + printk(KERN_DEBUG "dn_dev_islocal: Called for non DECnet device\n"); + return 0; + } + + for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) + if ((addr ^ ifa->ifa_local) == 0) + return 1; + + return 0; +} + +#endif /* _NET_DN_DEV_H */ diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h new file mode 100644 index 00000000..bbcde323 --- /dev/null +++ b/include/net/dn_fib.h @@ -0,0 +1,184 @@ +#ifndef _NET_DN_FIB_H +#define _NET_DN_FIB_H + +/* WARNING: The ordering of these elements must match ordering + * of RTA_* rtnetlink attribute numbers. + */ +struct dn_kern_rta { + void *rta_dst; + void *rta_src; + int *rta_iif; + int *rta_oif; + void *rta_gw; + u32 *rta_priority; + void *rta_prefsrc; + struct rtattr *rta_mx; + struct rtattr *rta_mp; + unsigned char *rta_protoinfo; + u32 *rta_flow; + struct rta_cacheinfo *rta_ci; + struct rta_session *rta_sess; +}; + +struct dn_fib_res { + struct fib_rule *r; + struct dn_fib_info *fi; + unsigned char prefixlen; + unsigned char nh_sel; + unsigned char type; + unsigned char scope; +}; + +struct dn_fib_nh { + struct net_device *nh_dev; + unsigned nh_flags; + unsigned char nh_scope; + int nh_weight; + int nh_power; + int nh_oif; + __le16 nh_gw; +}; + +struct dn_fib_info { + struct dn_fib_info *fib_next; + struct dn_fib_info *fib_prev; + int fib_treeref; + atomic_t fib_clntref; + int fib_dead; + unsigned fib_flags; + int fib_protocol; + __le16 fib_prefsrc; + __u32 fib_priority; + __u32 fib_metrics[RTAX_MAX]; + int fib_nhs; + int fib_power; + struct dn_fib_nh fib_nh[0]; +#define dn_fib_dev fib_nh[0].nh_dev +}; + + +#define DN_FIB_RES_RESET(res) ((res).nh_sel = 0) +#define DN_FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel]) + +#define DN_FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __dn_fib_res_prefsrc(&res)) +#define DN_FIB_RES_GW(res) (DN_FIB_RES_NH(res).nh_gw) +#define DN_FIB_RES_DEV(res) (DN_FIB_RES_NH(res).nh_dev) +#define DN_FIB_RES_OIF(res) (DN_FIB_RES_NH(res).nh_oif) + +typedef struct { + __le16 datum; +} dn_fib_key_t; + +typedef struct { + __le16 datum; +} dn_fib_hash_t; + +typedef struct { + __u16 datum; +} dn_fib_idx_t; + +struct dn_fib_node { + struct dn_fib_node *fn_next; + struct dn_fib_info *fn_info; +#define DN_FIB_INFO(f) ((f)->fn_info) + dn_fib_key_t fn_key; + u8 fn_type; + u8 fn_scope; + u8 fn_state; +}; + + +struct dn_fib_table { + struct hlist_node hlist; + u32 n; + + int (*insert)(struct dn_fib_table *t, struct rtmsg *r, + struct dn_kern_rta *rta, struct nlmsghdr *n, + struct netlink_skb_parms *req); + int (*delete)(struct dn_fib_table *t, struct rtmsg *r, + struct dn_kern_rta *rta, struct nlmsghdr *n, + struct netlink_skb_parms *req); + int (*lookup)(struct dn_fib_table *t, const struct flowi *fl, + struct dn_fib_res *res); + int (*flush)(struct dn_fib_table *t); + int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb); + + unsigned char data[0]; +}; + +#ifdef CONFIG_DECNET_ROUTER +/* + * dn_fib.c + */ +extern void dn_fib_init(void); +extern void dn_fib_cleanup(void); + +extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); +extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, + struct dn_kern_rta *rta, + const struct nlmsghdr *nlh, int *errp); +extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi, + const struct flowi *fl, + struct dn_fib_res *res); +extern void dn_fib_release_info(struct dn_fib_info *fi); +extern __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type); +extern void dn_fib_flush(void); +extern void dn_fib_select_multipath(const struct flowi *fl, + struct dn_fib_res *res); + +/* + * dn_tables.c + */ +extern struct dn_fib_table *dn_fib_get_table(u32 n, int creat); +extern struct dn_fib_table *dn_fib_empty_table(void); +extern void dn_fib_table_init(void); +extern void dn_fib_table_cleanup(void); + +/* + * dn_rules.c + */ +extern void dn_fib_rules_init(void); +extern void dn_fib_rules_cleanup(void); +extern unsigned dnet_addr_type(__le16 addr); +extern int dn_fib_lookup(struct flowi *fl, struct dn_fib_res *res); + +extern int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb); + +extern void dn_fib_free_info(struct dn_fib_info *fi); + +static inline void dn_fib_info_put(struct dn_fib_info *fi) +{ + if (atomic_dec_and_test(&fi->fib_clntref)) + dn_fib_free_info(fi); +} + +static inline void dn_fib_res_put(struct dn_fib_res *res) +{ + if (res->fi) + dn_fib_info_put(res->fi); + if (res->r) + fib_rule_put(res->r); +} + +#else /* Endnode */ + +#define dn_fib_init() do { } while(0) +#define dn_fib_cleanup() do { } while(0) + +#define dn_fib_lookup(fl, res) (-ESRCH) +#define dn_fib_info_put(fi) do { } while(0) +#define dn_fib_select_multipath(fl, res) do { } while(0) +#define dn_fib_rules_policy(saddr,res,flags) (0) +#define dn_fib_res_put(res) do { } while(0) + +#endif /* CONFIG_DECNET_ROUTER */ + +static inline __le16 dnet_make_mask(int n) +{ + if (n) + return cpu_to_le16(~((1 << (16 - n)) - 1)); + return cpu_to_le16(0); +} + +#endif /* _NET_DN_FIB_H */ diff --git a/include/net/dn_neigh.h b/include/net/dn_neigh.h new file mode 100644 index 00000000..4cb4ae7f --- /dev/null +++ b/include/net/dn_neigh.h @@ -0,0 +1,28 @@ +#ifndef _NET_DN_NEIGH_H +#define _NET_DN_NEIGH_H + +/* + * The position of the first two fields of + * this structure are critical - SJW + */ +struct dn_neigh { + struct neighbour n; + __le16 addr; + unsigned long flags; +#define DN_NDFLAG_R1 0x0001 /* Router L1 */ +#define DN_NDFLAG_R2 0x0002 /* Router L2 */ +#define DN_NDFLAG_P3 0x0004 /* Phase III Node */ + unsigned long blksize; + __u8 priority; +}; + +extern void dn_neigh_init(void); +extern void dn_neigh_cleanup(void); +extern int dn_neigh_router_hello(struct sk_buff *skb); +extern int dn_neigh_endnode_hello(struct sk_buff *skb); +extern void dn_neigh_pointopoint_hello(struct sk_buff *skb); +extern int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n); + +extern struct neigh_table dn_neigh_table; + +#endif /* _NET_DN_NEIGH_H */ diff --git a/include/net/dn_nsp.h b/include/net/dn_nsp.h new file mode 100644 index 00000000..e43a2893 --- /dev/null +++ b/include/net/dn_nsp.h @@ -0,0 +1,201 @@ +#ifndef _NET_DN_NSP_H +#define _NET_DN_NSP_H +/****************************************************************************** + (c) 1995-1998 E.M. Serrat emserrat@geocities.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*******************************************************************************/ +/* dn_nsp.c functions prototyping */ + +extern void dn_nsp_send_data_ack(struct sock *sk); +extern void dn_nsp_send_oth_ack(struct sock *sk); +extern void dn_nsp_delayed_ack(struct sock *sk); +extern void dn_send_conn_ack(struct sock *sk); +extern void dn_send_conn_conf(struct sock *sk, gfp_t gfp); +extern void dn_nsp_send_disc(struct sock *sk, unsigned char type, + unsigned short reason, gfp_t gfp); +extern void dn_nsp_return_disc(struct sk_buff *skb, unsigned char type, + unsigned short reason); +extern void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval); +extern void dn_nsp_send_conninit(struct sock *sk, unsigned char flags); + +extern void dn_nsp_output(struct sock *sk); +extern int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *q, unsigned short acknum); +extern void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb, gfp_t gfp, int oob); +extern unsigned long dn_nsp_persist(struct sock *sk); +extern int dn_nsp_xmit_timeout(struct sock *sk); + +extern int dn_nsp_rx(struct sk_buff *); +extern int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb); + +extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri); +extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, long timeo, int *err); + +#define NSP_REASON_OK 0 /* No error */ +#define NSP_REASON_NR 1 /* No resources */ +#define NSP_REASON_UN 2 /* Unrecognised node name */ +#define NSP_REASON_SD 3 /* Node shutting down */ +#define NSP_REASON_ID 4 /* Invalid destination end user */ +#define NSP_REASON_ER 5 /* End user lacks resources */ +#define NSP_REASON_OB 6 /* Object too busy */ +#define NSP_REASON_US 7 /* Unspecified error */ +#define NSP_REASON_TP 8 /* Third-Party abort */ +#define NSP_REASON_EA 9 /* End user has aborted the link */ +#define NSP_REASON_IF 10 /* Invalid node name format */ +#define NSP_REASON_LS 11 /* Local node shutdown */ +#define NSP_REASON_LL 32 /* Node lacks logical-link resources */ +#define NSP_REASON_LE 33 /* End user lacks logical-link resources */ +#define NSP_REASON_UR 34 /* Unacceptable RQSTRID or PASSWORD field */ +#define NSP_REASON_UA 36 /* Unacceptable ACCOUNT field */ +#define NSP_REASON_TM 38 /* End user timed out logical link */ +#define NSP_REASON_NU 39 /* Node unreachable */ +#define NSP_REASON_NL 41 /* No-link message */ +#define NSP_REASON_DC 42 /* Disconnect confirm */ +#define NSP_REASON_IO 43 /* Image data field overflow */ + +#define NSP_DISCINIT 0x38 +#define NSP_DISCCONF 0x48 + +/*------------------------- NSP - messages ------------------------------*/ +/* Data Messages */ +/*---------------*/ + +/* Data Messages (data segment/interrupt/link service) */ + +struct nsp_data_seg_msg { + __u8 msgflg; + __le16 dstaddr; + __le16 srcaddr; +} __packed; + +struct nsp_data_opt_msg { + __le16 acknum; + __le16 segnum; + __le16 lsflgs; +} __packed; + +struct nsp_data_opt_msg1 { + __le16 acknum; + __le16 segnum; +} __packed; + + +/* Acknowledgment Message (data/other data) */ +struct nsp_data_ack_msg { + __u8 msgflg; + __le16 dstaddr; + __le16 srcaddr; + __le16 acknum; +} __packed; + +/* Connect Acknowledgment Message */ +struct nsp_conn_ack_msg { + __u8 msgflg; + __le16 dstaddr; +} __packed; + + +/* Connect Initiate/Retransmit Initiate/Connect Confirm */ +struct nsp_conn_init_msg { + __u8 msgflg; +#define NSP_CI 0x18 /* Connect Initiate */ +#define NSP_RCI 0x68 /* Retrans. Conn Init */ + __le16 dstaddr; + __le16 srcaddr; + __u8 services; +#define NSP_FC_NONE 0x00 /* Flow Control None */ +#define NSP_FC_SRC 0x04 /* Seg Req. Count */ +#define NSP_FC_SCMC 0x08 /* Sess. Control Mess */ +#define NSP_FC_MASK 0x0c /* FC type mask */ + __u8 info; + __le16 segsize; +} __packed; + +/* Disconnect Initiate/Disconnect Confirm */ +struct nsp_disconn_init_msg { + __u8 msgflg; + __le16 dstaddr; + __le16 srcaddr; + __le16 reason; +} __packed; + + + +struct srcobj_fmt { + __u8 format; + __u8 task; + __le16 grpcode; + __le16 usrcode; + __u8 dlen; +} __packed; + +/* + * A collection of functions for manipulating the sequence + * numbers used in NSP. Similar in operation to the functions + * of the same name in TCP. + */ +static __inline__ int dn_before(__u16 seq1, __u16 seq2) +{ + seq1 &= 0x0fff; + seq2 &= 0x0fff; + + return (int)((seq1 - seq2) & 0x0fff) > 2048; +} + + +static __inline__ int dn_after(__u16 seq1, __u16 seq2) +{ + seq1 &= 0x0fff; + seq2 &= 0x0fff; + + return (int)((seq2 - seq1) & 0x0fff) > 2048; +} + +static __inline__ int dn_equal(__u16 seq1, __u16 seq2) +{ + return ((seq1 ^ seq2) & 0x0fff) == 0; +} + +static __inline__ int dn_before_or_equal(__u16 seq1, __u16 seq2) +{ + return (dn_before(seq1, seq2) || dn_equal(seq1, seq2)); +} + +static __inline__ void seq_add(__u16 *seq, __u16 off) +{ + (*seq) += off; + (*seq) &= 0x0fff; +} + +static __inline__ int seq_next(__u16 seq1, __u16 seq2) +{ + return dn_equal(seq1 + 1, seq2); +} + +/* + * Can we delay the ack ? + */ +static __inline__ int sendack(__u16 seq) +{ + return (int)((seq & 0x1000) ? 0 : 1); +} + +/* + * Is socket congested ? + */ +static __inline__ int dn_congested(struct sock *sk) +{ + return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1); +} + +#define DN_MAX_NSP_DATA_HEADER (11) + +#endif /* _NET_DN_NSP_H */ diff --git a/include/net/dn_route.h b/include/net/dn_route.h new file mode 100644 index 00000000..ccadab3a --- /dev/null +++ b/include/net/dn_route.h @@ -0,0 +1,107 @@ +#ifndef _NET_DN_ROUTE_H +#define _NET_DN_ROUTE_H + +/****************************************************************************** + (c) 1995-1998 E.M. Serrat emserrat@geocities.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*******************************************************************************/ + +extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri); +extern int dn_route_output_sock(struct dst_entry **pprt, struct flowi *, struct sock *sk, int flags); +extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); +extern void dn_rt_cache_flush(int delay); + +/* Masks for flags field */ +#define DN_RT_F_PID 0x07 /* Mask for packet type */ +#define DN_RT_F_PF 0x80 /* Padding Follows */ +#define DN_RT_F_VER 0x40 /* Version =0 discard packet if ==1 */ +#define DN_RT_F_IE 0x20 /* Intra Ethernet, Reserved in short pkt */ +#define DN_RT_F_RTS 0x10 /* Packet is being returned to sender */ +#define DN_RT_F_RQR 0x08 /* Return packet to sender upon non-delivery */ + +/* Mask for types of routing packets */ +#define DN_RT_PKT_MSK 0x06 +/* Types of routing packets */ +#define DN_RT_PKT_SHORT 0x02 /* Short routing packet */ +#define DN_RT_PKT_LONG 0x06 /* Long routing packet */ + +/* Mask for control/routing selection */ +#define DN_RT_PKT_CNTL 0x01 /* Set to 1 if a control packet */ +/* Types of control packets */ +#define DN_RT_CNTL_MSK 0x0f /* Mask for control packets */ +#define DN_RT_PKT_INIT 0x01 /* Initialisation packet */ +#define DN_RT_PKT_VERI 0x03 /* Verification Message */ +#define DN_RT_PKT_HELO 0x05 /* Hello and Test Message */ +#define DN_RT_PKT_L1RT 0x07 /* Level 1 Routing Message */ +#define DN_RT_PKT_L2RT 0x09 /* Level 2 Routing Message */ +#define DN_RT_PKT_ERTH 0x0b /* Ethernet Router Hello */ +#define DN_RT_PKT_EEDH 0x0d /* Ethernet EndNode Hello */ + +/* Values for info field in hello message */ +#define DN_RT_INFO_TYPE 0x03 /* Type mask */ +#define DN_RT_INFO_L1RT 0x02 /* L1 Router */ +#define DN_RT_INFO_L2RT 0x01 /* L2 Router */ +#define DN_RT_INFO_ENDN 0x03 /* EndNode */ +#define DN_RT_INFO_VERI 0x04 /* Verification Reqd. */ +#define DN_RT_INFO_RJCT 0x08 /* Reject Flag, Reserved */ +#define DN_RT_INFO_VFLD 0x10 /* Verification Failed, Reserved */ +#define DN_RT_INFO_NOML 0x20 /* No Multicast traffic accepted */ +#define DN_RT_INFO_BLKR 0x40 /* Blocking Requested */ + +/* + * The fl structure is what we used to look up the route. + * The rt_saddr & rt_daddr entries are the same as key.saddr & key.daddr + * except for local input routes, where the rt_saddr = fl.fld_dst and + * rt_daddr = fl.fld_src to allow the route to be used for returning + * packets to the originating host. + */ +struct dn_route { + struct dst_entry dst; + + struct flowi fl; + + __le16 rt_saddr; + __le16 rt_daddr; + __le16 rt_gateway; + __le16 rt_local_src; /* Source used for forwarding packets */ + __le16 rt_src_map; + __le16 rt_dst_map; + + unsigned rt_flags; + unsigned rt_type; +}; + +extern void dn_route_init(void); +extern void dn_route_cleanup(void); + +#include <net/sock.h> +#include <linux/if_arp.h> + +static inline void dn_rt_send(struct sk_buff *skb) +{ + dev_queue_xmit(skb); +} + +static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst, char *src) +{ + struct net_device *dev = skb->dev; + + if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) + dst = NULL; + + if (dev_hard_header(skb, dev, ETH_P_DNA_RT, dst, src, skb->len) >= 0) + dn_rt_send(skb); + else + kfree_skb(skb); +} + +#endif /* _NET_DN_ROUTE_H */ diff --git a/include/net/dsa.h b/include/net/dsa.h new file mode 100644 index 00000000..839f768f --- /dev/null +++ b/include/net/dsa.h @@ -0,0 +1,61 @@ +/* + * include/net/dsa.h - Driver for Distributed Switch Architecture switch chips + * Copyright (c) 2008-2009 Marvell Semiconductor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_NET_DSA_H +#define __LINUX_NET_DSA_H + +#define DSA_MAX_SWITCHES 4 +#define DSA_MAX_PORTS 12 + +struct dsa_chip_data { + /* + * How to access the switch configuration registers. + */ + struct device *mii_bus; + int sw_addr; + + /* + * The names of the switch's ports. Use "cpu" to + * designate the switch port that the cpu is connected to, + * "dsa" to indicate that this port is a DSA link to + * another switch, NULL to indicate the port is unused, + * or any other string to indicate this is a physical port. + */ + char *port_names[DSA_MAX_PORTS]; + + /* + * An array (with nr_chips elements) of which element [a] + * indicates which port on this switch should be used to + * send packets to that are destined for switch a. Can be + * NULL if there is only one switch chip. + */ + s8 *rtable; +}; + +struct dsa_platform_data { + /* + * Reference to a Linux network interface that connects + * to the root switch chip of the tree. + */ + struct device *netdev; + + /* + * Info structs describing each of the switch chips + * connected via this network interface. + */ + int nr_chips; + struct dsa_chip_data *chip; +}; + +extern bool dsa_uses_dsa_tags(void *dsa_ptr); +extern bool dsa_uses_trailer_tags(void *dsa_ptr); + + +#endif diff --git a/include/net/dsfield.h b/include/net/dsfield.h new file mode 100644 index 00000000..8a8d4e06 --- /dev/null +++ b/include/net/dsfield.h @@ -0,0 +1,54 @@ +/* include/net/dsfield.h - Manipulation of the Differentiated Services field */ + +/* Written 1998-2000 by Werner Almesberger, EPFL ICA */ + + +#ifndef __NET_DSFIELD_H +#define __NET_DSFIELD_H + +#include <linux/types.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <asm/byteorder.h> + + +static inline __u8 ipv4_get_dsfield(const struct iphdr *iph) +{ + return iph->tos; +} + + +static inline __u8 ipv6_get_dsfield(const struct ipv6hdr *ipv6h) +{ + return ntohs(*(const __be16 *)ipv6h) >> 4; +} + + +static inline void ipv4_change_dsfield(struct iphdr *iph,__u8 mask, + __u8 value) +{ + __u32 check = ntohs((__force __be16)iph->check); + __u8 dsfield; + + dsfield = (iph->tos & mask) | value; + check += iph->tos; + if ((check+1) >> 16) check = (check+1) & 0xffff; + check -= dsfield; + check += check >> 16; /* adjust carry */ + iph->check = (__force __sum16)htons(check); + iph->tos = dsfield; +} + + +static inline void ipv6_change_dsfield(struct ipv6hdr *ipv6h,__u8 mask, + __u8 value) +{ + __u16 tmp; + + tmp = ntohs(*(__be16 *) ipv6h); + tmp = (tmp & ((mask << 4) | 0xf00f)) | (value << 4); + *(__be16 *) ipv6h = htons(tmp); +} + + +#endif diff --git a/include/net/dst.h b/include/net/dst.h new file mode 100644 index 00000000..02386505 --- /dev/null +++ b/include/net/dst.h @@ -0,0 +1,356 @@ +/* + * net/dst.h Protocol independent destination cache definitions. + * + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + * + */ + +#ifndef _NET_DST_H +#define _NET_DST_H + +#include <net/dst_ops.h> +#include <linux/netdevice.h> +#include <linux/rtnetlink.h> +#include <linux/rcupdate.h> +#include <linux/jiffies.h> +#include <net/neighbour.h> +#include <asm/processor.h> + +/* + * 0 - no debugging messages + * 1 - rare events and bugs (default) + * 2 - trace mode. + */ +#define RT_CACHE_DEBUG 0 + +#define DST_GC_MIN (HZ/10) +#define DST_GC_INC (HZ/2) +#define DST_GC_MAX (120*HZ) + +/* Each dst_entry has reference count and sits in some parent list(s). + * When it is removed from parent list, it is "freed" (dst_free). + * After this it enters dead state (dst->obsolete > 0) and if its refcnt + * is zero, it can be destroyed immediately, otherwise it is added + * to gc list and garbage collector periodically checks the refcnt. + */ + +struct sk_buff; + +struct dst_entry { + struct rcu_head rcu_head; + struct dst_entry *child; + struct net_device *dev; + short error; + short obsolete; + int flags; +#define DST_HOST 1 +#define DST_NOXFRM 2 +#define DST_NOPOLICY 4 +#define DST_NOHASH 8 + unsigned long expires; + + unsigned short header_len; /* more space at head required */ + unsigned short trailer_len; /* space to reserve at tail */ + + unsigned int rate_tokens; + unsigned long rate_last; /* rate limiting for ICMP */ + + struct dst_entry *path; + + struct neighbour *neighbour; + struct hh_cache *hh; +#ifdef CONFIG_XFRM + struct xfrm_state *xfrm; +#else + void *__pad1; +#endif + int (*input)(struct sk_buff*); + int (*output)(struct sk_buff*); + + struct dst_ops *ops; + + u32 metrics[RTAX_MAX]; + +#ifdef CONFIG_NET_CLS_ROUTE + __u32 tclassid; +#else + __u32 __pad2; +#endif + + + /* + * Align __refcnt to a 64 bytes alignment + * (L1_CACHE_SIZE would be too much) + */ +#ifdef CONFIG_64BIT + long __pad_to_align_refcnt[1]; +#endif + /* + * __refcnt wants to be on a different cache line from + * input/output/ops or performance tanks badly + */ + atomic_t __refcnt; /* client references */ + int __use; + unsigned long lastuse; + union { + struct dst_entry *next; + struct rtable *rt_next; + struct rt6_info *rt6_next; + struct dn_route *dn_next; + }; +}; + +#ifdef __KERNEL__ + +static inline u32 +dst_metric(const struct dst_entry *dst, int metric) +{ + return dst->metrics[metric-1]; +} + +static inline u32 +dst_feature(const struct dst_entry *dst, u32 feature) +{ + return dst_metric(dst, RTAX_FEATURES) & feature; +} + +static inline u32 dst_mtu(const struct dst_entry *dst) +{ + u32 mtu = dst_metric(dst, RTAX_MTU); + /* + * Alexey put it here, so ask him about it :) + */ + barrier(); + return mtu; +} + +/* RTT metrics are stored in milliseconds for user ABI, but used as jiffies */ +static inline unsigned long dst_metric_rtt(const struct dst_entry *dst, int metric) +{ + return msecs_to_jiffies(dst_metric(dst, metric)); +} + +static inline void set_dst_metric_rtt(struct dst_entry *dst, int metric, + unsigned long rtt) +{ + dst->metrics[metric-1] = jiffies_to_msecs(rtt); +} + +static inline u32 +dst_allfrag(const struct dst_entry *dst) +{ + int ret = dst_feature(dst, RTAX_FEATURE_ALLFRAG); + /* Yes, _exactly_. This is paranoia. */ + barrier(); + return ret; +} + +static inline int +dst_metric_locked(struct dst_entry *dst, int metric) +{ + return dst_metric(dst, RTAX_LOCK) & (1<<metric); +} + +static inline void dst_hold(struct dst_entry * dst) +{ + /* + * If your kernel compilation stops here, please check + * __pad_to_align_refcnt declaration in struct dst_entry + */ + BUILD_BUG_ON(offsetof(struct dst_entry, __refcnt) & 63); + atomic_inc(&dst->__refcnt); +} + +static inline void dst_use(struct dst_entry *dst, unsigned long time) +{ + dst_hold(dst); + dst->__use++; + dst->lastuse = time; +} + +static inline void dst_use_noref(struct dst_entry *dst, unsigned long time) +{ + dst->__use++; + dst->lastuse = time; +} + +static inline +struct dst_entry * dst_clone(struct dst_entry * dst) +{ + if (dst) + atomic_inc(&dst->__refcnt); + return dst; +} + +extern void dst_release(struct dst_entry *dst); + +static inline void refdst_drop(unsigned long refdst) +{ + if (!(refdst & SKB_DST_NOREF)) + dst_release((struct dst_entry *)(refdst & SKB_DST_PTRMASK)); +} + +/** + * skb_dst_drop - drops skb dst + * @skb: buffer + * + * Drops dst reference count if a reference was taken. + */ +static inline void skb_dst_drop(struct sk_buff *skb) +{ + if (skb->_skb_refdst) { + refdst_drop(skb->_skb_refdst); + skb->_skb_refdst = 0UL; + } +} + +static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb) +{ + nskb->_skb_refdst = oskb->_skb_refdst; + if (!(nskb->_skb_refdst & SKB_DST_NOREF)) + dst_clone(skb_dst(nskb)); +} + +/** + * skb_dst_force - makes sure skb dst is refcounted + * @skb: buffer + * + * If dst is not yet refcounted, let's do it + */ +static inline void skb_dst_force(struct sk_buff *skb) +{ + if (skb_dst_is_noref(skb)) { + WARN_ON(!rcu_read_lock_held()); + skb->_skb_refdst &= ~SKB_DST_NOREF; + dst_clone(skb_dst(skb)); + } +} + + +/** + * skb_tunnel_rx - prepare skb for rx reinsert + * @skb: buffer + * @dev: tunnel device + * + * After decapsulation, packet is going to re-enter (netif_rx()) our stack, + * so make some cleanups, and perform accounting. + */ +static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev) +{ + skb->dev = dev; + /* TODO : stats should be SMP safe */ + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + skb->rxhash = 0; + skb_set_queue_mapping(skb, 0); + skb_dst_drop(skb); + nf_reset(skb); +} + +/* Children define the path of the packet through the + * Linux networking. Thus, destinations are stackable. + */ + +static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb) +{ + struct dst_entry *child = skb_dst(skb)->child; + + skb_dst_drop(skb); + return child; +} + +extern int dst_discard(struct sk_buff *skb); +extern void * dst_alloc(struct dst_ops * ops); +extern void __dst_free(struct dst_entry * dst); +extern struct dst_entry *dst_destroy(struct dst_entry * dst); + +static inline void dst_free(struct dst_entry * dst) +{ + if (dst->obsolete > 1) + return; + if (!atomic_read(&dst->__refcnt)) { + dst = dst_destroy(dst); + if (!dst) + return; + } + __dst_free(dst); +} + +static inline void dst_rcu_free(struct rcu_head *head) +{ + struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head); + dst_free(dst); +} + +static inline void dst_confirm(struct dst_entry *dst) +{ + if (dst) + neigh_confirm(dst->neighbour); +} + +static inline void dst_link_failure(struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + if (dst && dst->ops && dst->ops->link_failure) + dst->ops->link_failure(skb); +} + +static inline void dst_set_expires(struct dst_entry *dst, int timeout) +{ + unsigned long expires = jiffies + timeout; + + if (expires == 0) + expires = 1; + + if (dst->expires == 0 || time_before(expires, dst->expires)) + dst->expires = expires; +} + +/* Output packet to network from transport. */ +static inline int dst_output(struct sk_buff *skb) +{ + return skb_dst(skb)->output(skb); +} + +/* Input packet from network to transport. */ +static inline int dst_input(struct sk_buff *skb) +{ + return skb_dst(skb)->input(skb); +} + +static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie) +{ + if (dst->obsolete) + dst = dst->ops->check(dst, cookie); + return dst; +} + +extern void dst_init(void); + +/* Flags for xfrm_lookup flags argument. */ +enum { + XFRM_LOOKUP_WAIT = 1 << 0, + XFRM_LOOKUP_ICMP = 1 << 1, +}; + +struct flowi; +#ifndef CONFIG_XFRM +static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags) +{ + return 0; +} +static inline int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags) +{ + return 0; +} +#else +extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags); +extern int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags); +#endif +#endif + +#endif /* _NET_DST_H */ diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h new file mode 100644 index 00000000..d1ff9b7e --- /dev/null +++ b/include/net/dst_ops.h @@ -0,0 +1,28 @@ +#ifndef _NET_DST_OPS_H +#define _NET_DST_OPS_H +#include <linux/types.h> + +struct dst_entry; +struct kmem_cachep; +struct net_device; +struct sk_buff; + +struct dst_ops { + unsigned short family; + __be16 protocol; + unsigned gc_thresh; + + int (*gc)(struct dst_ops *ops); + struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); + void (*destroy)(struct dst_entry *); + void (*ifdown)(struct dst_entry *, + struct net_device *dev, int how); + struct dst_entry * (*negative_advice)(struct dst_entry *); + void (*link_failure)(struct sk_buff *); + void (*update_pmtu)(struct dst_entry *dst, u32 mtu); + int (*local_out)(struct sk_buff *skb); + + atomic_t entries; + struct kmem_cache *kmem_cachep; +}; +#endif diff --git a/include/net/esp.h b/include/net/esp.h new file mode 100644 index 00000000..d5845133 --- /dev/null +++ b/include/net/esp.h @@ -0,0 +1,25 @@ +#ifndef _NET_ESP_H +#define _NET_ESP_H + +#include <linux/skbuff.h> + +struct crypto_aead; + +struct esp_data { + /* 0..255 */ + int padlen; + + /* Confidentiality & Integrity */ + struct crypto_aead *aead; +}; + +extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len); + +struct ip_esp_hdr; + +static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) +{ + return (struct ip_esp_hdr *)skb_transport_header(skb); +} + +#endif diff --git a/include/net/ethoc.h b/include/net/ethoc.h new file mode 100644 index 00000000..96f3789b --- /dev/null +++ b/include/net/ethoc.h @@ -0,0 +1,22 @@ +/* + * linux/include/net/ethoc.h + * + * Copyright (C) 2008-2009 Avionic Design GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Written by Thierry Reding <thierry.reding@avionic-design.de> + */ + +#ifndef LINUX_NET_ETHOC_H +#define LINUX_NET_ETHOC_H 1 + +struct ethoc_platform_data { + u8 hwaddr[IFHWADDRLEN]; + s8 phy_id; +}; + +#endif /* !LINUX_NET_ETHOC_H */ + diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h new file mode 100644 index 00000000..e8923bc2 --- /dev/null +++ b/include/net/fib_rules.h @@ -0,0 +1,118 @@ +#ifndef __NET_FIB_RULES_H +#define __NET_FIB_RULES_H + +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/netdevice.h> +#include <linux/fib_rules.h> +#include <net/flow.h> +#include <net/rtnetlink.h> + +struct fib_rule { + struct list_head list; + atomic_t refcnt; + int iifindex; + int oifindex; + u32 mark; + u32 mark_mask; + u32 pref; + u32 flags; + u32 table; + u8 action; + u32 target; + struct fib_rule * ctarget; + char iifname[IFNAMSIZ]; + char oifname[IFNAMSIZ]; + struct rcu_head rcu; + struct net * fr_net; +}; + +struct fib_lookup_arg { + void *lookup_ptr; + void *result; + struct fib_rule *rule; +}; + +struct fib_rules_ops { + int family; + struct list_head list; + int rule_size; + int addr_size; + int unresolved_rules; + int nr_goto_rules; + + int (*action)(struct fib_rule *, + struct flowi *, int, + struct fib_lookup_arg *); + int (*match)(struct fib_rule *, + struct flowi *, int); + int (*configure)(struct fib_rule *, + struct sk_buff *, + struct fib_rule_hdr *, + struct nlattr **); + int (*compare)(struct fib_rule *, + struct fib_rule_hdr *, + struct nlattr **); + int (*fill)(struct fib_rule *, struct sk_buff *, + struct fib_rule_hdr *); + u32 (*default_pref)(struct fib_rules_ops *ops); + size_t (*nlmsg_payload)(struct fib_rule *); + + /* Called after modifications to the rules set, must flush + * the route cache if one exists. */ + void (*flush_cache)(struct fib_rules_ops *ops); + + int nlgroup; + const struct nla_policy *policy; + struct list_head rules_list; + struct module *owner; + struct net *fro_net; + struct rcu_head rcu; +}; + +#define FRA_GENERIC_POLICY \ + [FRA_IIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ + [FRA_OIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ + [FRA_PRIORITY] = { .type = NLA_U32 }, \ + [FRA_FWMARK] = { .type = NLA_U32 }, \ + [FRA_FWMASK] = { .type = NLA_U32 }, \ + [FRA_TABLE] = { .type = NLA_U32 }, \ + [FRA_GOTO] = { .type = NLA_U32 } + +static inline void fib_rule_get(struct fib_rule *rule) +{ + atomic_inc(&rule->refcnt); +} + +static inline void fib_rule_put_rcu(struct rcu_head *head) +{ + struct fib_rule *rule = container_of(head, struct fib_rule, rcu); + release_net(rule->fr_net); + kfree(rule); +} + +static inline void fib_rule_put(struct fib_rule *rule) +{ + if (atomic_dec_and_test(&rule->refcnt)) + call_rcu(&rule->rcu, fib_rule_put_rcu); +} + +static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla) +{ + if (nla[FRA_TABLE]) + return nla_get_u32(nla[FRA_TABLE]); + return frh->table; +} + +extern struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *, struct net *); +extern void fib_rules_unregister(struct fib_rules_ops *); +extern void fib_rules_cleanup_ops(struct fib_rules_ops *); + +extern int fib_rules_lookup(struct fib_rules_ops *, + struct flowi *, int flags, + struct fib_lookup_arg *); +extern int fib_default_rule_add(struct fib_rules_ops *, + u32 pref, u32 table, + u32 flags); +extern u32 fib_default_rule_pref(struct fib_rules_ops *ops); +#endif diff --git a/include/net/flow.h b/include/net/flow.h new file mode 100644 index 00000000..bb08692a --- /dev/null +++ b/include/net/flow.h @@ -0,0 +1,118 @@ +/* + * + * Generic internet FLOW. + * + */ + +#ifndef _NET_FLOW_H +#define _NET_FLOW_H + +#include <linux/in6.h> +#include <asm/atomic.h> + +struct flowi { + int oif; + int iif; + __u32 mark; + + union { + struct { + __be32 daddr; + __be32 saddr; + __u8 tos; + __u8 scope; + } ip4_u; + + struct { + struct in6_addr daddr; + struct in6_addr saddr; + __be32 flowlabel; + } ip6_u; + + struct { + __le16 daddr; + __le16 saddr; + __u8 scope; + } dn_u; + } nl_u; +#define fld_dst nl_u.dn_u.daddr +#define fld_src nl_u.dn_u.saddr +#define fld_scope nl_u.dn_u.scope +#define fl6_dst nl_u.ip6_u.daddr +#define fl6_src nl_u.ip6_u.saddr +#define fl6_flowlabel nl_u.ip6_u.flowlabel +#define fl4_dst nl_u.ip4_u.daddr +#define fl4_src nl_u.ip4_u.saddr +#define fl4_tos nl_u.ip4_u.tos +#define fl4_scope nl_u.ip4_u.scope + + __u8 proto; + __u8 flags; +#define FLOWI_FLAG_ANYSRC 0x01 + union { + struct { + __be16 sport; + __be16 dport; + } ports; + + struct { + __u8 type; + __u8 code; + } icmpt; + + struct { + __le16 sport; + __le16 dport; + } dnports; + + __be32 spi; + + struct { + __u8 type; + } mht; + } uli_u; +#define fl_ip_sport uli_u.ports.sport +#define fl_ip_dport uli_u.ports.dport +#define fl_icmp_type uli_u.icmpt.type +#define fl_icmp_code uli_u.icmpt.code +#define fl_ipsec_spi uli_u.spi +#define fl_mh_type uli_u.mht.type + __u32 secid; /* used by xfrm; see secid.txt */ +} __attribute__((__aligned__(BITS_PER_LONG/8))); + +#define FLOW_DIR_IN 0 +#define FLOW_DIR_OUT 1 +#define FLOW_DIR_FWD 2 + +struct net; +struct sock; +struct flow_cache_ops; + +struct flow_cache_object { + const struct flow_cache_ops *ops; +}; + +struct flow_cache_ops { + struct flow_cache_object *(*get)(struct flow_cache_object *); + int (*check)(struct flow_cache_object *); + void (*delete)(struct flow_cache_object *); +}; + +typedef struct flow_cache_object *(*flow_resolve_t)( + struct net *net, struct flowi *key, u16 family, + u8 dir, struct flow_cache_object *oldobj, void *ctx); + +extern struct flow_cache_object *flow_cache_lookup( + struct net *net, struct flowi *key, u16 family, + u8 dir, flow_resolve_t resolver, void *ctx); + +extern void flow_cache_flush(void); +extern atomic_t flow_cache_genid; + +static inline int flow_cache_uli_match(struct flowi *fl1, struct flowi *fl2) +{ + return (fl1->proto == fl2->proto && + !memcmp(&fl1->uli_u, &fl2->uli_u, sizeof(fl1->uli_u))); +} + +#endif diff --git a/include/net/garp.h b/include/net/garp.h new file mode 100644 index 00000000..825f172c --- /dev/null +++ b/include/net/garp.h @@ -0,0 +1,128 @@ +#ifndef _NET_GARP_H +#define _NET_GARP_H + +#include <net/stp.h> + +#define GARP_PROTOCOL_ID 0x1 +#define GARP_END_MARK 0x0 + +struct garp_pdu_hdr { + __be16 protocol; +}; + +struct garp_msg_hdr { + u8 attrtype; +}; + +enum garp_attr_event { + GARP_LEAVE_ALL, + GARP_JOIN_EMPTY, + GARP_JOIN_IN, + GARP_LEAVE_EMPTY, + GARP_LEAVE_IN, + GARP_EMPTY, +}; + +struct garp_attr_hdr { + u8 len; + u8 event; + u8 data[]; +}; + +struct garp_skb_cb { + u8 cur_type; +}; + +static inline struct garp_skb_cb *garp_cb(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(struct garp_skb_cb) > + FIELD_SIZEOF(struct sk_buff, cb)); + return (struct garp_skb_cb *)skb->cb; +} + +enum garp_applicant_state { + GARP_APPLICANT_INVALID, + GARP_APPLICANT_VA, + GARP_APPLICANT_AA, + GARP_APPLICANT_QA, + GARP_APPLICANT_LA, + GARP_APPLICANT_VP, + GARP_APPLICANT_AP, + GARP_APPLICANT_QP, + GARP_APPLICANT_VO, + GARP_APPLICANT_AO, + GARP_APPLICANT_QO, + __GARP_APPLICANT_MAX +}; +#define GARP_APPLICANT_MAX (__GARP_APPLICANT_MAX - 1) + +enum garp_event { + GARP_EVENT_REQ_JOIN, + GARP_EVENT_REQ_LEAVE, + GARP_EVENT_R_JOIN_IN, + GARP_EVENT_R_JOIN_EMPTY, + GARP_EVENT_R_EMPTY, + GARP_EVENT_R_LEAVE_IN, + GARP_EVENT_R_LEAVE_EMPTY, + GARP_EVENT_TRANSMIT_PDU, + __GARP_EVENT_MAX +}; +#define GARP_EVENT_MAX (__GARP_EVENT_MAX - 1) + +enum garp_action { + GARP_ACTION_NONE, + GARP_ACTION_S_JOIN_IN, + GARP_ACTION_S_LEAVE_EMPTY, +}; + +struct garp_attr { + struct rb_node node; + enum garp_applicant_state state; + u8 type; + u8 dlen; + unsigned char data[]; +}; + +enum garp_applications { + GARP_APPLICATION_GVRP, + __GARP_APPLICATION_MAX +}; +#define GARP_APPLICATION_MAX (__GARP_APPLICATION_MAX - 1) + +struct garp_application { + enum garp_applications type; + unsigned int maxattr; + struct stp_proto proto; +}; + +struct garp_applicant { + struct garp_application *app; + struct net_device *dev; + struct timer_list join_timer; + + spinlock_t lock; + struct sk_buff_head queue; + struct sk_buff *pdu; + struct rb_root gid; +}; + +struct garp_port { + struct garp_applicant *applicants[GARP_APPLICATION_MAX + 1]; +}; + +extern int garp_register_application(struct garp_application *app); +extern void garp_unregister_application(struct garp_application *app); + +extern int garp_init_applicant(struct net_device *dev, + struct garp_application *app); +extern void garp_uninit_applicant(struct net_device *dev, + struct garp_application *app); + +extern int garp_request_join(const struct net_device *dev, + const struct garp_application *app, + const void *data, u8 len, u8 type); +extern void garp_request_leave(const struct net_device *dev, + const struct garp_application *app, + const void *data, u8 len, u8 type); + +#endif /* _NET_GARP_H */ diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h new file mode 100644 index 00000000..fa157712 --- /dev/null +++ b/include/net/gen_stats.h @@ -0,0 +1,50 @@ +#ifndef __NET_GEN_STATS_H +#define __NET_GEN_STATS_H + +#include <linux/gen_stats.h> +#include <linux/socket.h> +#include <linux/rtnetlink.h> +#include <linux/pkt_sched.h> + +struct gnet_dump { + spinlock_t * lock; + struct sk_buff * skb; + struct nlattr * tail; + + /* Backward compatability */ + int compat_tc_stats; + int compat_xstats; + void * xstats; + int xstats_len; + struct tc_stats tc_stats; +}; + +extern int gnet_stats_start_copy(struct sk_buff *skb, int type, + spinlock_t *lock, struct gnet_dump *d); + +extern int gnet_stats_start_copy_compat(struct sk_buff *skb, int type, + int tc_stats_type,int xstats_type, + spinlock_t *lock, struct gnet_dump *d); + +extern int gnet_stats_copy_basic(struct gnet_dump *d, + struct gnet_stats_basic_packed *b); +extern int gnet_stats_copy_rate_est(struct gnet_dump *d, + const struct gnet_stats_basic_packed *b, + struct gnet_stats_rate_est *r); +extern int gnet_stats_copy_queue(struct gnet_dump *d, + struct gnet_stats_queue *q); +extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len); + +extern int gnet_stats_finish_copy(struct gnet_dump *d); + +extern int gen_new_estimator(struct gnet_stats_basic_packed *bstats, + struct gnet_stats_rate_est *rate_est, + spinlock_t *stats_lock, struct nlattr *opt); +extern void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, + struct gnet_stats_rate_est *rate_est); +extern int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, + struct gnet_stats_rate_est *rate_est, + spinlock_t *stats_lock, struct nlattr *opt); +extern bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, + const struct gnet_stats_rate_est *rate_est); +#endif diff --git a/include/net/genetlink.h b/include/net/genetlink.h new file mode 100644 index 00000000..f7dcd2c7 --- /dev/null +++ b/include/net/genetlink.h @@ -0,0 +1,291 @@ +#ifndef __NET_GENERIC_NETLINK_H +#define __NET_GENERIC_NETLINK_H + +#include <linux/genetlink.h> +#include <net/netlink.h> +#include <net/net_namespace.h> + +/** + * struct genl_multicast_group - generic netlink multicast group + * @name: name of the multicast group, names are per-family + * @id: multicast group ID, assigned by the core, to use with + * genlmsg_multicast(). + * @list: list entry for linking + * @family: pointer to family, need not be set before registering + */ +struct genl_multicast_group { + struct genl_family *family; /* private */ + struct list_head list; /* private */ + char name[GENL_NAMSIZ]; + u32 id; +}; + +/** + * struct genl_family - generic netlink family + * @id: protocol family idenfitier + * @hdrsize: length of user specific header in bytes + * @name: name of family + * @version: protocol version + * @maxattr: maximum number of attributes supported + * @netnsok: set to true if the family can handle network + * namespaces and should be presented in all of them + * @attrbuf: buffer to store parsed attributes + * @ops_list: list of all assigned operations + * @family_list: family list + * @mcast_groups: multicast groups list + */ +struct genl_family { + unsigned int id; + unsigned int hdrsize; + char name[GENL_NAMSIZ]; + unsigned int version; + unsigned int maxattr; + bool netnsok; + struct nlattr ** attrbuf; /* private */ + struct list_head ops_list; /* private */ + struct list_head family_list; /* private */ + struct list_head mcast_groups; /* private */ +}; + +/** + * struct genl_info - receiving information + * @snd_seq: sending sequence number + * @snd_pid: netlink pid of sender + * @nlhdr: netlink message header + * @genlhdr: generic netlink message header + * @userhdr: user specific header + * @attrs: netlink attributes + */ +struct genl_info { + u32 snd_seq; + u32 snd_pid; + struct nlmsghdr * nlhdr; + struct genlmsghdr * genlhdr; + void * userhdr; + struct nlattr ** attrs; +#ifdef CONFIG_NET_NS + struct net * _net; +#endif +}; + +static inline struct net *genl_info_net(struct genl_info *info) +{ + return read_pnet(&info->_net); +} + +static inline void genl_info_net_set(struct genl_info *info, struct net *net) +{ + write_pnet(&info->_net, net); +} + +/** + * struct genl_ops - generic netlink operations + * @cmd: command identifier + * @flags: flags + * @policy: attribute validation policy + * @doit: standard command callback + * @dumpit: callback for dumpers + * @done: completion callback for dumps + * @ops_list: operations list + */ +struct genl_ops { + u8 cmd; + unsigned int flags; + const struct nla_policy *policy; + int (*doit)(struct sk_buff *skb, + struct genl_info *info); + int (*dumpit)(struct sk_buff *skb, + struct netlink_callback *cb); + int (*done)(struct netlink_callback *cb); + struct list_head ops_list; +}; + +extern int genl_register_family(struct genl_family *family); +extern int genl_register_family_with_ops(struct genl_family *family, + struct genl_ops *ops, size_t n_ops); +extern int genl_unregister_family(struct genl_family *family); +extern int genl_register_ops(struct genl_family *, struct genl_ops *ops); +extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); +extern int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp); +extern void genl_unregister_mc_group(struct genl_family *family, + struct genl_multicast_group *grp); + +/** + * genlmsg_put - Add generic netlink header to netlink message + * @skb: socket buffer holding the message + * @pid: netlink pid the message is addressed to + * @seq: sequence number (usually the one of the sender) + * @family: generic netlink family + * @flags netlink message flags + * @cmd: generic netlink command + * + * Returns pointer to user specific header + */ +static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, + struct genl_family *family, int flags, u8 cmd) +{ + struct nlmsghdr *nlh; + struct genlmsghdr *hdr; + + nlh = nlmsg_put(skb, pid, seq, family->id, GENL_HDRLEN + + family->hdrsize, flags); + if (nlh == NULL) + return NULL; + + hdr = nlmsg_data(nlh); + hdr->cmd = cmd; + hdr->version = family->version; + hdr->reserved = 0; + + return (char *) hdr + GENL_HDRLEN; +} + +/** + * genlmsg_put_reply - Add generic netlink header to a reply message + * @skb: socket buffer holding the message + * @info: receiver info + * @family: generic netlink family + * @flags: netlink message flags + * @cmd: generic netlink command + * + * Returns pointer to user specific header + */ +static inline void *genlmsg_put_reply(struct sk_buff *skb, + struct genl_info *info, + struct genl_family *family, + int flags, u8 cmd) +{ + return genlmsg_put(skb, info->snd_pid, info->snd_seq, family, + flags, cmd); +} + +/** + * genlmsg_end - Finalize a generic netlink message + * @skb: socket buffer the message is stored in + * @hdr: user specific header + */ +static inline int genlmsg_end(struct sk_buff *skb, void *hdr) +{ + return nlmsg_end(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN); +} + +/** + * genlmsg_cancel - Cancel construction of a generic netlink message + * @skb: socket buffer the message is stored in + * @hdr: generic netlink message header + */ +static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) +{ + nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN); +} + +/** + * genlmsg_multicast_netns - multicast a netlink message to a specific netns + * @net: the net namespace + * @skb: netlink message as socket buffer + * @pid: own netlink pid to avoid sending to yourself + * @group: multicast group id + * @flags: allocation flags + */ +static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb, + u32 pid, unsigned int group, gfp_t flags) +{ + return nlmsg_multicast(net->genl_sock, skb, pid, group, flags); +} + +/** + * genlmsg_multicast - multicast a netlink message to the default netns + * @skb: netlink message as socket buffer + * @pid: own netlink pid to avoid sending to yourself + * @group: multicast group id + * @flags: allocation flags + */ +static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid, + unsigned int group, gfp_t flags) +{ + return genlmsg_multicast_netns(&init_net, skb, pid, group, flags); +} + +/** + * genlmsg_multicast_allns - multicast a netlink message to all net namespaces + * @skb: netlink message as socket buffer + * @pid: own netlink pid to avoid sending to yourself + * @group: multicast group id + * @flags: allocation flags + * + * This function must hold the RTNL or rcu_read_lock(). + */ +int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid, + unsigned int group, gfp_t flags); + +/** + * genlmsg_unicast - unicast a netlink message + * @skb: netlink message as socket buffer + * @pid: netlink pid of the destination socket + */ +static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 pid) +{ + return nlmsg_unicast(net->genl_sock, skb, pid); +} + +/** + * genlmsg_reply - reply to a request + * @skb: netlink message to be sent back + * @info: receiver information + */ +static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info) +{ + return genlmsg_unicast(genl_info_net(info), skb, info->snd_pid); +} + +/** + * gennlmsg_data - head of message payload + * @gnlh: genetlink messsage header + */ +static inline void *genlmsg_data(const struct genlmsghdr *gnlh) +{ + return ((unsigned char *) gnlh + GENL_HDRLEN); +} + +/** + * genlmsg_len - length of message payload + * @gnlh: genetlink message header + */ +static inline int genlmsg_len(const struct genlmsghdr *gnlh) +{ + struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh - + NLMSG_HDRLEN); + return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); +} + +/** + * genlmsg_msg_size - length of genetlink message not including padding + * @payload: length of message payload + */ +static inline int genlmsg_msg_size(int payload) +{ + return GENL_HDRLEN + payload; +} + +/** + * genlmsg_total_size - length of genetlink message including padding + * @payload: length of message payload + */ +static inline int genlmsg_total_size(int payload) +{ + return NLMSG_ALIGN(genlmsg_msg_size(payload)); +} + +/** + * genlmsg_new - Allocate a new generic netlink message + * @payload: size of the message payload + * @flags: the type of memory to allocate. + */ +static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) +{ + return nlmsg_new(genlmsg_total_size(payload), flags); +} + + +#endif /* __NET_GENERIC_NETLINK_H */ diff --git a/include/net/icmp.h b/include/net/icmp.h new file mode 100644 index 00000000..6e991e0d --- /dev/null +++ b/include/net/icmp.h @@ -0,0 +1,51 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the ICMP module. + * + * Version: @(#)icmp.h 1.0.4 05/13/93 + * + * Authors: Ross Biro + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _ICMP_H +#define _ICMP_H + +#include <linux/icmp.h> + +#include <net/inet_sock.h> +#include <net/snmp.h> + +struct icmp_err { + int errno; + unsigned fatal:1; +}; + +extern const struct icmp_err icmp_err_convert[]; +#define ICMP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmp_statistics, field) +#define ICMP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.icmp_statistics, field) +#define ICMPMSGOUT_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmpmsg_statistics, field+256) +#define ICMPMSGIN_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.icmpmsg_statistics, field) + +struct dst_entry; +struct net_proto_family; +struct sk_buff; +struct net; + +extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info); +extern int icmp_rcv(struct sk_buff *skb); +extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); +extern int icmp_init(void); +extern void icmp_out_count(struct net *net, unsigned char type); + +/* Move into dst.h ? */ +extern int xrlim_allow(struct dst_entry *dst, int timeout); + +#endif /* _ICMP_H */ diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h new file mode 100644 index 00000000..af49f8ab --- /dev/null +++ b/include/net/ieee80211_radiotap.h @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2003, 2004 David Young. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of David Young may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID + * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* + * Modifications to fit into the linux IEEE 802.11 stack, + * Mike Kershaw (dragorn@kismetwireless.net) + */ + +#ifndef IEEE80211RADIOTAP_H +#define IEEE80211RADIOTAP_H + +#include <linux/if_ether.h> +#include <linux/kernel.h> +#include <asm/unaligned.h> + +/* Base version of the radiotap packet header data */ +#define PKTHDR_RADIOTAP_VERSION 0 + +/* A generic radio capture format is desirable. There is one for + * Linux, but it is neither rigidly defined (there were not even + * units given for some fields) nor easily extensible. + * + * I suggest the following extensible radio capture format. It is + * based on a bitmap indicating which fields are present. + * + * I am trying to describe precisely what the application programmer + * should expect in the following, and for that reason I tell the + * units and origin of each measurement (where it applies), or else I + * use sufficiently weaselly language ("is a monotonically nondecreasing + * function of...") that I cannot set false expectations for lawyerly + * readers. + */ + +/* + * The radio capture header precedes the 802.11 header. + * All data in the header is little endian on all platforms. + */ +struct ieee80211_radiotap_header { + u8 it_version; /* Version 0. Only increases + * for drastic changes, + * introduction of compatible + * new fields does not count. + */ + u8 it_pad; + __le16 it_len; /* length of the whole + * header in bytes, including + * it_version, it_pad, + * it_len, and data fields. + */ + __le32 it_present; /* A bitmap telling which + * fields are present. Set bit 31 + * (0x80000000) to extend the + * bitmap by another 32 bits. + * Additional extensions are made + * by setting bit 31. + */ +} __packed; + +/* Name Data type Units + * ---- --------- ----- + * + * IEEE80211_RADIOTAP_TSFT __le64 microseconds + * + * Value in microseconds of the MAC's 64-bit 802.11 Time + * Synchronization Function timer when the first bit of the + * MPDU arrived at the MAC. For received frames, only. + * + * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap + * + * Tx/Rx frequency in MHz, followed by flags (see below). + * + * IEEE80211_RADIOTAP_FHSS __le16 see below + * + * For frequency-hopping radios, the hop set (first byte) + * and pattern (second byte). + * + * IEEE80211_RADIOTAP_RATE u8 500kb/s + * + * Tx/Rx data rate + * + * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from + * one milliwatt (dBm) + * + * RF signal power at the antenna, decibel difference from + * one milliwatt. + * + * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from + * one milliwatt (dBm) + * + * RF noise power at the antenna, decibel difference from one + * milliwatt. + * + * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) + * + * RF signal power at the antenna, decibel difference from an + * arbitrary, fixed reference. + * + * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) + * + * RF noise power at the antenna, decibel difference from an + * arbitrary, fixed reference point. + * + * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless + * + * Quality of Barker code lock. Unitless. Monotonically + * nondecreasing with "better" lock strength. Called "Signal + * Quality" in datasheets. (Is there a standard way to measure + * this?) + * + * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless + * + * Transmit power expressed as unitless distance from max + * power set at factory calibration. 0 is max power. + * Monotonically nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB) + * + * Transmit power expressed as decibel distance from max power + * set at factory calibration. 0 is max power. Monotonically + * nondecreasing with lower power levels. + * + * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from + * one milliwatt (dBm) + * + * Transmit power expressed as dBm (decibels from a 1 milliwatt + * reference). This is the absolute power level measured at + * the antenna port. + * + * IEEE80211_RADIOTAP_FLAGS u8 bitmap + * + * Properties of transmitted and received frames. See flags + * defined below. + * + * IEEE80211_RADIOTAP_ANTENNA u8 antenna index + * + * Unitless indication of the Rx/Tx antenna for this packet. + * The first antenna is antenna 0. + * + * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap + * + * Properties of received frames. See flags defined below. + * + * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap + * + * Properties of transmitted frames. See flags defined below. + * + * IEEE80211_RADIOTAP_RTS_RETRIES u8 data + * + * Number of rts retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_DATA_RETRIES u8 data + * + * Number of unicast retries a transmitted frame used. + * + */ +enum ieee80211_radiotap_type { + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + IEEE80211_RADIOTAP_ANTENNA = 11, + IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + + /* valid in every it_present bitmap, even vendor namespaces */ + IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, + IEEE80211_RADIOTAP_EXT = 31 +}; + +/* Channel flags. */ +#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ + +/* For IEEE80211_RADIOTAP_FLAGS */ +#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received + * during CFP + */ +#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received + * with short + * preamble + */ +#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received + * with WEP encryption + */ +#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received + * with fragmentation + */ +#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ +#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between + * 802.11 header and payload + * (to 32-bit boundary) + */ +#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* bad FCS */ + +/* For IEEE80211_RADIOTAP_RX_FLAGS */ +#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* frame has bad PLCP */ + +/* For IEEE80211_RADIOTAP_TX_FLAGS */ +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive + * retries */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ + +/* Ugly macro to convert literal channel numbers into their mhz equivalents + * There are certianly some conditions that will break this (like feeding it '30') + * but they shouldn't arise since nothing talks on channel 30. */ +#define ieee80211chan2mhz(x) \ + (((x) <= 14) ? \ + (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \ + ((x) + 1000) * 5) + +/* helpers */ +static inline int ieee80211_get_radiotap_len(unsigned char *data) +{ + struct ieee80211_radiotap_header *hdr = + (struct ieee80211_radiotap_header *)data; + + return get_unaligned_le16(&hdr->it_len); +} + +#endif /* IEEE80211_RADIOTAP_H */ diff --git a/include/net/ieee802154.h b/include/net/ieee802154.h new file mode 100644 index 00000000..d52685de --- /dev/null +++ b/include/net/ieee802154.h @@ -0,0 +1,160 @@ +/* + * IEEE802.15.4-2003 specification + * + * Copyright (C) 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Pavel Smolenskiy <pavel.smolenskiy@gmail.com> + * Maxim Gorbachyov <maxim.gorbachev@siemens.com> + * Maxim Osipov <maxim.osipov@siemens.com> + * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> + */ + +#ifndef NET_IEEE802154_H +#define NET_IEEE802154_H + +#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */ +#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */ +#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */ +#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */ + +#define IEEE802154_FC_TYPE_SHIFT 0 +#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1) +#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT) +#define IEEE802154_FC_SET_TYPE(v, x) do { \ + v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \ + (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \ + } while (0) + +#define IEEE802154_FC_SECEN (1 << 3) +#define IEEE802154_FC_FRPEND (1 << 4) +#define IEEE802154_FC_ACK_REQ (1 << 5) +#define IEEE802154_FC_INTRA_PAN (1 << 6) + +#define IEEE802154_FC_SAMODE_SHIFT 14 +#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT) +#define IEEE802154_FC_DAMODE_SHIFT 10 +#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT) + +#define IEEE802154_FC_SAMODE(x) \ + (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT) + +#define IEEE802154_FC_DAMODE(x) \ + (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT) + + +/* MAC's Command Frames Identifiers */ +#define IEEE802154_CMD_ASSOCIATION_REQ 0x01 +#define IEEE802154_CMD_ASSOCIATION_RESP 0x02 +#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03 +#define IEEE802154_CMD_DATA_REQ 0x04 +#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05 +#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06 +#define IEEE802154_CMD_BEACON_REQ 0x07 +#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08 +#define IEEE802154_CMD_GTS_REQ 0x09 + +/* + * The return values of MAC operations + */ +enum { + /* + * The requested operation was completed successfully. + * For a transmission request, this value indicates + * a successful transmission. + */ + IEEE802154_SUCCESS = 0x0, + + /* The beacon was lost following a synchronization request. */ + IEEE802154_BEACON_LOSS = 0xe0, + /* + * A transmission could not take place due to activity on the + * channel, i.e., the CSMA-CA mechanism has failed. + */ + IEEE802154_CHNL_ACCESS_FAIL = 0xe1, + /* The GTS request has been denied by the PAN coordinator. */ + IEEE802154_DENINED = 0xe2, + /* The attempt to disable the transceiver has failed. */ + IEEE802154_DISABLE_TRX_FAIL = 0xe3, + /* + * The received frame induces a failed security check according to + * the security suite. + */ + IEEE802154_FAILED_SECURITY_CHECK = 0xe4, + /* + * The frame resulting from secure processing has a length that is + * greater than aMACMaxFrameSize. + */ + IEEE802154_FRAME_TOO_LONG = 0xe5, + /* + * The requested GTS transmission failed because the specified GTS + * either did not have a transmit GTS direction or was not defined. + */ + IEEE802154_INVALID_GTS = 0xe6, + /* + * A request to purge an MSDU from the transaction queue was made using + * an MSDU handle that was not found in the transaction table. + */ + IEEE802154_INVALID_HANDLE = 0xe7, + /* A parameter in the primitive is out of the valid range.*/ + IEEE802154_INVALID_PARAMETER = 0xe8, + /* No acknowledgment was received after aMaxFrameRetries. */ + IEEE802154_NO_ACK = 0xe9, + /* A scan operation failed to find any network beacons.*/ + IEEE802154_NO_BEACON = 0xea, + /* No response data were available following a request. */ + IEEE802154_NO_DATA = 0xeb, + /* The operation failed because a short address was not allocated. */ + IEEE802154_NO_SHORT_ADDRESS = 0xec, + /* + * A receiver enable request was unsuccessful because it could not be + * completed within the CAP. + */ + IEEE802154_OUT_OF_CAP = 0xed, + /* + * A PAN identifier conflict has been detected and communicated to the + * PAN coordinator. + */ + IEEE802154_PANID_CONFLICT = 0xee, + /* A coordinator realignment command has been received. */ + IEEE802154_REALIGMENT = 0xef, + /* The transaction has expired and its information discarded. */ + IEEE802154_TRANSACTION_EXPIRED = 0xf0, + /* There is no capacity to store the transaction. */ + IEEE802154_TRANSACTION_OVERFLOW = 0xf1, + /* + * The transceiver was in the transmitter enabled state when the + * receiver was requested to be enabled. + */ + IEEE802154_TX_ACTIVE = 0xf2, + /* The appropriate key is not available in the ACL. */ + IEEE802154_UNAVAILABLE_KEY = 0xf3, + /* + * A SET/GET request was issued with the identifier of a PIB attribute + * that is not supported. + */ + IEEE802154_UNSUPPORTED_ATTR = 0xf4, + /* + * A request to perform a scan operation failed because the MLME was + * in the process of performing a previously initiated scan operation. + */ + IEEE802154_SCAN_IN_PROGRESS = 0xfc, +}; + + +#endif + + diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h new file mode 100644 index 00000000..57430555 --- /dev/null +++ b/include/net/ieee802154_netdev.h @@ -0,0 +1,121 @@ +/* + * An interface between IEEE802.15.4 device and rest of the kernel. + * + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Pavel Smolenskiy <pavel.smolenskiy@gmail.com> + * Maxim Gorbachyov <maxim.gorbachev@siemens.com> + * Maxim Osipov <maxim.osipov@siemens.com> + * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> + */ + +#ifndef IEEE802154_NETDEVICE_H +#define IEEE802154_NETDEVICE_H + +/* + * A control block of skb passed between the ARPHRD_IEEE802154 device + * and other stack parts. + */ +struct ieee802154_mac_cb { + u8 lqi; + struct ieee802154_addr sa; + struct ieee802154_addr da; + u8 flags; + u8 seq; +}; + +static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb) +{ + return (struct ieee802154_mac_cb *)skb->cb; +} + +#define MAC_CB_FLAG_TYPEMASK ((1 << 3) - 1) + +#define MAC_CB_FLAG_ACKREQ (1 << 3) +#define MAC_CB_FLAG_SECEN (1 << 4) +#define MAC_CB_FLAG_INTRAPAN (1 << 5) + +static inline int mac_cb_is_ackreq(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ; +} + +static inline int mac_cb_is_secen(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN; +} + +static inline int mac_cb_is_intrapan(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN; +} + +static inline int mac_cb_type(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK; +} + +#define IEEE802154_MAC_SCAN_ED 0 +#define IEEE802154_MAC_SCAN_ACTIVE 1 +#define IEEE802154_MAC_SCAN_PASSIVE 2 +#define IEEE802154_MAC_SCAN_ORPHAN 3 + +struct wpan_phy; +/* + * This should be located at net_device->ml_priv + * + * get_phy should increment the reference counting on returned phy. + * Use wpan_wpy_put to put that reference. + */ +struct ieee802154_mlme_ops { + int (*assoc_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 channel, u8 page, u8 cap); + int (*assoc_resp)(struct net_device *dev, + struct ieee802154_addr *addr, + u16 short_addr, u8 status); + int (*disassoc_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 reason); + int (*start_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, + u8 pan_coord, u8 blx, u8 coord_realign); + int (*scan_req)(struct net_device *dev, + u8 type, u32 channels, u8 page, u8 duration); + + struct wpan_phy *(*get_phy)(const struct net_device *dev); + + /* + * FIXME: these should become the part of PIB/MIB interface. + * However we still don't have IB interface of any kind + */ + u16 (*get_pan_id)(const struct net_device *dev); + u16 (*get_short_addr)(const struct net_device *dev); + u8 (*get_dsn)(const struct net_device *dev); + u8 (*get_bsn)(const struct net_device *dev); +}; + +static inline struct ieee802154_mlme_ops *ieee802154_mlme_ops( + const struct net_device *dev) +{ + return dev->ml_priv; +} + +#endif + + diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h new file mode 100644 index 00000000..f95ff8d9 --- /dev/null +++ b/include/net/if_inet6.h @@ -0,0 +1,289 @@ +/* + * inet6 interface/address list definitions + * Linux INET6 implementation + * + * Authors: + * Pedro Roque <roque@di.fc.ul.pt> + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _NET_IF_INET6_H +#define _NET_IF_INET6_H + +#include <net/snmp.h> +#include <linux/ipv6.h> + +/* inet6_dev.if_flags */ + +#define IF_RA_OTHERCONF 0x80 +#define IF_RA_MANAGED 0x40 +#define IF_RA_RCVD 0x20 +#define IF_RS_SENT 0x10 +#define IF_READY 0x80000000 + +/* prefix flags */ +#define IF_PREFIX_ONLINK 0x01 +#define IF_PREFIX_AUTOCONF 0x02 + +#ifdef __KERNEL__ + +enum { + INET6_IFADDR_STATE_DAD, + INET6_IFADDR_STATE_POSTDAD, + INET6_IFADDR_STATE_UP, + INET6_IFADDR_STATE_DEAD, +}; + +struct inet6_ifaddr { + struct in6_addr addr; + __u32 prefix_len; + + __u32 valid_lft; + __u32 prefered_lft; + atomic_t refcnt; + spinlock_t lock; + spinlock_t state_lock; + + int state; + + __u8 probes; + __u8 flags; + + __u16 scope; + + unsigned long cstamp; /* created timestamp */ + unsigned long tstamp; /* updated timestamp */ + + struct timer_list timer; + + struct inet6_dev *idev; + struct rt6_info *rt; + + struct hlist_node addr_lst; + struct list_head if_list; + +#ifdef CONFIG_IPV6_PRIVACY + struct list_head tmp_list; + struct inet6_ifaddr *ifpub; + int regen_count; +#endif + struct rcu_head rcu; +}; + +struct ip6_sf_socklist { + unsigned int sl_max; + unsigned int sl_count; + struct in6_addr sl_addr[0]; +}; + +#define IP6_SFLSIZE(count) (sizeof(struct ip6_sf_socklist) + \ + (count) * sizeof(struct in6_addr)) + +#define IP6_SFBLOCK 10 /* allocate this many at once */ + +struct ipv6_mc_socklist { + struct in6_addr addr; + int ifindex; + struct ipv6_mc_socklist *next; + rwlock_t sflock; + unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */ + struct ip6_sf_socklist *sflist; +}; + +struct ip6_sf_list { + struct ip6_sf_list *sf_next; + struct in6_addr sf_addr; + unsigned long sf_count[2]; /* include/exclude counts */ + unsigned char sf_gsresp; /* include in g & s response? */ + unsigned char sf_oldin; /* change state */ + unsigned char sf_crcount; /* retrans. left to send */ +}; + +#define MAF_TIMER_RUNNING 0x01 +#define MAF_LAST_REPORTER 0x02 +#define MAF_LOADED 0x04 +#define MAF_NOREPORT 0x08 +#define MAF_GSQUERY 0x10 + +struct ifmcaddr6 { + struct in6_addr mca_addr; + struct inet6_dev *idev; + struct ifmcaddr6 *next; + struct ip6_sf_list *mca_sources; + struct ip6_sf_list *mca_tomb; + unsigned int mca_sfmode; + unsigned char mca_crcount; + unsigned long mca_sfcount[2]; + struct timer_list mca_timer; + unsigned mca_flags; + int mca_users; + atomic_t mca_refcnt; + spinlock_t mca_lock; + unsigned long mca_cstamp; + unsigned long mca_tstamp; +}; + +/* Anycast stuff */ + +struct ipv6_ac_socklist { + struct in6_addr acl_addr; + int acl_ifindex; + struct ipv6_ac_socklist *acl_next; +}; + +struct ifacaddr6 { + struct in6_addr aca_addr; + struct inet6_dev *aca_idev; + struct rt6_info *aca_rt; + struct ifacaddr6 *aca_next; + int aca_users; + atomic_t aca_refcnt; + spinlock_t aca_lock; + unsigned long aca_cstamp; + unsigned long aca_tstamp; +}; + +#define IFA_HOST IPV6_ADDR_LOOPBACK +#define IFA_LINK IPV6_ADDR_LINKLOCAL +#define IFA_SITE IPV6_ADDR_SITELOCAL + +struct ipv6_devstat { + struct proc_dir_entry *proc_dir_entry; + DEFINE_SNMP_STAT(struct ipstats_mib, ipv6); + DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6); + DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg); +}; + +struct inet6_dev { + struct net_device *dev; + + struct list_head addr_list; + + struct ifmcaddr6 *mc_list; + struct ifmcaddr6 *mc_tomb; + spinlock_t mc_lock; + unsigned char mc_qrv; + unsigned char mc_gq_running; + unsigned char mc_ifc_count; + unsigned long mc_v1_seen; + unsigned long mc_maxdelay; + struct timer_list mc_gq_timer; /* general query timer */ + struct timer_list mc_ifc_timer; /* interface change timer */ + + struct ifacaddr6 *ac_list; + rwlock_t lock; + atomic_t refcnt; + __u32 if_flags; + int dead; + +#ifdef CONFIG_IPV6_PRIVACY + u8 rndid[8]; + struct timer_list regen_timer; + struct list_head tempaddr_list; +#endif + + struct neigh_parms *nd_parms; + struct inet6_dev *next; + struct ipv6_devconf cnf; + struct ipv6_devstat stats; + unsigned long tstamp; /* ipv6InterfaceTable update timestamp */ + struct rcu_head rcu; +}; + +static inline void ipv6_eth_mc_map(struct in6_addr *addr, char *buf) +{ + /* + * +-------+-------+-------+-------+-------+-------+ + * | 33 | 33 | DST13 | DST14 | DST15 | DST16 | + * +-------+-------+-------+-------+-------+-------+ + */ + + buf[0]= 0x33; + buf[1]= 0x33; + + memcpy(buf + 2, &addr->s6_addr32[3], sizeof(__u32)); +} + +static inline void ipv6_tr_mc_map(struct in6_addr *addr, char *buf) +{ + /* All nodes FF01::1, FF02::1, FF02::1:FFxx:xxxx */ + + if (((addr->s6_addr[0] == 0xFF) && + ((addr->s6_addr[1] == 0x01) || (addr->s6_addr[1] == 0x02)) && + (addr->s6_addr16[1] == 0) && + (addr->s6_addr32[1] == 0) && + (addr->s6_addr32[2] == 0) && + (addr->s6_addr16[6] == 0) && + (addr->s6_addr[15] == 1)) || + ((addr->s6_addr[0] == 0xFF) && + (addr->s6_addr[1] == 0x02) && + (addr->s6_addr16[1] == 0) && + (addr->s6_addr32[1] == 0) && + (addr->s6_addr16[4] == 0) && + (addr->s6_addr[10] == 0) && + (addr->s6_addr[11] == 1) && + (addr->s6_addr[12] == 0xff))) + { + buf[0]=0xC0; + buf[1]=0x00; + buf[2]=0x01; + buf[3]=0x00; + buf[4]=0x00; + buf[5]=0x00; + /* All routers FF0x::2 */ + } else if ((addr->s6_addr[0] ==0xff) && + ((addr->s6_addr[1] & 0xF0) == 0) && + (addr->s6_addr16[1] == 0) && + (addr->s6_addr32[1] == 0) && + (addr->s6_addr32[2] == 0) && + (addr->s6_addr16[6] == 0) && + (addr->s6_addr[15] == 2)) + { + buf[0]=0xC0; + buf[1]=0x00; + buf[2]=0x02; + buf[3]=0x00; + buf[4]=0x00; + buf[5]=0x00; + } else { + unsigned char i ; + + i = addr->s6_addr[15] & 7 ; + buf[0]=0xC0; + buf[1]=0x00; + buf[2]=0x00; + buf[3]=0x01 << i ; + buf[4]=0x00; + buf[5]=0x00; + } +} + +static inline void ipv6_arcnet_mc_map(const struct in6_addr *addr, char *buf) +{ + buf[0] = 0x00; +} + +static inline void ipv6_ib_mc_map(const struct in6_addr *addr, + const unsigned char *broadcast, char *buf) +{ + unsigned char scope = broadcast[5] & 0xF; + + buf[0] = 0; /* Reserved */ + buf[1] = 0xff; /* Multicast QPN */ + buf[2] = 0xff; + buf[3] = 0xff; + buf[4] = 0xff; + buf[5] = 0x10 | scope; /* scope from broadcast address */ + buf[6] = 0x60; /* IPv6 signature */ + buf[7] = 0x1b; + buf[8] = broadcast[8]; /* P_Key */ + buf[9] = broadcast[9]; + memcpy(buf + 10, addr->s6_addr + 6, 10); +} +#endif +#endif diff --git a/include/net/inet6_connection_sock.h b/include/net/inet6_connection_sock.h new file mode 100644 index 00000000..aae08f68 --- /dev/null +++ b/include/net/inet6_connection_sock.h @@ -0,0 +1,42 @@ +/* + * NET Generic infrastructure for INET6 connection oriented protocols. + * + * Authors: Many people, see the TCPv6 sources + * + * From code originally in TCPv6 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _INET6_CONNECTION_SOCK_H +#define _INET6_CONNECTION_SOCK_H + +#include <linux/types.h> + +struct in6_addr; +struct inet_bind_bucket; +struct request_sock; +struct sk_buff; +struct sock; +struct sockaddr; + +extern int inet6_csk_bind_conflict(const struct sock *sk, + const struct inet_bind_bucket *tb); + +extern struct request_sock *inet6_csk_search_req(const struct sock *sk, + struct request_sock ***prevp, + const __be16 rport, + const struct in6_addr *raddr, + const struct in6_addr *laddr, + const int iif); + +extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk, + struct request_sock *req, + const unsigned long timeout); + +extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); + +extern int inet6_csk_xmit(struct sk_buff *skb); +#endif /* _INET6_CONNECTION_SOCK_H */ diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h new file mode 100644 index 00000000..e46674d5 --- /dev/null +++ b/include/net/inet6_hashtables.h @@ -0,0 +1,114 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Authors: Lotsa people, from code originally in tcp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _INET6_HASHTABLES_H +#define _INET6_HASHTABLES_H + + +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +#include <linux/in6.h> +#include <linux/ipv6.h> +#include <linux/types.h> +#include <linux/jhash.h> + +#include <net/inet_sock.h> + +#include <net/ipv6.h> +#include <net/netns/hash.h> + +struct inet_hashinfo; + +/* I have no idea if this is a good hash for v6 or not. -DaveM */ +static inline unsigned int inet6_ehashfn(struct net *net, + const struct in6_addr *laddr, const u16 lport, + const struct in6_addr *faddr, const __be16 fport) +{ + u32 ports = (lport ^ (__force u16)fport); + + return jhash_3words((__force u32)laddr->s6_addr32[3], + (__force u32)faddr->s6_addr32[3], + ports, inet_ehash_secret + net_hash_mix(net)); +} + +static inline int inet6_sk_ehashfn(const struct sock *sk) +{ + const struct inet_sock *inet = inet_sk(sk); + const struct ipv6_pinfo *np = inet6_sk(sk); + const struct in6_addr *laddr = &np->rcv_saddr; + const struct in6_addr *faddr = &np->daddr; + const __u16 lport = inet->inet_num; + const __be16 fport = inet->inet_dport; + struct net *net = sock_net(sk); + + return inet6_ehashfn(net, laddr, lport, faddr, fport); +} + +extern int __inet6_hash(struct sock *sk, struct inet_timewait_sock *twp); + +/* + * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so + * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM + * + * The sockhash lock must be held as a reader here. + */ +extern struct sock *__inet6_lookup_established(struct net *net, + struct inet_hashinfo *hashinfo, + const struct in6_addr *saddr, + const __be16 sport, + const struct in6_addr *daddr, + const u16 hnum, + const int dif); + +extern struct sock *inet6_lookup_listener(struct net *net, + struct inet_hashinfo *hashinfo, + const struct in6_addr *daddr, + const unsigned short hnum, + const int dif); + +static inline struct sock *__inet6_lookup(struct net *net, + struct inet_hashinfo *hashinfo, + const struct in6_addr *saddr, + const __be16 sport, + const struct in6_addr *daddr, + const u16 hnum, + const int dif) +{ + struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr, + sport, daddr, hnum, dif); + if (sk) + return sk; + + return inet6_lookup_listener(net, hashinfo, daddr, hnum, dif); +} + +static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo, + struct sk_buff *skb, + const __be16 sport, + const __be16 dport) +{ + struct sock *sk; + + if (unlikely(sk = skb_steal_sock(skb))) + return sk; + else return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, + &ipv6_hdr(skb)->saddr, sport, + &ipv6_hdr(skb)->daddr, ntohs(dport), + inet6_iif(skb)); +} + +extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, + const struct in6_addr *saddr, const __be16 sport, + const struct in6_addr *daddr, const __be16 dport, + const int dif); +#endif /* defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) */ +#endif /* _INET6_HASHTABLES_H */ diff --git a/include/net/inet_common.h b/include/net/inet_common.h new file mode 100644 index 00000000..22fac989 --- /dev/null +++ b/include/net/inet_common.h @@ -0,0 +1,44 @@ +#ifndef _INET_COMMON_H +#define _INET_COMMON_H + +extern const struct proto_ops inet_stream_ops; +extern const struct proto_ops inet_dgram_ops; + +/* + * INET4 prototypes used by INET6 + */ + +struct msghdr; +struct sock; +struct sockaddr; +struct socket; + +extern int inet_release(struct socket *sock); +extern int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, + int addr_len, int flags); +extern int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, + int addr_len, int flags); +extern int inet_accept(struct socket *sock, struct socket *newsock, int flags); +extern int inet_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size); +extern ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, + size_t size, int flags); +extern int inet_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size, int flags); +extern int inet_shutdown(struct socket *sock, int how); +extern int inet_listen(struct socket *sock, int backlog); +extern void inet_sock_destruct(struct sock *sk); +extern int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); +extern int inet_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer); +extern int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +extern int inet_ctl_sock_create(struct sock **sk, unsigned short family, + unsigned short type, unsigned char protocol, + struct net *net); + +static inline void inet_ctl_sock_destroy(struct sock *sk) +{ + sk_release_kernel(sk); +} + +#endif diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h new file mode 100644 index 00000000..b6d3b55d --- /dev/null +++ b/include/net/inet_connection_sock.h @@ -0,0 +1,335 @@ +/* + * NET Generic infrastructure for INET connection oriented protocols. + * + * Definitions for inet_connection_sock + * + * Authors: Many people, see the TCP sources + * + * From code originally in TCP + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _INET_CONNECTION_SOCK_H +#define _INET_CONNECTION_SOCK_H + +#include <linux/compiler.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/poll.h> + +#include <net/inet_sock.h> +#include <net/request_sock.h> + +#define INET_CSK_DEBUG 1 + +/* Cancel timers, when they are not required. */ +#undef INET_CSK_CLEAR_TIMERS + +struct inet_bind_bucket; +struct tcp_congestion_ops; + +/* + * Pointers to address related TCP functions + * (i.e. things that depend on the address family) + */ +struct inet_connection_sock_af_ops { + int (*queue_xmit)(struct sk_buff *skb); + void (*send_check)(struct sock *sk, struct sk_buff *skb); + int (*rebuild_header)(struct sock *sk); + int (*conn_request)(struct sock *sk, struct sk_buff *skb); + struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb, + struct request_sock *req, + struct dst_entry *dst); + int (*remember_stamp)(struct sock *sk); + u16 net_header_len; + u16 sockaddr_len; + int (*setsockopt)(struct sock *sk, int level, int optname, + char __user *optval, unsigned int optlen); + int (*getsockopt)(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +#ifdef CONFIG_COMPAT + int (*compat_setsockopt)(struct sock *sk, + int level, int optname, + char __user *optval, unsigned int optlen); + int (*compat_getsockopt)(struct sock *sk, + int level, int optname, + char __user *optval, int __user *optlen); +#endif + void (*addr2sockaddr)(struct sock *sk, struct sockaddr *); + int (*bind_conflict)(const struct sock *sk, + const struct inet_bind_bucket *tb); +}; + +/** inet_connection_sock - INET connection oriented sock + * + * @icsk_accept_queue: FIFO of established children + * @icsk_bind_hash: Bind node + * @icsk_timeout: Timeout + * @icsk_retransmit_timer: Resend (no ack) + * @icsk_rto: Retransmit timeout + * @icsk_pmtu_cookie Last pmtu seen by socket + * @icsk_ca_ops Pluggable congestion control hook + * @icsk_af_ops Operations which are AF_INET{4,6} specific + * @icsk_ca_state: Congestion control state + * @icsk_retransmits: Number of unrecovered [RTO] timeouts + * @icsk_pending: Scheduled timer event + * @icsk_backoff: Backoff + * @icsk_syn_retries: Number of allowed SYN (or equivalent) retries + * @icsk_probes_out: unanswered 0 window probes + * @icsk_ext_hdr_len: Network protocol overhead (IP/IPv6 options) + * @icsk_ack: Delayed ACK control data + * @icsk_mtup; MTU probing control data + */ +struct inet_connection_sock { + /* inet_sock has to be the first member! */ + struct inet_sock icsk_inet; + struct request_sock_queue icsk_accept_queue; + struct inet_bind_bucket *icsk_bind_hash; + unsigned long icsk_timeout; + struct timer_list icsk_retransmit_timer; + struct timer_list icsk_delack_timer; + __u32 icsk_rto; + __u32 icsk_pmtu_cookie; + const struct tcp_congestion_ops *icsk_ca_ops; + const struct inet_connection_sock_af_ops *icsk_af_ops; + unsigned int (*icsk_sync_mss)(struct sock *sk, u32 pmtu); + __u8 icsk_ca_state; + __u8 icsk_retransmits; + __u8 icsk_pending; + __u8 icsk_backoff; + __u8 icsk_syn_retries; + __u8 icsk_probes_out; + __u16 icsk_ext_hdr_len; + struct { + __u8 pending; /* ACK is pending */ + __u8 quick; /* Scheduled number of quick acks */ + __u8 pingpong; /* The session is interactive */ + __u8 blocked; /* Delayed ACK was blocked by socket lock */ + __u32 ato; /* Predicted tick of soft clock */ + unsigned long timeout; /* Currently scheduled timeout */ + __u32 lrcvtime; /* timestamp of last received data packet */ + __u16 last_seg_size; /* Size of last incoming segment */ + __u16 rcv_mss; /* MSS used for delayed ACK decisions */ + } icsk_ack; + struct { + int enabled; + + /* Range of MTUs to search */ + int search_high; + int search_low; + + /* Information on the current probe. */ + int probe_size; + } icsk_mtup; + u32 icsk_ca_priv[16]; +#define ICSK_CA_PRIV_SIZE (16 * sizeof(u32)) +}; + +#define ICSK_TIME_RETRANS 1 /* Retransmit timer */ +#define ICSK_TIME_DACK 2 /* Delayed ack timer */ +#define ICSK_TIME_PROBE0 3 /* Zero window probe timer */ +#define ICSK_TIME_KEEPOPEN 4 /* Keepalive timer */ + +static inline struct inet_connection_sock *inet_csk(const struct sock *sk) +{ + return (struct inet_connection_sock *)sk; +} + +static inline void *inet_csk_ca(const struct sock *sk) +{ + return (void *)inet_csk(sk)->icsk_ca_priv; +} + +extern struct sock *inet_csk_clone(struct sock *sk, + const struct request_sock *req, + const gfp_t priority); + +enum inet_csk_ack_state_t { + ICSK_ACK_SCHED = 1, + ICSK_ACK_TIMER = 2, + ICSK_ACK_PUSHED = 4, + ICSK_ACK_PUSHED2 = 8 +}; + +extern void inet_csk_init_xmit_timers(struct sock *sk, + void (*retransmit_handler)(unsigned long), + void (*delack_handler)(unsigned long), + void (*keepalive_handler)(unsigned long)); +extern void inet_csk_clear_xmit_timers(struct sock *sk); + +static inline void inet_csk_schedule_ack(struct sock *sk) +{ + inet_csk(sk)->icsk_ack.pending |= ICSK_ACK_SCHED; +} + +static inline int inet_csk_ack_scheduled(const struct sock *sk) +{ + return inet_csk(sk)->icsk_ack.pending & ICSK_ACK_SCHED; +} + +static inline void inet_csk_delack_init(struct sock *sk) +{ + memset(&inet_csk(sk)->icsk_ack, 0, sizeof(inet_csk(sk)->icsk_ack)); +} + +extern void inet_csk_delete_keepalive_timer(struct sock *sk); +extern void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long timeout); + +#ifdef INET_CSK_DEBUG +extern const char inet_csk_timer_bug_msg[]; +#endif + +static inline void inet_csk_clear_xmit_timer(struct sock *sk, const int what) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + + if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0) { + icsk->icsk_pending = 0; +#ifdef INET_CSK_CLEAR_TIMERS + sk_stop_timer(sk, &icsk->icsk_retransmit_timer); +#endif + } else if (what == ICSK_TIME_DACK) { + icsk->icsk_ack.blocked = icsk->icsk_ack.pending = 0; +#ifdef INET_CSK_CLEAR_TIMERS + sk_stop_timer(sk, &icsk->icsk_delack_timer); +#endif + } +#ifdef INET_CSK_DEBUG + else { + pr_debug("%s", inet_csk_timer_bug_msg); + } +#endif +} + +/* + * Reset the retransmission timer + */ +static inline void inet_csk_reset_xmit_timer(struct sock *sk, const int what, + unsigned long when, + const unsigned long max_when) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + + if (when > max_when) { +#ifdef INET_CSK_DEBUG + pr_debug("reset_xmit_timer: sk=%p %d when=0x%lx, caller=%p\n", + sk, what, when, current_text_addr()); +#endif + when = max_when; + } + + if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0) { + icsk->icsk_pending = what; + icsk->icsk_timeout = jiffies + when; + sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout); + } else if (what == ICSK_TIME_DACK) { + icsk->icsk_ack.pending |= ICSK_ACK_TIMER; + icsk->icsk_ack.timeout = jiffies + when; + sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout); + } +#ifdef INET_CSK_DEBUG + else { + pr_debug("%s", inet_csk_timer_bug_msg); + } +#endif +} + +extern struct sock *inet_csk_accept(struct sock *sk, int flags, int *err); + +extern struct request_sock *inet_csk_search_req(const struct sock *sk, + struct request_sock ***prevp, + const __be16 rport, + const __be32 raddr, + const __be32 laddr); +extern int inet_csk_bind_conflict(const struct sock *sk, + const struct inet_bind_bucket *tb); +extern int inet_csk_get_port(struct sock *sk, unsigned short snum); + +extern struct dst_entry* inet_csk_route_req(struct sock *sk, + const struct request_sock *req); + +static inline void inet_csk_reqsk_queue_add(struct sock *sk, + struct request_sock *req, + struct sock *child) +{ + reqsk_queue_add(&inet_csk(sk)->icsk_accept_queue, req, sk, child); +} + +extern void inet_csk_reqsk_queue_hash_add(struct sock *sk, + struct request_sock *req, + unsigned long timeout); + +static inline void inet_csk_reqsk_queue_removed(struct sock *sk, + struct request_sock *req) +{ + if (reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req) == 0) + inet_csk_delete_keepalive_timer(sk); +} + +static inline void inet_csk_reqsk_queue_added(struct sock *sk, + const unsigned long timeout) +{ + if (reqsk_queue_added(&inet_csk(sk)->icsk_accept_queue) == 0) + inet_csk_reset_keepalive_timer(sk, timeout); +} + +static inline int inet_csk_reqsk_queue_len(const struct sock *sk) +{ + return reqsk_queue_len(&inet_csk(sk)->icsk_accept_queue); +} + +static inline int inet_csk_reqsk_queue_young(const struct sock *sk) +{ + return reqsk_queue_len_young(&inet_csk(sk)->icsk_accept_queue); +} + +static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk) +{ + return reqsk_queue_is_full(&inet_csk(sk)->icsk_accept_queue); +} + +static inline void inet_csk_reqsk_queue_unlink(struct sock *sk, + struct request_sock *req, + struct request_sock **prev) +{ + reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req, prev); +} + +static inline void inet_csk_reqsk_queue_drop(struct sock *sk, + struct request_sock *req, + struct request_sock **prev) +{ + inet_csk_reqsk_queue_unlink(sk, req, prev); + inet_csk_reqsk_queue_removed(sk, req); + reqsk_free(req); +} + +extern void inet_csk_reqsk_queue_prune(struct sock *parent, + const unsigned long interval, + const unsigned long timeout, + const unsigned long max_rto); + +extern void inet_csk_destroy_sock(struct sock *sk); + +/* + * LISTEN is a special case for poll.. + */ +static inline unsigned int inet_csk_listen_poll(const struct sock *sk) +{ + return !reqsk_queue_empty(&inet_csk(sk)->icsk_accept_queue) ? + (POLLIN | POLLRDNORM) : 0; +} + +extern int inet_csk_listen_start(struct sock *sk, const int nr_table_entries); +extern void inet_csk_listen_stop(struct sock *sk); + +extern void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); + +extern int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +extern int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, unsigned int optlen); +#endif /* _INET_CONNECTION_SOCK_H */ diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h new file mode 100644 index 00000000..9b5d08f4 --- /dev/null +++ b/include/net/inet_ecn.h @@ -0,0 +1,130 @@ +#ifndef _INET_ECN_H_ +#define _INET_ECN_H_ + +#include <linux/ip.h> +#include <linux/skbuff.h> + +#include <net/inet_sock.h> +#include <net/dsfield.h> + +enum { + INET_ECN_NOT_ECT = 0, + INET_ECN_ECT_1 = 1, + INET_ECN_ECT_0 = 2, + INET_ECN_CE = 3, + INET_ECN_MASK = 3, +}; + +static inline int INET_ECN_is_ce(__u8 dsfield) +{ + return (dsfield & INET_ECN_MASK) == INET_ECN_CE; +} + +static inline int INET_ECN_is_not_ect(__u8 dsfield) +{ + return (dsfield & INET_ECN_MASK) == INET_ECN_NOT_ECT; +} + +static inline int INET_ECN_is_capable(__u8 dsfield) +{ + return (dsfield & INET_ECN_ECT_0); +} + +static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) +{ + outer &= ~INET_ECN_MASK; + outer |= !INET_ECN_is_ce(inner) ? (inner & INET_ECN_MASK) : + INET_ECN_ECT_0; + return outer; +} + +#define INET_ECN_xmit(sk) do { inet_sk(sk)->tos |= INET_ECN_ECT_0; } while (0) +#define INET_ECN_dontxmit(sk) \ + do { inet_sk(sk)->tos &= ~INET_ECN_MASK; } while (0) + +#define IP6_ECN_flow_init(label) do { \ + (label) &= ~htonl(INET_ECN_MASK << 20); \ + } while (0) + +#define IP6_ECN_flow_xmit(sk, label) do { \ + if (INET_ECN_is_capable(inet6_sk(sk)->tclass)) \ + (label) |= htonl(INET_ECN_ECT_0 << 20); \ + } while (0) + +static inline int IP_ECN_set_ce(struct iphdr *iph) +{ + u32 check = (__force u32)iph->check; + u32 ecn = (iph->tos + 1) & INET_ECN_MASK; + + /* + * After the last operation we have (in binary): + * INET_ECN_NOT_ECT => 01 + * INET_ECN_ECT_1 => 10 + * INET_ECN_ECT_0 => 11 + * INET_ECN_CE => 00 + */ + if (!(ecn & 2)) + return !ecn; + + /* + * The following gives us: + * INET_ECN_ECT_1 => check += htons(0xFFFD) + * INET_ECN_ECT_0 => check += htons(0xFFFE) + */ + check += (__force u16)htons(0xFFFB) + (__force u16)htons(ecn); + + iph->check = (__force __sum16)(check + (check>=0xFFFF)); + iph->tos |= INET_ECN_CE; + return 1; +} + +static inline void IP_ECN_clear(struct iphdr *iph) +{ + iph->tos &= ~INET_ECN_MASK; +} + +static inline void ipv4_copy_dscp(unsigned int dscp, struct iphdr *inner) +{ + dscp &= ~INET_ECN_MASK; + ipv4_change_dsfield(inner, INET_ECN_MASK, dscp); +} + +struct ipv6hdr; + +static inline int IP6_ECN_set_ce(struct ipv6hdr *iph) +{ + if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph))) + return 0; + *(__be32*)iph |= htonl(INET_ECN_CE << 20); + return 1; +} + +static inline void IP6_ECN_clear(struct ipv6hdr *iph) +{ + *(__be32*)iph &= ~htonl(INET_ECN_MASK << 20); +} + +static inline void ipv6_copy_dscp(unsigned int dscp, struct ipv6hdr *inner) +{ + dscp &= ~INET_ECN_MASK; + ipv6_change_dsfield(inner, INET_ECN_MASK, dscp); +} + +static inline int INET_ECN_set_ce(struct sk_buff *skb) +{ + switch (skb->protocol) { + case cpu_to_be16(ETH_P_IP): + if (skb->network_header + sizeof(struct iphdr) <= skb->tail) + return IP_ECN_set_ce(ip_hdr(skb)); + break; + + case cpu_to_be16(ETH_P_IPV6): + if (skb->network_header + sizeof(struct ipv6hdr) <= skb->tail) + return IP6_ECN_set_ce(ipv6_hdr(skb)); + break; + } + + return 0; +} + +#endif diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h new file mode 100644 index 00000000..16ff29a7 --- /dev/null +++ b/include/net/inet_frag.h @@ -0,0 +1,74 @@ +#ifndef __NET_FRAG_H__ +#define __NET_FRAG_H__ + +struct netns_frags { + int nqueues; + atomic_t mem; + struct list_head lru_list; + + /* sysctls */ + int timeout; + int high_thresh; + int low_thresh; +}; + +struct inet_frag_queue { + struct hlist_node list; + struct netns_frags *net; + struct list_head lru_list; /* lru list member */ + spinlock_t lock; + atomic_t refcnt; + struct timer_list timer; /* when will this queue expire? */ + struct sk_buff *fragments; /* list of received fragments */ + struct sk_buff *fragments_tail; + ktime_t stamp; + int len; /* total length of orig datagram */ + int meat; + __u8 last_in; /* first/last segment arrived? */ + +#define INET_FRAG_COMPLETE 4 +#define INET_FRAG_FIRST_IN 2 +#define INET_FRAG_LAST_IN 1 +}; + +#define INETFRAGS_HASHSZ 64 + +struct inet_frags { + struct hlist_head hash[INETFRAGS_HASHSZ]; + rwlock_t lock; + u32 rnd; + int qsize; + int secret_interval; + struct timer_list secret_timer; + + unsigned int (*hashfn)(struct inet_frag_queue *); + void (*constructor)(struct inet_frag_queue *q, + void *arg); + void (*destructor)(struct inet_frag_queue *); + void (*skb_free)(struct sk_buff *); + int (*match)(struct inet_frag_queue *q, + void *arg); + void (*frag_expire)(unsigned long data); +}; + +void inet_frags_init(struct inet_frags *); +void inet_frags_fini(struct inet_frags *); + +void inet_frags_init_net(struct netns_frags *nf); +void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f); + +void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); +void inet_frag_destroy(struct inet_frag_queue *q, + struct inet_frags *f, int *work); +int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f); +struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, + struct inet_frags *f, void *key, unsigned int hash) + __releases(&f->lock); + +static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f) +{ + if (atomic_dec_and_test(&q->refcnt)) + inet_frag_destroy(q, f, NULL); +} + +#endif diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h new file mode 100644 index 00000000..74358d1b --- /dev/null +++ b/include/net/inet_hashtables.h @@ -0,0 +1,402 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Authors: Lotsa people, from code originally in tcp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _INET_HASHTABLES_H +#define _INET_HASHTABLES_H + + +#include <linux/interrupt.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/socket.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/vmalloc.h> + +#include <net/inet_connection_sock.h> +#include <net/inet_sock.h> +#include <net/sock.h> +#include <net/route.h> +#include <net/tcp_states.h> +#include <net/netns/hash.h> + +#include <asm/atomic.h> +#include <asm/byteorder.h> + +/* This is for all connections with a full identity, no wildcards. + * One chain is dedicated to TIME_WAIT sockets. + * I'll experiment with dynamic table growth later. + */ +struct inet_ehash_bucket { + struct hlist_nulls_head chain; + struct hlist_nulls_head twchain; +}; + +/* There are a few simple rules, which allow for local port reuse by + * an application. In essence: + * + * 1) Sockets bound to different interfaces may share a local port. + * Failing that, goto test 2. + * 2) If all sockets have sk->sk_reuse set, and none of them are in + * TCP_LISTEN state, the port may be shared. + * Failing that, goto test 3. + * 3) If all sockets are bound to a specific inet_sk(sk)->rcv_saddr local + * address, and none of them are the same, the port may be + * shared. + * Failing this, the port cannot be shared. + * + * The interesting point, is test #2. This is what an FTP server does + * all day. To optimize this case we use a specific flag bit defined + * below. As we add sockets to a bind bucket list, we perform a + * check of: (newsk->sk_reuse && (newsk->sk_state != TCP_LISTEN)) + * As long as all sockets added to a bind bucket pass this test, + * the flag bit will be set. + * The resulting situation is that tcp_v[46]_verify_bind() can just check + * for this flag bit, if it is set and the socket trying to bind has + * sk->sk_reuse set, we don't even have to walk the owners list at all, + * we return that it is ok to bind this socket to the requested local port. + * + * Sounds like a lot of work, but it is worth it. In a more naive + * implementation (ie. current FreeBSD etc.) the entire list of ports + * must be walked for each data port opened by an ftp server. Needless + * to say, this does not scale at all. With a couple thousand FTP + * users logged onto your box, isn't it nice to know that new data + * ports are created in O(1) time? I thought so. ;-) -DaveM + */ +struct inet_bind_bucket { +#ifdef CONFIG_NET_NS + struct net *ib_net; +#endif + unsigned short port; + signed short fastreuse; + int num_owners; + struct hlist_node node; + struct hlist_head owners; +}; + +static inline struct net *ib_net(struct inet_bind_bucket *ib) +{ + return read_pnet(&ib->ib_net); +} + +#define inet_bind_bucket_for_each(tb, pos, head) \ + hlist_for_each_entry(tb, pos, head, node) + +struct inet_bind_hashbucket { + spinlock_t lock; + struct hlist_head chain; +}; + +/* + * Sockets can be hashed in established or listening table + * We must use different 'nulls' end-of-chain value for listening + * hash table, or we might find a socket that was closed and + * reallocated/inserted into established hash table + */ +#define LISTENING_NULLS_BASE (1U << 29) +struct inet_listen_hashbucket { + spinlock_t lock; + struct hlist_nulls_head head; +}; + +/* This is for listening sockets, thus all sockets which possess wildcards. */ +#define INET_LHTABLE_SIZE 32 /* Yes, really, this is all you need. */ + +struct inet_hashinfo { + /* This is for sockets with full identity only. Sockets here will + * always be without wildcards and will have the following invariant: + * + * TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE + * + * TIME_WAIT sockets use a separate chain (twchain). + */ + struct inet_ehash_bucket *ehash; + spinlock_t *ehash_locks; + unsigned int ehash_mask; + unsigned int ehash_locks_mask; + + /* Ok, let's try this, I give up, we do need a local binding + * TCP hash as well as the others for fast bind/connect. + */ + struct inet_bind_hashbucket *bhash; + + unsigned int bhash_size; + /* 4 bytes hole on 64 bit */ + + struct kmem_cache *bind_bucket_cachep; + + /* All the above members are written once at bootup and + * never written again _or_ are predominantly read-access. + * + * Now align to a new cache line as all the following members + * might be often dirty. + */ + /* All sockets in TCP_LISTEN state will be in here. This is the only + * table where wildcard'd TCP sockets can exist. Hash function here + * is just local port number. + */ + struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE] + ____cacheline_aligned_in_smp; + + atomic_t bsockets; +}; + +static inline struct inet_ehash_bucket *inet_ehash_bucket( + struct inet_hashinfo *hashinfo, + unsigned int hash) +{ + return &hashinfo->ehash[hash & hashinfo->ehash_mask]; +} + +static inline spinlock_t *inet_ehash_lockp( + struct inet_hashinfo *hashinfo, + unsigned int hash) +{ + return &hashinfo->ehash_locks[hash & hashinfo->ehash_locks_mask]; +} + +static inline int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo) +{ + unsigned int i, size = 256; +#if defined(CONFIG_PROVE_LOCKING) + unsigned int nr_pcpus = 2; +#else + unsigned int nr_pcpus = num_possible_cpus(); +#endif + if (nr_pcpus >= 4) + size = 512; + if (nr_pcpus >= 8) + size = 1024; + if (nr_pcpus >= 16) + size = 2048; + if (nr_pcpus >= 32) + size = 4096; + if (sizeof(spinlock_t) != 0) { +#ifdef CONFIG_NUMA + if (size * sizeof(spinlock_t) > PAGE_SIZE) + hashinfo->ehash_locks = vmalloc(size * sizeof(spinlock_t)); + else +#endif + hashinfo->ehash_locks = kmalloc(size * sizeof(spinlock_t), + GFP_KERNEL); + if (!hashinfo->ehash_locks) + return ENOMEM; + for (i = 0; i < size; i++) + spin_lock_init(&hashinfo->ehash_locks[i]); + } + hashinfo->ehash_locks_mask = size - 1; + return 0; +} + +static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo) +{ + if (hashinfo->ehash_locks) { +#ifdef CONFIG_NUMA + unsigned int size = (hashinfo->ehash_locks_mask + 1) * + sizeof(spinlock_t); + if (size > PAGE_SIZE) + vfree(hashinfo->ehash_locks); + else +#endif + kfree(hashinfo->ehash_locks); + hashinfo->ehash_locks = NULL; + } +} + +extern struct inet_bind_bucket * + inet_bind_bucket_create(struct kmem_cache *cachep, + struct net *net, + struct inet_bind_hashbucket *head, + const unsigned short snum); +extern void inet_bind_bucket_destroy(struct kmem_cache *cachep, + struct inet_bind_bucket *tb); + +static inline int inet_bhashfn(struct net *net, + const __u16 lport, const int bhash_size) +{ + return (lport + net_hash_mix(net)) & (bhash_size - 1); +} + +extern void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, + const unsigned short snum); + +/* These can have wildcards, don't try too hard. */ +static inline int inet_lhashfn(struct net *net, const unsigned short num) +{ + return (num + net_hash_mix(net)) & (INET_LHTABLE_SIZE - 1); +} + +static inline int inet_sk_listen_hashfn(const struct sock *sk) +{ + return inet_lhashfn(sock_net(sk), inet_sk(sk)->inet_num); +} + +/* Caller must disable local BH processing. */ +extern void __inet_inherit_port(struct sock *sk, struct sock *child); + +extern void inet_put_port(struct sock *sk); + +void inet_hashinfo_init(struct inet_hashinfo *h); + +extern int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw); +extern void inet_hash(struct sock *sk); +extern void inet_unhash(struct sock *sk); + +extern struct sock *__inet_lookup_listener(struct net *net, + struct inet_hashinfo *hashinfo, + const __be32 daddr, + const unsigned short hnum, + const int dif); + +static inline struct sock *inet_lookup_listener(struct net *net, + struct inet_hashinfo *hashinfo, + __be32 daddr, __be16 dport, int dif) +{ + return __inet_lookup_listener(net, hashinfo, daddr, ntohs(dport), dif); +} + +/* Socket demux engine toys. */ +/* What happens here is ugly; there's a pair of adjacent fields in + struct inet_sock; __be16 dport followed by __u16 num. We want to + search by pair, so we combine the keys into a single 32bit value + and compare with 32bit value read from &...->dport. Let's at least + make sure that it's not mixed with anything else... + On 64bit targets we combine comparisons with pair of adjacent __be32 + fields in the same way. +*/ +typedef __u32 __bitwise __portpair; +#ifdef __BIG_ENDIAN +#define INET_COMBINED_PORTS(__sport, __dport) \ + ((__force __portpair)(((__force __u32)(__be16)(__sport) << 16) | (__u32)(__dport))) +#else /* __LITTLE_ENDIAN */ +#define INET_COMBINED_PORTS(__sport, __dport) \ + ((__force __portpair)(((__u32)(__dport) << 16) | (__force __u32)(__be16)(__sport))) +#endif + +#if (BITS_PER_LONG == 64) +typedef __u64 __bitwise __addrpair; +#ifdef __BIG_ENDIAN +#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ + const __addrpair __name = (__force __addrpair) ( \ + (((__force __u64)(__be32)(__saddr)) << 32) | \ + ((__force __u64)(__be32)(__daddr))); +#else /* __LITTLE_ENDIAN */ +#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ + const __addrpair __name = (__force __addrpair) ( \ + (((__force __u64)(__be32)(__daddr)) << 32) | \ + ((__force __u64)(__be32)(__saddr))); +#endif /* __BIG_ENDIAN */ +#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ + ((*((__addrpair *)&(inet_sk(__sk)->inet_daddr))) == (__cookie)) && \ + ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +#define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ + ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ + ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +#else /* 32-bit arch */ +#define INET_ADDR_COOKIE(__name, __saddr, __daddr) +#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ + (inet_sk(__sk)->inet_daddr == (__saddr)) && \ + (inet_sk(__sk)->inet_rcv_saddr == (__daddr)) && \ + ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +#define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ + (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ + (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ + ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +#endif /* 64-bit arch */ + +/* + * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need + * not check it for lookups anymore, thanks Alexey. -DaveM + * + * Local BH must be disabled here. + */ +extern struct sock * __inet_lookup_established(struct net *net, + struct inet_hashinfo *hashinfo, + const __be32 saddr, const __be16 sport, + const __be32 daddr, const u16 hnum, const int dif); + +static inline struct sock * + inet_lookup_established(struct net *net, struct inet_hashinfo *hashinfo, + const __be32 saddr, const __be16 sport, + const __be32 daddr, const __be16 dport, + const int dif) +{ + return __inet_lookup_established(net, hashinfo, saddr, sport, daddr, + ntohs(dport), dif); +} + +static inline struct sock *__inet_lookup(struct net *net, + struct inet_hashinfo *hashinfo, + const __be32 saddr, const __be16 sport, + const __be32 daddr, const __be16 dport, + const int dif) +{ + u16 hnum = ntohs(dport); + struct sock *sk = __inet_lookup_established(net, hashinfo, + saddr, sport, daddr, hnum, dif); + + return sk ? : __inet_lookup_listener(net, hashinfo, daddr, hnum, dif); +} + +static inline struct sock *inet_lookup(struct net *net, + struct inet_hashinfo *hashinfo, + const __be32 saddr, const __be16 sport, + const __be32 daddr, const __be16 dport, + const int dif) +{ + struct sock *sk; + + local_bh_disable(); + sk = __inet_lookup(net, hashinfo, saddr, sport, daddr, dport, dif); + local_bh_enable(); + + return sk; +} + +static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo, + struct sk_buff *skb, + const __be16 sport, + const __be16 dport) +{ + struct sock *sk; + const struct iphdr *iph = ip_hdr(skb); + + if (unlikely(sk = skb_steal_sock(skb))) + return sk; + else + return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, + iph->saddr, sport, + iph->daddr, dport, inet_iif(skb)); +} + +extern int __inet_hash_connect(struct inet_timewait_death_row *death_row, + struct sock *sk, + u32 port_offset, + int (*check_established)(struct inet_timewait_death_row *, + struct sock *, __u16, struct inet_timewait_sock **), + int (*hash)(struct sock *sk, struct inet_timewait_sock *twp)); + +extern int inet_hash_connect(struct inet_timewait_death_row *death_row, + struct sock *sk); +#endif /* _INET_HASHTABLES_H */ diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h new file mode 100644 index 00000000..1989cfd7 --- /dev/null +++ b/include/net/inet_sock.h @@ -0,0 +1,224 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for inet_sock + * + * Authors: Many, reorganised here by + * Arnaldo Carvalho de Melo <acme@mandriva.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _INET_SOCK_H +#define _INET_SOCK_H + + +#include <linux/kmemcheck.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/jhash.h> +#include <linux/netdevice.h> + +#include <net/flow.h> +#include <net/sock.h> +#include <net/request_sock.h> +#include <net/netns/hash.h> + +/** struct ip_options - IP Options + * + * @faddr - Saved first hop address + * @is_data - Options in __data, rather than skb + * @is_strictroute - Strict source route + * @srr_is_hit - Packet destination addr was our one + * @is_changed - IP checksum more not valid + * @rr_needaddr - Need to record addr of outgoing dev + * @ts_needtime - Need to record timestamp + * @ts_needaddr - Need to record addr of outgoing dev + */ +struct ip_options { + __be32 faddr; + unsigned char optlen; + unsigned char srr; + unsigned char rr; + unsigned char ts; + unsigned char is_strictroute:1, + srr_is_hit:1, + is_changed:1, + rr_needaddr:1, + ts_needtime:1, + ts_needaddr:1; + unsigned char router_alert; + unsigned char cipso; + unsigned char __pad2; + unsigned char __data[0]; +}; + +#define optlength(opt) (sizeof(struct ip_options) + opt->optlen) + +struct inet_request_sock { + struct request_sock req; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + u16 inet6_rsk_offset; +#endif + __be16 loc_port; + __be32 loc_addr; + __be32 rmt_addr; + __be16 rmt_port; + kmemcheck_bitfield_begin(flags); + u16 snd_wscale : 4, + rcv_wscale : 4, + tstamp_ok : 1, + sack_ok : 1, + wscale_ok : 1, + ecn_ok : 1, + acked : 1, + no_srccheck: 1; + kmemcheck_bitfield_end(flags); + struct ip_options *opt; +}; + +static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk) +{ + return (struct inet_request_sock *)sk; +} + +struct ip_mc_socklist; +struct ipv6_pinfo; +struct rtable; + +/** struct inet_sock - representation of INET sockets + * + * @sk - ancestor class + * @pinet6 - pointer to IPv6 control block + * @inet_daddr - Foreign IPv4 addr + * @inet_rcv_saddr - Bound local IPv4 addr + * @inet_dport - Destination port + * @inet_num - Local port + * @inet_saddr - Sending source + * @uc_ttl - Unicast TTL + * @inet_sport - Source port + * @inet_id - ID counter for DF pkts + * @tos - TOS + * @mc_ttl - Multicasting TTL + * @is_icsk - is this an inet_connection_sock? + * @mc_index - Multicast device index + * @mc_list - Group array + * @cork - info to build ip hdr on each ip frag while socket is corked + */ +struct inet_sock { + /* sk and pinet6 has to be the first two members of inet_sock */ + struct sock sk; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct ipv6_pinfo *pinet6; +#endif + /* Socket demultiplex comparisons on incoming packets. */ + __be32 inet_daddr; + __be32 inet_rcv_saddr; + __be16 inet_dport; + __u16 inet_num; + __be32 inet_saddr; + __s16 uc_ttl; + __u16 cmsg_flags; + __be16 inet_sport; + __u16 inet_id; + + struct ip_options *opt; + __u8 tos; + __u8 min_ttl; + __u8 mc_ttl; + __u8 pmtudisc; + __u8 recverr:1, + is_icsk:1, + freebind:1, + hdrincl:1, + mc_loop:1, + transparent:1, + mc_all:1, + nodefrag:1; + int mc_index; + __be32 mc_addr; + struct ip_mc_socklist *mc_list; + struct { + unsigned int flags; + unsigned int fragsize; + struct ip_options *opt; + struct dst_entry *dst; + int length; /* Total length of all frames */ + __be32 addr; + struct flowi fl; + } cork; +}; + +#define IPCORK_OPT 1 /* ip-options has been held in ipcork.opt */ +#define IPCORK_ALLFRAG 2 /* always fragment (for ipv6 for now) */ + +static inline struct inet_sock *inet_sk(const struct sock *sk) +{ + return (struct inet_sock *)sk; +} + +static inline void __inet_sk_copy_descendant(struct sock *sk_to, + const struct sock *sk_from, + const int ancestor_size) +{ + memcpy(inet_sk(sk_to) + 1, inet_sk(sk_from) + 1, + sk_from->sk_prot->obj_size - ancestor_size); +} +#if !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) +static inline void inet_sk_copy_descendant(struct sock *sk_to, + const struct sock *sk_from) +{ + __inet_sk_copy_descendant(sk_to, sk_from, sizeof(struct inet_sock)); +} +#endif + +extern int inet_sk_rebuild_header(struct sock *sk); + +extern u32 inet_ehash_secret; +extern void build_ehash_secret(void); + +static inline unsigned int inet_ehashfn(struct net *net, + const __be32 laddr, const __u16 lport, + const __be32 faddr, const __be16 fport) +{ + return jhash_3words((__force __u32) laddr, + (__force __u32) faddr, + ((__u32) lport) << 16 | (__force __u32)fport, + inet_ehash_secret + net_hash_mix(net)); +} + +static inline int inet_sk_ehashfn(const struct sock *sk) +{ + const struct inet_sock *inet = inet_sk(sk); + const __be32 laddr = inet->inet_rcv_saddr; + const __u16 lport = inet->inet_num; + const __be32 faddr = inet->inet_daddr; + const __be16 fport = inet->inet_dport; + struct net *net = sock_net(sk); + + return inet_ehashfn(net, laddr, lport, faddr, fport); +} + +static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops) +{ + struct request_sock *req = reqsk_alloc(ops); + struct inet_request_sock *ireq = inet_rsk(req); + + if (req != NULL) { + kmemcheck_annotate_bitfield(ireq, flags); + ireq->opt = NULL; + } + + return req; +} + +static inline __u8 inet_sk_flowi_flags(const struct sock *sk) +{ + return inet_sk(sk)->transparent ? FLOWI_FLAG_ANYSRC : 0; +} + +#endif /* _INET_SOCK_H */ diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h new file mode 100644 index 00000000..a066fdd5 --- /dev/null +++ b/include/net/inet_timewait_sock.h @@ -0,0 +1,242 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for a generic INET TIMEWAIT sock + * + * From code originally in net/tcp.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _INET_TIMEWAIT_SOCK_ +#define _INET_TIMEWAIT_SOCK_ + + +#include <linux/kmemcheck.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/types.h> +#include <linux/workqueue.h> + +#include <net/inet_sock.h> +#include <net/sock.h> +#include <net/tcp_states.h> +#include <net/timewait_sock.h> + +#include <asm/atomic.h> + +struct inet_hashinfo; + +#define INET_TWDR_RECYCLE_SLOTS_LOG 5 +#define INET_TWDR_RECYCLE_SLOTS (1 << INET_TWDR_RECYCLE_SLOTS_LOG) + +/* + * If time > 4sec, it is "slow" path, no recycling is required, + * so that we select tick to get range about 4 seconds. + */ +#if HZ <= 16 || HZ > 4096 +# error Unsupported: HZ <= 16 or HZ > 4096 +#elif HZ <= 32 +# define INET_TWDR_RECYCLE_TICK (5 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#elif HZ <= 64 +# define INET_TWDR_RECYCLE_TICK (6 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#elif HZ <= 128 +# define INET_TWDR_RECYCLE_TICK (7 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#elif HZ <= 256 +# define INET_TWDR_RECYCLE_TICK (8 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#elif HZ <= 512 +# define INET_TWDR_RECYCLE_TICK (9 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#elif HZ <= 1024 +# define INET_TWDR_RECYCLE_TICK (10 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#elif HZ <= 2048 +# define INET_TWDR_RECYCLE_TICK (11 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#else +# define INET_TWDR_RECYCLE_TICK (12 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG) +#endif + +/* TIME_WAIT reaping mechanism. */ +#define INET_TWDR_TWKILL_SLOTS 8 /* Please keep this a power of 2. */ + +#define INET_TWDR_TWKILL_QUOTA 100 + +struct inet_timewait_death_row { + /* Short-time timewait calendar */ + int twcal_hand; + unsigned long twcal_jiffie; + struct timer_list twcal_timer; + struct hlist_head twcal_row[INET_TWDR_RECYCLE_SLOTS]; + + spinlock_t death_lock; + int tw_count; + int period; + u32 thread_slots; + struct work_struct twkill_work; + struct timer_list tw_timer; + int slot; + struct hlist_head cells[INET_TWDR_TWKILL_SLOTS]; + struct inet_hashinfo *hashinfo; + int sysctl_tw_recycle; + int sysctl_max_tw_buckets; +}; + +extern void inet_twdr_hangman(unsigned long data); +extern void inet_twdr_twkill_work(struct work_struct *work); +extern void inet_twdr_twcal_tick(unsigned long data); + +#if (BITS_PER_LONG == 64) +#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 8 +#else +#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 4 +#endif + +struct inet_bind_bucket; + +/* + * This is a TIME_WAIT sock. It works around the memory consumption + * problems of sockets in such a state on heavily loaded servers, but + * without violating the protocol specification. + */ +struct inet_timewait_sock { + /* + * Now struct sock also uses sock_common, so please just + * don't add nothing before this first member (__tw_common) --acme + */ + struct sock_common __tw_common; +#define tw_family __tw_common.skc_family +#define tw_state __tw_common.skc_state +#define tw_reuse __tw_common.skc_reuse +#define tw_bound_dev_if __tw_common.skc_bound_dev_if +#define tw_node __tw_common.skc_nulls_node +#define tw_bind_node __tw_common.skc_bind_node +#define tw_refcnt __tw_common.skc_refcnt +#define tw_hash __tw_common.skc_hash +#define tw_prot __tw_common.skc_prot +#define tw_net __tw_common.skc_net + int tw_timeout; + volatile unsigned char tw_substate; + /* 3 bits hole, try to pack */ + unsigned char tw_rcv_wscale; + /* Socket demultiplex comparisons on incoming packets. */ + /* these five are in inet_sock */ + __be16 tw_sport; + __be32 tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES))); + __be32 tw_rcv_saddr; + __be16 tw_dport; + __u16 tw_num; + kmemcheck_bitfield_begin(flags); + /* And these are ours. */ + unsigned int tw_ipv6only : 1, + tw_transparent : 1, + tw_pad : 14, /* 14 bits hole */ + tw_ipv6_offset : 16; + kmemcheck_bitfield_end(flags); + unsigned long tw_ttd; + struct inet_bind_bucket *tw_tb; + struct hlist_node tw_death_node; +}; + +static inline void inet_twsk_add_node_rcu(struct inet_timewait_sock *tw, + struct hlist_nulls_head *list) +{ + hlist_nulls_add_head_rcu(&tw->tw_node, list); +} + +static inline void inet_twsk_add_bind_node(struct inet_timewait_sock *tw, + struct hlist_head *list) +{ + hlist_add_head(&tw->tw_bind_node, list); +} + +static inline int inet_twsk_dead_hashed(const struct inet_timewait_sock *tw) +{ + return !hlist_unhashed(&tw->tw_death_node); +} + +static inline void inet_twsk_dead_node_init(struct inet_timewait_sock *tw) +{ + tw->tw_death_node.pprev = NULL; +} + +static inline void __inet_twsk_del_dead_node(struct inet_timewait_sock *tw) +{ + __hlist_del(&tw->tw_death_node); + inet_twsk_dead_node_init(tw); +} + +static inline int inet_twsk_del_dead_node(struct inet_timewait_sock *tw) +{ + if (inet_twsk_dead_hashed(tw)) { + __inet_twsk_del_dead_node(tw); + return 1; + } + return 0; +} + +#define inet_twsk_for_each(tw, node, head) \ + hlist_nulls_for_each_entry(tw, node, head, tw_node) + +#define inet_twsk_for_each_inmate(tw, node, jail) \ + hlist_for_each_entry(tw, node, jail, tw_death_node) + +#define inet_twsk_for_each_inmate_safe(tw, node, safe, jail) \ + hlist_for_each_entry_safe(tw, node, safe, jail, tw_death_node) + +static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk) +{ + return (struct inet_timewait_sock *)sk; +} + +static inline __be32 inet_rcv_saddr(const struct sock *sk) +{ + return likely(sk->sk_state != TCP_TIME_WAIT) ? + inet_sk(sk)->inet_rcv_saddr : inet_twsk(sk)->tw_rcv_saddr; +} + +extern void inet_twsk_put(struct inet_timewait_sock *tw); + +extern int inet_twsk_unhash(struct inet_timewait_sock *tw); + +extern int inet_twsk_bind_unhash(struct inet_timewait_sock *tw, + struct inet_hashinfo *hashinfo); + +extern struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, + const int state); + +extern void __inet_twsk_hashdance(struct inet_timewait_sock *tw, + struct sock *sk, + struct inet_hashinfo *hashinfo); + +extern void inet_twsk_schedule(struct inet_timewait_sock *tw, + struct inet_timewait_death_row *twdr, + const int timeo, const int timewait_len); +extern void inet_twsk_deschedule(struct inet_timewait_sock *tw, + struct inet_timewait_death_row *twdr); + +extern void inet_twsk_purge(struct inet_hashinfo *hashinfo, + struct inet_timewait_death_row *twdr, int family); + +static inline +struct net *twsk_net(const struct inet_timewait_sock *twsk) +{ +#ifdef CONFIG_NET_NS + return rcu_dereference_raw(twsk->tw_net); /* protected by locking, */ + /* reference counting, */ + /* initialization, or RCU. */ +#else + return &init_net; +#endif +} + +static inline +void twsk_net_set(struct inet_timewait_sock *twsk, struct net *net) +{ +#ifdef CONFIG_NET_NS + rcu_assign_pointer(twsk->tw_net, net); +#endif +} +#endif /* _INET_TIMEWAIT_SOCK_ */ diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h new file mode 100644 index 00000000..417d0c89 --- /dev/null +++ b/include/net/inetpeer.h @@ -0,0 +1,68 @@ +/* + * INETPEER - A storage for permanent information about peers + * + * Authors: Andrey V. Savochkin <saw@msu.ru> + */ + +#ifndef _NET_INETPEER_H +#define _NET_INETPEER_H + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/spinlock.h> +#include <asm/atomic.h> + +struct inet_peer { + /* group together avl_left,avl_right,v4daddr to speedup lookups */ + struct inet_peer *avl_left, *avl_right; + __be32 v4daddr; /* peer's address */ + __u32 avl_height; + struct list_head unused; + __u32 dtime; /* the time of last use of not + * referenced entries */ + atomic_t refcnt; + /* + * Once inet_peer is queued for deletion (refcnt == -1), following fields + * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp + * We can share memory with rcu_head to keep inet_peer small + * (less then 64 bytes) + */ + union { + struct { + atomic_t rid; /* Frag reception counter */ + atomic_t ip_id_count; /* IP ID for the next packet */ + __u32 tcp_ts; + __u32 tcp_ts_stamp; + }; + struct rcu_head rcu; + }; +}; + +void inet_initpeers(void) __init; + +/* can be called with or without local BH being disabled */ +struct inet_peer *inet_getpeer(__be32 daddr, int create); + +/* can be called from BH context or outside */ +extern void inet_putpeer(struct inet_peer *p); + +/* + * temporary check to make sure we dont access rid, ip_id_count, tcp_ts, + * tcp_ts_stamp if no refcount is taken on inet_peer + */ +static inline void inet_peer_refcheck(const struct inet_peer *p) +{ + WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0); +} + + +/* can be called with or without local BH being disabled */ +static inline __u16 inet_getid(struct inet_peer *p, int more) +{ + more++; + inet_peer_refcheck(p); + return atomic_add_return(more, &p->ip_id_count) - more; +} + +#endif /* _NET_INETPEER_H */ diff --git a/include/net/ip.h b/include/net/ip.h new file mode 100644 index 00000000..890f9725 --- /dev/null +++ b/include/net/ip.h @@ -0,0 +1,444 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the IP module. + * + * Version: @(#)ip.h 1.0.2 05/07/93 + * + * Authors: Ross Biro + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Alan Cox, <gw4pts@gw4pts.ampr.org> + * + * Changes: + * Mike McLagan : Routing by source + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _IP_H +#define _IP_H + +#include <linux/types.h> +#include <linux/ip.h> +#include <linux/in.h> +#include <linux/skbuff.h> + +#include <net/inet_sock.h> +#include <net/snmp.h> +#include <net/flow.h> + +struct sock; + +struct inet_skb_parm { + struct ip_options opt; /* Compiled IP options */ + unsigned char flags; + +#define IPSKB_FORWARDED 1 +#define IPSKB_XFRM_TUNNEL_SIZE 2 +#define IPSKB_XFRM_TRANSFORMED 4 +#define IPSKB_FRAG_COMPLETE 8 +#define IPSKB_REROUTED 16 +}; + +static inline unsigned int ip_hdrlen(const struct sk_buff *skb) +{ + return ip_hdr(skb)->ihl * 4; +} + +struct ipcm_cookie { + __be32 addr; + int oif; + struct ip_options *opt; + union skb_shared_tx shtx; +}; + +#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) + +struct ip_ra_chain { + struct ip_ra_chain *next; + struct sock *sk; + union { + void (*destructor)(struct sock *); + struct sock *saved_sk; + }; + struct rcu_head rcu; +}; + +extern struct ip_ra_chain *ip_ra_chain; + +/* IP flags. */ +#define IP_CE 0x8000 /* Flag: "Congestion" */ +#define IP_DF 0x4000 /* Flag: "Don't Fragment" */ +#define IP_MF 0x2000 /* Flag: "More Fragments" */ +#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */ + +#define IP_FRAG_TIME (30 * HZ) /* fragment lifetime */ + +struct msghdr; +struct net_device; +struct packet_type; +struct rtable; +struct sockaddr; + +extern int igmp_mc_proc_init(void); + +/* + * Functions provided by ip.c + */ + +extern int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, + __be32 saddr, __be32 daddr, + struct ip_options *opt); +extern int ip_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev); +extern int ip_local_deliver(struct sk_buff *skb); +extern int ip_mr_input(struct sk_buff *skb); +extern int ip_output(struct sk_buff *skb); +extern int ip_mc_output(struct sk_buff *skb); +extern int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); +extern int ip_do_nat(struct sk_buff *skb); +extern void ip_send_check(struct iphdr *ip); +extern int __ip_local_out(struct sk_buff *skb); +extern int ip_local_out(struct sk_buff *skb); +extern int ip_queue_xmit(struct sk_buff *skb); +extern void ip_init(void); +extern int ip_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, int len, + int odd, struct sk_buff *skb), + void *from, int len, int protolen, + struct ipcm_cookie *ipc, + struct rtable **rt, + unsigned int flags); +extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb); +extern ssize_t ip_append_page(struct sock *sk, struct page *page, + int offset, size_t size, int flags); +extern int ip_push_pending_frames(struct sock *sk); +extern void ip_flush_pending_frames(struct sock *sk); + +/* datagram.c */ +extern int ip4_datagram_connect(struct sock *sk, + struct sockaddr *uaddr, int addr_len); + +/* + * Map a multicast IP onto multicast MAC for type Token Ring. + * This conforms to RFC1469 Option 2 Multicasting i.e. + * using a functional address to transmit / receive + * multicast packets. + */ + +static inline void ip_tr_mc_map(__be32 addr, char *buf) +{ + buf[0]=0xC0; + buf[1]=0x00; + buf[2]=0x00; + buf[3]=0x04; + buf[4]=0x00; + buf[5]=0x00; +} + +struct ip_reply_arg { + struct kvec iov[1]; + int flags; + __wsum csum; + int csumoffset; /* u16 offset of csum in iov[0].iov_base */ + /* -1 if not needed */ + int bound_dev_if; +}; + +#define IP_REPLY_ARG_NOSRCCHECK 1 + +static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg) +{ + return (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ? FLOWI_FLAG_ANYSRC : 0; +} + +void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg, + unsigned int len); + +struct ipv4_config { + int log_martians; + int no_pmtu_disc; +}; + +extern struct ipv4_config ipv4_config; +#define IP_INC_STATS(net, field) SNMP_INC_STATS64((net)->mib.ip_statistics, field) +#define IP_INC_STATS_BH(net, field) SNMP_INC_STATS64_BH((net)->mib.ip_statistics, field) +#define IP_ADD_STATS(net, field, val) SNMP_ADD_STATS64((net)->mib.ip_statistics, field, val) +#define IP_ADD_STATS_BH(net, field, val) SNMP_ADD_STATS64_BH((net)->mib.ip_statistics, field, val) +#define IP_UPD_PO_STATS(net, field, val) SNMP_UPD_PO_STATS64((net)->mib.ip_statistics, field, val) +#define IP_UPD_PO_STATS_BH(net, field, val) SNMP_UPD_PO_STATS64_BH((net)->mib.ip_statistics, field, val) +#define NET_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.net_statistics, field) +#define NET_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.net_statistics, field) +#define NET_INC_STATS_USER(net, field) SNMP_INC_STATS_USER((net)->mib.net_statistics, field) +#define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd) +#define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd) + +extern unsigned long snmp_fold_field(void __percpu *mib[], int offt); +#if BITS_PER_LONG==32 +extern u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t sync_off); +#else +static inline u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_off) +{ + return snmp_fold_field(mib, offt); +} +#endif +extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align); +extern void snmp_mib_free(void __percpu *ptr[2]); + +extern struct local_ports { + seqlock_t lock; + int range[2]; +} sysctl_local_ports; +extern void inet_get_local_port_range(int *low, int *high); + +extern unsigned long *sysctl_local_reserved_ports; +static inline int inet_is_reserved_local_port(int port) +{ + return test_bit(port, sysctl_local_reserved_ports); +} + +extern int sysctl_ip_default_ttl; +extern int sysctl_ip_nonlocal_bind; + +extern struct ctl_path net_core_path[]; +extern struct ctl_path net_ipv4_ctl_path[]; + +/* From inetpeer.c */ +extern int inet_peer_threshold; +extern int inet_peer_minttl; +extern int inet_peer_maxttl; +extern int inet_peer_gc_mintime; +extern int inet_peer_gc_maxtime; + +/* From ip_output.c */ +extern int sysctl_ip_dynaddr; + +extern void ipfrag_init(void); + +extern void ip_static_sysctl_init(void); + +#ifdef CONFIG_INET +#include <net/dst.h> + +/* The function in 2.2 was invalid, producing wrong result for + * check=0xFEFF. It was noticed by Arthur Skawina _year_ ago. --ANK(000625) */ +static inline +int ip_decrease_ttl(struct iphdr *iph) +{ + u32 check = (__force u32)iph->check; + check += (__force u32)htons(0x0100); + iph->check = (__force __sum16)(check + (check>=0xFFFF)); + return --iph->ttl; +} + +static inline +int ip_dont_fragment(struct sock *sk, struct dst_entry *dst) +{ + return (inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO || + (inet_sk(sk)->pmtudisc == IP_PMTUDISC_WANT && + !(dst_metric_locked(dst, RTAX_MTU)))); +} + +extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more); + +static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk) +{ + if (iph->frag_off & htons(IP_DF)) { + /* This is only to work around buggy Windows95/2000 + * VJ compression implementations. If the ID field + * does not change, they drop every other packet in + * a TCP stream using header compression. + */ + iph->id = (sk && inet_sk(sk)->inet_daddr) ? + htons(inet_sk(sk)->inet_id++) : 0; + } else + __ip_select_ident(iph, dst, 0); +} + +static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more) +{ + if (iph->frag_off & htons(IP_DF)) { + if (sk && inet_sk(sk)->inet_daddr) { + iph->id = htons(inet_sk(sk)->inet_id); + inet_sk(sk)->inet_id += 1 + more; + } else + iph->id = 0; + } else + __ip_select_ident(iph, dst, more); +} + +/* + * Map a multicast IP onto multicast MAC for type ethernet. + */ + +static inline void ip_eth_mc_map(__be32 naddr, char *buf) +{ + __u32 addr=ntohl(naddr); + buf[0]=0x01; + buf[1]=0x00; + buf[2]=0x5e; + buf[5]=addr&0xFF; + addr>>=8; + buf[4]=addr&0xFF; + addr>>=8; + buf[3]=addr&0x7F; +} + +/* + * Map a multicast IP onto multicast MAC for type IP-over-InfiniBand. + * Leave P_Key as 0 to be filled in by driver. + */ + +static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf) +{ + __u32 addr; + unsigned char scope = broadcast[5] & 0xF; + + buf[0] = 0; /* Reserved */ + buf[1] = 0xff; /* Multicast QPN */ + buf[2] = 0xff; + buf[3] = 0xff; + addr = ntohl(naddr); + buf[4] = 0xff; + buf[5] = 0x10 | scope; /* scope from broadcast address */ + buf[6] = 0x40; /* IPv4 signature */ + buf[7] = 0x1b; + buf[8] = broadcast[8]; /* P_Key */ + buf[9] = broadcast[9]; + buf[10] = 0; + buf[11] = 0; + buf[12] = 0; + buf[13] = 0; + buf[14] = 0; + buf[15] = 0; + buf[19] = addr & 0xff; + addr >>= 8; + buf[18] = addr & 0xff; + addr >>= 8; + buf[17] = addr & 0xff; + addr >>= 8; + buf[16] = addr & 0x0f; +} + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#include <linux/ipv6.h> +#endif + +static __inline__ void inet_reset_saddr(struct sock *sk) +{ + inet_sk(sk)->inet_rcv_saddr = inet_sk(sk)->inet_saddr = 0; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (sk->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + + memset(&np->saddr, 0, sizeof(np->saddr)); + memset(&np->rcv_saddr, 0, sizeof(np->rcv_saddr)); + } +#endif +} + +#endif + +static inline int sk_mc_loop(struct sock *sk) +{ + if (!sk) + return 1; + switch (sk->sk_family) { + case AF_INET: + return inet_sk(sk)->mc_loop; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + return inet6_sk(sk)->mc_loop; +#endif + } + WARN_ON(1); + return 1; +} + +extern int ip_call_ra_chain(struct sk_buff *skb); + +/* + * Functions provided by ip_fragment.c + */ + +enum ip_defrag_users { + IP_DEFRAG_LOCAL_DELIVER, + IP_DEFRAG_CALL_RA_CHAIN, + IP_DEFRAG_CONNTRACK_IN, + __IP_DEFRAG_CONNTRACK_IN_END = IP_DEFRAG_CONNTRACK_IN + USHRT_MAX, + IP_DEFRAG_CONNTRACK_OUT, + __IP_DEFRAG_CONNTRACK_OUT_END = IP_DEFRAG_CONNTRACK_OUT + USHRT_MAX, + IP_DEFRAG_CONNTRACK_BRIDGE_IN, + __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX, + IP_DEFRAG_VS_IN, + IP_DEFRAG_VS_OUT, + IP_DEFRAG_VS_FWD +}; + +int ip_defrag(struct sk_buff *skb, u32 user); +int ip_frag_mem(struct net *net); +int ip_frag_nqueues(struct net *net); + +/* + * Functions provided by ip_forward.c + */ + +extern int ip_forward(struct sk_buff *skb); + +/* + * Functions provided by ip_options.c + */ + +extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag); +extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb); +extern void ip_options_fragment(struct sk_buff *skb); +extern int ip_options_compile(struct net *net, + struct ip_options *opt, struct sk_buff *skb); +extern int ip_options_get(struct net *net, struct ip_options **optp, + unsigned char *data, int optlen); +extern int ip_options_get_from_user(struct net *net, struct ip_options **optp, + unsigned char __user *data, int optlen); +extern void ip_options_undo(struct ip_options * opt); +extern void ip_forward_options(struct sk_buff *skb); +extern int ip_options_rcv_srr(struct sk_buff *skb); + +/* + * Functions provided by ip_sockglue.c + */ + +extern int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); +extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); +extern int ip_cmsg_send(struct net *net, + struct msghdr *msg, struct ipcm_cookie *ipc); +extern int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen); +extern int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); +extern int compat_ip_setsockopt(struct sock *sk, int level, + int optname, char __user *optval, unsigned int optlen); +extern int compat_ip_getsockopt(struct sock *sk, int level, + int optname, char __user *optval, int __user *optlen); +extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)); + +extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len); +extern void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, + __be16 port, u32 info, u8 *payload); +extern void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport, + u32 info); + +/* sysctl helpers - any sysctl which holds a value that ends up being + * fed into the routing cache should use these handlers. + */ +int ipv4_doint_and_flush(ctl_table *ctl, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos); +int ipv4_doint_and_flush_strategy(ctl_table *table, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen); +#ifdef CONFIG_PROC_FS +extern int ip_misc_proc_init(void); +#endif + +#endif /* _IP_H */ diff --git a/include/net/ip6_checksum.h b/include/net/ip6_checksum.h new file mode 100644 index 00000000..bc1b0fda --- /dev/null +++ b/include/net/ip6_checksum.h @@ -0,0 +1,94 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Checksumming functions for IPv6 + * + * Authors: Jorge Cwik, <jorge@laser.satlink.net> + * Arnt Gulbrandsen, <agulbra@nvg.unit.no> + * Borrows very liberally from tcp.c and ip.c, see those + * files for more names. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * Fixes: + * + * Ralf Baechle : generic ipv6 checksum + * <ralf@waldorf-gmbh.de> + */ + +#ifndef _CHECKSUM_IPV6_H +#define _CHECKSUM_IPV6_H + +#include <asm/types.h> +#include <asm/byteorder.h> +#include <net/ip.h> +#include <asm/checksum.h> +#include <linux/in6.h> + +#ifndef _HAVE_ARCH_IPV6_CSUM + +static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, unsigned short proto, + __wsum csum) +{ + + int carry; + __u32 ulen; + __u32 uproto; + __u32 sum = (__force u32)csum; + + sum += (__force u32)saddr->s6_addr32[0]; + carry = (sum < (__force u32)saddr->s6_addr32[0]); + sum += carry; + + sum += (__force u32)saddr->s6_addr32[1]; + carry = (sum < (__force u32)saddr->s6_addr32[1]); + sum += carry; + + sum += (__force u32)saddr->s6_addr32[2]; + carry = (sum < (__force u32)saddr->s6_addr32[2]); + sum += carry; + + sum += (__force u32)saddr->s6_addr32[3]; + carry = (sum < (__force u32)saddr->s6_addr32[3]); + sum += carry; + + sum += (__force u32)daddr->s6_addr32[0]; + carry = (sum < (__force u32)daddr->s6_addr32[0]); + sum += carry; + + sum += (__force u32)daddr->s6_addr32[1]; + carry = (sum < (__force u32)daddr->s6_addr32[1]); + sum += carry; + + sum += (__force u32)daddr->s6_addr32[2]; + carry = (sum < (__force u32)daddr->s6_addr32[2]); + sum += carry; + + sum += (__force u32)daddr->s6_addr32[3]; + carry = (sum < (__force u32)daddr->s6_addr32[3]); + sum += carry; + + ulen = (__force u32)htonl((__u32) len); + sum += ulen; + carry = (sum < ulen); + sum += carry; + + uproto = (__force u32)htonl(proto); + sum += uproto; + carry = (sum < uproto); + sum += carry; + + return csum_fold((__force __wsum)sum); +} + +#endif +#endif diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h new file mode 100644 index 00000000..062a823d --- /dev/null +++ b/include/net/ip6_fib.h @@ -0,0 +1,238 @@ +/* + * Linux INET6 implementation + * + * Authors: + * Pedro Roque <roque@di.fc.ul.pt> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _IP6_FIB_H +#define _IP6_FIB_H + +#ifdef __KERNEL__ + +#include <linux/ipv6_route.h> +#include <linux/rtnetlink.h> +#include <linux/spinlock.h> +#include <net/dst.h> +#include <net/flow.h> +#include <net/netlink.h> + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES +#define FIB6_TABLE_HASHSZ 256 +#else +#define FIB6_TABLE_HASHSZ 1 +#endif + +struct rt6_info; + +struct fib6_config { + u32 fc_table; + u32 fc_metric; + int fc_dst_len; + int fc_src_len; + int fc_ifindex; + u32 fc_flags; + u32 fc_protocol; + + struct in6_addr fc_dst; + struct in6_addr fc_src; + struct in6_addr fc_gateway; + + unsigned long fc_expires; + struct nlattr *fc_mx; + int fc_mx_len; + + struct nl_info fc_nlinfo; +}; + +struct fib6_node { + struct fib6_node *parent; + struct fib6_node *left; + struct fib6_node *right; +#ifdef CONFIG_IPV6_SUBTREES + struct fib6_node *subtree; +#endif + struct rt6_info *leaf; + + __u16 fn_bit; /* bit key */ + __u16 fn_flags; + __u32 fn_sernum; + struct rt6_info *rr_ptr; +}; + +#ifndef CONFIG_IPV6_SUBTREES +#define FIB6_SUBTREE(fn) NULL +#else +#define FIB6_SUBTREE(fn) ((fn)->subtree) +#endif + +/* + * routing information + * + */ + +struct rt6key { + struct in6_addr addr; + int plen; +}; + +struct fib6_table; + +struct rt6_info { + struct dst_entry dst; + +#define rt6i_dev dst.dev +#define rt6i_nexthop dst.neighbour +#define rt6i_expires dst.expires + + /* + * Tail elements of dst_entry (__refcnt etc.) + * and these elements (rarely used in hot path) are in + * the same cache line. + */ + struct fib6_table *rt6i_table; + struct fib6_node *rt6i_node; + + struct in6_addr rt6i_gateway; + + atomic_t rt6i_ref; + + /* These are in a separate cache line. */ + struct rt6key rt6i_dst ____cacheline_aligned_in_smp; + u32 rt6i_flags; + struct rt6key rt6i_src; + u32 rt6i_metric; + + struct inet6_dev *rt6i_idev; + +#ifdef CONFIG_XFRM + u32 rt6i_flow_cache_genid; +#endif + /* more non-fragment space at head required */ + unsigned short rt6i_nfheader_len; + + u8 rt6i_protocol; +}; + +static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) +{ + return ((struct rt6_info *)dst)->rt6i_idev; +} + +struct fib6_walker_t { + struct list_head lh; + struct fib6_node *root, *node; + struct rt6_info *leaf; + unsigned char state; + unsigned char prune; + unsigned int skip; + unsigned int count; + int (*func)(struct fib6_walker_t *); + void *args; +}; + +struct rt6_statistics { + __u32 fib_nodes; + __u32 fib_route_nodes; + __u32 fib_rt_alloc; /* permanent routes */ + __u32 fib_rt_entries; /* rt entries in table */ + __u32 fib_rt_cache; /* cache routes */ + __u32 fib_discarded_routes; +}; + +#define RTN_TL_ROOT 0x0001 +#define RTN_ROOT 0x0002 /* tree root node */ +#define RTN_RTINFO 0x0004 /* node with valid routing info */ + +/* + * priority levels (or metrics) + * + */ + + +struct fib6_table { + struct hlist_node tb6_hlist; + u32 tb6_id; + rwlock_t tb6_lock; + struct fib6_node tb6_root; +}; + +#define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC +#define RT6_TABLE_MAIN RT_TABLE_MAIN +#define RT6_TABLE_DFLT RT6_TABLE_MAIN +#define RT6_TABLE_INFO RT6_TABLE_MAIN +#define RT6_TABLE_PREFIX RT6_TABLE_MAIN + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES +#define FIB6_TABLE_MIN 1 +#define FIB6_TABLE_MAX RT_TABLE_MAX +#define RT6_TABLE_LOCAL RT_TABLE_LOCAL +#else +#define FIB6_TABLE_MIN RT_TABLE_MAIN +#define FIB6_TABLE_MAX FIB6_TABLE_MIN +#define RT6_TABLE_LOCAL RT6_TABLE_MAIN +#endif + +typedef struct rt6_info *(*pol_lookup_t)(struct net *, + struct fib6_table *, + struct flowi *, int); + +/* + * exported functions + */ + +extern struct fib6_table *fib6_get_table(struct net *net, u32 id); +extern struct fib6_table *fib6_new_table(struct net *net, u32 id); +extern struct dst_entry *fib6_rule_lookup(struct net *net, + struct flowi *fl, int flags, + pol_lookup_t lookup); + +extern struct fib6_node *fib6_lookup(struct fib6_node *root, + struct in6_addr *daddr, + struct in6_addr *saddr); + +struct fib6_node *fib6_locate(struct fib6_node *root, + struct in6_addr *daddr, int dst_len, + struct in6_addr *saddr, int src_len); + +extern void fib6_clean_all(struct net *net, + int (*func)(struct rt6_info *, void *arg), + int prune, void *arg); + +extern int fib6_add(struct fib6_node *root, + struct rt6_info *rt, + struct nl_info *info); + +extern int fib6_del(struct rt6_info *rt, + struct nl_info *info); + +extern void inet6_rt_notify(int event, struct rt6_info *rt, + struct nl_info *info); + +extern void fib6_run_gc(unsigned long expires, + struct net *net); + +extern void fib6_gc_cleanup(void); + +extern int fib6_init(void); + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES +extern int fib6_rules_init(void); +extern void fib6_rules_cleanup(void); +#else +static inline int fib6_rules_init(void) +{ + return 0; +} +static inline void fib6_rules_cleanup(void) +{ + return ; +} +#endif +#endif +#endif diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h new file mode 100644 index 00000000..278312c9 --- /dev/null +++ b/include/net/ip6_route.h @@ -0,0 +1,168 @@ +#ifndef _NET_IP6_ROUTE_H +#define _NET_IP6_ROUTE_H + +#define IP6_RT_PRIO_USER 1024 +#define IP6_RT_PRIO_ADDRCONF 256 +#define IP6_RT_PRIO_KERN 512 + +struct route_info { + __u8 type; + __u8 length; + __u8 prefix_len; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved_h:3, + route_pref:2, + reserved_l:3; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 reserved_l:3, + route_pref:2, + reserved_h:3; +#endif + __be32 lifetime; + __u8 prefix[0]; /* 0,8 or 16 */ +}; + +#ifdef __KERNEL__ + +#include <net/flow.h> +#include <net/ip6_fib.h> +#include <net/sock.h> +#include <linux/ip.h> +#include <linux/ipv6.h> + +#define RT6_LOOKUP_F_IFACE 0x00000001 +#define RT6_LOOKUP_F_REACHABLE 0x00000002 +#define RT6_LOOKUP_F_HAS_SADDR 0x00000004 +#define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008 +#define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010 +#define RT6_LOOKUP_F_SRCPREF_COA 0x00000020 + +/* + * rt6_srcprefs2flags() and rt6_flags2srcprefs() translate + * between IPV6_ADDR_PREFERENCES socket option values + * IPV6_PREFER_SRC_TMP = 0x1 + * IPV6_PREFER_SRC_PUBLIC = 0x2 + * IPV6_PREFER_SRC_COA = 0x4 + * and above RT6_LOOKUP_F_SRCPREF_xxx flags. + */ +static inline int rt6_srcprefs2flags(unsigned int srcprefs) +{ + /* No need to bitmask because srcprefs have only 3 bits. */ + return srcprefs << 3; +} + +static inline unsigned int rt6_flags2srcprefs(int flags) +{ + return (flags >> 3) & 7; +} + +extern void ip6_route_input(struct sk_buff *skb); + +extern struct dst_entry * ip6_route_output(struct net *net, + struct sock *sk, + struct flowi *fl); + +extern int ip6_route_init(void); +extern void ip6_route_cleanup(void); + +extern int ipv6_route_ioctl(struct net *net, + unsigned int cmd, + void __user *arg); + +extern int ip6_route_add(struct fib6_config *cfg); +extern int ip6_ins_rt(struct rt6_info *); +extern int ip6_del_rt(struct rt6_info *); + +extern struct rt6_info *rt6_lookup(struct net *net, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + int oif, int flags); + +extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev, + struct neighbour *neigh, + const struct in6_addr *addr); +extern int icmp6_dst_gc(void); + +extern void fib6_force_start_gc(struct net *net); + +extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, + const struct in6_addr *addr, + int anycast); + +extern int ip6_dst_hoplimit(struct dst_entry *dst); + +/* + * support functions for ND + * + */ +extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr, + struct net_device *dev); +extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, + struct net_device *dev, + unsigned int pref); + +extern void rt6_purge_dflt_routers(struct net *net); + +extern int rt6_route_rcv(struct net_device *dev, + u8 *opt, int len, + struct in6_addr *gwaddr); + +extern void rt6_redirect(struct in6_addr *dest, + struct in6_addr *src, + struct in6_addr *saddr, + struct neighbour *neigh, + u8 *lladdr, + int on_link); + +extern void rt6_pmtu_discovery(struct in6_addr *daddr, + struct in6_addr *saddr, + struct net_device *dev, + u32 pmtu); + +struct netlink_callback; + +struct rt6_rtnl_dump_arg { + struct sk_buff *skb; + struct netlink_callback *cb; + struct net *net; +}; + +extern int rt6_dump_route(struct rt6_info *rt, void *p_arg); +extern void rt6_ifdown(struct net *net, struct net_device *dev); +extern void rt6_mtu_change(struct net_device *dev, unsigned mtu); + + +/* + * Store a destination cache entry in a socket + */ +static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst, + struct in6_addr *daddr, struct in6_addr *saddr) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + struct rt6_info *rt = (struct rt6_info *) dst; + + sk_setup_caps(sk, dst); + np->daddr_cache = daddr; +#ifdef CONFIG_IPV6_SUBTREES + np->saddr_cache = saddr; +#endif + np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; +} + +static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, + struct in6_addr *daddr, struct in6_addr *saddr) +{ + spin_lock(&sk->sk_dst_lock); + __ip6_dst_store(sk, dst, daddr, saddr); + spin_unlock(&sk->sk_dst_lock); +} + +static inline int ipv6_unicast_destination(struct sk_buff *skb) +{ + struct rt6_info *rt = (struct rt6_info *) skb_dst(skb); + + return rt->rt6i_flags & RTF_LOCAL; +} + +#endif +#endif diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h new file mode 100644 index 00000000..fc94ec56 --- /dev/null +++ b/include/net/ip6_tunnel.h @@ -0,0 +1,32 @@ +#ifndef _NET_IP6_TUNNEL_H +#define _NET_IP6_TUNNEL_H + +#include <linux/ipv6.h> +#include <linux/netdevice.h> +#include <linux/ip6_tunnel.h> + +/* capable of sending packets */ +#define IP6_TNL_F_CAP_XMIT 0x10000 +/* capable of receiving packets */ +#define IP6_TNL_F_CAP_RCV 0x20000 + +/* IPv6 tunnel */ + +struct ip6_tnl { + struct ip6_tnl *next; /* next tunnel in list */ + struct net_device *dev; /* virtual device associated with tunnel */ + struct ip6_tnl_parm parms; /* tunnel configuration parameters */ + struct flowi fl; /* flowi template for xmit */ + struct dst_entry *dst_cache; /* cached dst */ + u32 dst_cookie; +}; + +/* Tunnel encapsulation limit destination sub-option */ + +struct ipv6_tlv_tnl_enc_lim { + __u8 type; /* type-code for option */ + __u8 length; /* option length */ + __u8 encap_limit; /* tunnel encapsulation limit */ +} __packed; + +#endif diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h new file mode 100644 index 00000000..c93f94ed --- /dev/null +++ b/include/net/ip_fib.h @@ -0,0 +1,280 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the Forwarding Information Base. + * + * Authors: A.N.Kuznetsov, <kuznet@ms2.inr.ac.ru> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _NET_IP_FIB_H +#define _NET_IP_FIB_H + +#include <net/flow.h> +#include <linux/seq_file.h> +#include <net/fib_rules.h> + +struct fib_config { + u8 fc_dst_len; + u8 fc_tos; + u8 fc_protocol; + u8 fc_scope; + u8 fc_type; + /* 3 bytes unused */ + u32 fc_table; + __be32 fc_dst; + __be32 fc_gw; + int fc_oif; + u32 fc_flags; + u32 fc_priority; + __be32 fc_prefsrc; + struct nlattr *fc_mx; + struct rtnexthop *fc_mp; + int fc_mx_len; + int fc_mp_len; + u32 fc_flow; + u32 fc_nlflags; + struct nl_info fc_nlinfo; + }; + +struct fib_info; + +struct fib_nh { + struct net_device *nh_dev; + struct hlist_node nh_hash; + struct fib_info *nh_parent; + unsigned nh_flags; + unsigned char nh_scope; +#ifdef CONFIG_IP_ROUTE_MULTIPATH + int nh_weight; + int nh_power; +#endif +#ifdef CONFIG_NET_CLS_ROUTE + __u32 nh_tclassid; +#endif + int nh_oif; + __be32 nh_gw; +}; + +/* + * This structure contains data shared by many of routes. + */ + +struct fib_info { + struct hlist_node fib_hash; + struct hlist_node fib_lhash; + struct net *fib_net; + int fib_treeref; + atomic_t fib_clntref; + int fib_dead; + unsigned fib_flags; + int fib_protocol; + __be32 fib_prefsrc; + u32 fib_priority; + u32 fib_metrics[RTAX_MAX]; +#define fib_mtu fib_metrics[RTAX_MTU-1] +#define fib_window fib_metrics[RTAX_WINDOW-1] +#define fib_rtt fib_metrics[RTAX_RTT-1] +#define fib_advmss fib_metrics[RTAX_ADVMSS-1] + int fib_nhs; +#ifdef CONFIG_IP_ROUTE_MULTIPATH + int fib_power; +#endif + struct fib_nh fib_nh[0]; +#define fib_dev fib_nh[0].nh_dev +}; + + +#ifdef CONFIG_IP_MULTIPLE_TABLES +struct fib_rule; +#endif + +struct fib_result { + unsigned char prefixlen; + unsigned char nh_sel; + unsigned char type; + unsigned char scope; + struct fib_info *fi; +#ifdef CONFIG_IP_MULTIPLE_TABLES + struct fib_rule *r; +#endif +}; + +struct fib_result_nl { + __be32 fl_addr; /* To be looked up*/ + u32 fl_mark; + unsigned char fl_tos; + unsigned char fl_scope; + unsigned char tb_id_in; + + unsigned char tb_id; /* Results */ + unsigned char prefixlen; + unsigned char nh_sel; + unsigned char type; + unsigned char scope; + int err; +}; + +#ifdef CONFIG_IP_ROUTE_MULTIPATH + +#define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel]) + +#define FIB_TABLE_HASHSZ 2 + +#else /* CONFIG_IP_ROUTE_MULTIPATH */ + +#define FIB_RES_NH(res) ((res).fi->fib_nh[0]) + +#define FIB_TABLE_HASHSZ 256 + +#endif /* CONFIG_IP_ROUTE_MULTIPATH */ + +#define FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __fib_res_prefsrc(&res)) +#define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw) +#define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev) +#define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif) + +struct fib_table { + struct hlist_node tb_hlist; + u32 tb_id; + int tb_default; + unsigned char tb_data[0]; +}; + +extern int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, + struct fib_result *res); +extern int fib_table_insert(struct fib_table *, struct fib_config *); +extern int fib_table_delete(struct fib_table *, struct fib_config *); +extern int fib_table_dump(struct fib_table *table, struct sk_buff *skb, + struct netlink_callback *cb); +extern int fib_table_flush(struct fib_table *table); +extern void fib_table_select_default(struct fib_table *table, + const struct flowi *flp, + struct fib_result *res); + + +#ifndef CONFIG_IP_MULTIPLE_TABLES + +#define TABLE_LOCAL_INDEX 0 +#define TABLE_MAIN_INDEX 1 + +static inline struct fib_table *fib_get_table(struct net *net, u32 id) +{ + struct hlist_head *ptr; + + ptr = id == RT_TABLE_LOCAL ? + &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] : + &net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]; + return hlist_entry(ptr->first, struct fib_table, tb_hlist); +} + +static inline struct fib_table *fib_new_table(struct net *net, u32 id) +{ + return fib_get_table(net, id); +} + +static inline int fib_lookup(struct net *net, const struct flowi *flp, + struct fib_result *res) +{ + struct fib_table *table; + + table = fib_get_table(net, RT_TABLE_LOCAL); + if (!fib_table_lookup(table, flp, res)) + return 0; + + table = fib_get_table(net, RT_TABLE_MAIN); + if (!fib_table_lookup(table, flp, res)) + return 0; + return -ENETUNREACH; +} + +#else /* CONFIG_IP_MULTIPLE_TABLES */ +extern int __net_init fib4_rules_init(struct net *net); +extern void __net_exit fib4_rules_exit(struct net *net); + +#ifdef CONFIG_NET_CLS_ROUTE +extern u32 fib_rules_tclass(struct fib_result *res); +#endif + +extern int fib_lookup(struct net *n, struct flowi *flp, struct fib_result *res); + +extern struct fib_table *fib_new_table(struct net *net, u32 id); +extern struct fib_table *fib_get_table(struct net *net, u32 id); + +#endif /* CONFIG_IP_MULTIPLE_TABLES */ + +/* Exported by fib_frontend.c */ +extern const struct nla_policy rtm_ipv4_policy[]; +extern void ip_fib_init(void); +extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, + struct net_device *dev, __be32 *spec_dst, + u32 *itag, u32 mark); +extern void fib_select_default(struct net *net, const struct flowi *flp, + struct fib_result *res); + +/* Exported by fib_semantics.c */ +extern int ip_fib_check_default(__be32 gw, struct net_device *dev); +extern int fib_sync_down_dev(struct net_device *dev, int force); +extern int fib_sync_down_addr(struct net *net, __be32 local); +extern int fib_sync_up(struct net_device *dev); +extern __be32 __fib_res_prefsrc(struct fib_result *res); +extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res); + +/* Exported by fib_{hash|trie}.c */ +extern void fib_hash_init(void); +extern struct fib_table *fib_hash_table(u32 id); + +static inline void fib_combine_itag(u32 *itag, struct fib_result *res) +{ +#ifdef CONFIG_NET_CLS_ROUTE +#ifdef CONFIG_IP_MULTIPLE_TABLES + u32 rtag; +#endif + *itag = FIB_RES_NH(*res).nh_tclassid<<16; +#ifdef CONFIG_IP_MULTIPLE_TABLES + rtag = fib_rules_tclass(res); + if (*itag == 0) + *itag = (rtag<<16); + *itag |= (rtag>>16); +#endif +#endif +} + +extern void free_fib_info(struct fib_info *fi); + +static inline void fib_info_put(struct fib_info *fi) +{ + if (atomic_dec_and_test(&fi->fib_clntref)) + free_fib_info(fi); +} + +static inline void fib_res_put(struct fib_result *res) +{ + if (res->fi) + fib_info_put(res->fi); +#ifdef CONFIG_IP_MULTIPLE_TABLES + if (res->r) + fib_rule_put(res->r); +#endif +} + +#ifdef CONFIG_PROC_FS +extern int __net_init fib_proc_init(struct net *net); +extern void __net_exit fib_proc_exit(struct net *net); +#else +static inline int fib_proc_init(struct net *net) +{ + return 0; +} +static inline void fib_proc_exit(struct net *net) +{ +} +#endif + +#endif /* _NET_FIB_H */ diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h new file mode 100644 index 00000000..f976885f --- /dev/null +++ b/include/net/ip_vs.h @@ -0,0 +1,963 @@ +/* + * IP Virtual Server + * data structure and functionality definitions + */ + +#ifndef _NET_IP_VS_H +#define _NET_IP_VS_H + +#include <linux/ip_vs.h> /* definitions shared with userland */ + +/* old ipvsadm versions still include this file directly */ +#ifdef __KERNEL__ + +#include <asm/types.h> /* for __uXX types */ + +#include <linux/sysctl.h> /* for ctl_path */ +#include <linux/list.h> /* for struct list_head */ +#include <linux/spinlock.h> /* for struct rwlock_t */ +#include <asm/atomic.h> /* for struct atomic_t */ +#include <linux/compiler.h> +#include <linux/timer.h> + +#include <net/checksum.h> +#include <linux/netfilter.h> /* for union nf_inet_addr */ +#include <linux/ip.h> +#include <linux/ipv6.h> /* for struct ipv6hdr */ +#include <net/ipv6.h> /* for ipv6_addr_copy */ + + +/* Connections' size value needed by ip_vs_ctl.c */ +extern int ip_vs_conn_tab_size; + + +struct ip_vs_iphdr { + int len; + __u8 protocol; + union nf_inet_addr saddr; + union nf_inet_addr daddr; +}; + +static inline void +ip_vs_fill_iphdr(int af, const void *nh, struct ip_vs_iphdr *iphdr) +{ +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) { + const struct ipv6hdr *iph = nh; + iphdr->len = sizeof(struct ipv6hdr); + iphdr->protocol = iph->nexthdr; + ipv6_addr_copy(&iphdr->saddr.in6, &iph->saddr); + ipv6_addr_copy(&iphdr->daddr.in6, &iph->daddr); + } else +#endif + { + const struct iphdr *iph = nh; + iphdr->len = iph->ihl * 4; + iphdr->protocol = iph->protocol; + iphdr->saddr.ip = iph->saddr; + iphdr->daddr.ip = iph->daddr; + } +} + +static inline void ip_vs_addr_copy(int af, union nf_inet_addr *dst, + const union nf_inet_addr *src) +{ +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) + ipv6_addr_copy(&dst->in6, &src->in6); + else +#endif + dst->ip = src->ip; +} + +static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a, + const union nf_inet_addr *b) +{ +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) + return ipv6_addr_equal(&a->in6, &b->in6); +#endif + return a->ip == b->ip; +} + +#ifdef CONFIG_IP_VS_DEBUG +#include <linux/net.h> + +extern int ip_vs_get_debug_level(void); + +static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len, + const union nf_inet_addr *addr, + int *idx) +{ + int len; +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) + len = snprintf(&buf[*idx], buf_len - *idx, "[%pI6]", + &addr->in6) + 1; + else +#endif + len = snprintf(&buf[*idx], buf_len - *idx, "%pI4", + &addr->ip) + 1; + + *idx += len; + BUG_ON(*idx > buf_len + 1); + return &buf[*idx - len]; +} + +#define IP_VS_DBG_BUF(level, msg, ...) \ + do { \ + char ip_vs_dbg_buf[160]; \ + int ip_vs_dbg_idx = 0; \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \ + } while (0) +#define IP_VS_ERR_BUF(msg...) \ + do { \ + char ip_vs_dbg_buf[160]; \ + int ip_vs_dbg_idx = 0; \ + pr_err(msg); \ + } while (0) + +/* Only use from within IP_VS_DBG_BUF() or IP_VS_ERR_BUF macros */ +#define IP_VS_DBG_ADDR(af, addr) \ + ip_vs_dbg_addr(af, ip_vs_dbg_buf, \ + sizeof(ip_vs_dbg_buf), addr, \ + &ip_vs_dbg_idx) + +#define IP_VS_DBG(level, msg, ...) \ + do { \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \ + } while (0) +#define IP_VS_DBG_RL(msg, ...) \ + do { \ + if (net_ratelimit()) \ + printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \ + } while (0) +#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) \ + do { \ + if (level <= ip_vs_get_debug_level()) \ + pp->debug_packet(pp, skb, ofs, msg); \ + } while (0) +#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) \ + do { \ + if (level <= ip_vs_get_debug_level() && \ + net_ratelimit()) \ + pp->debug_packet(pp, skb, ofs, msg); \ + } while (0) +#else /* NO DEBUGGING at ALL */ +#define IP_VS_DBG_BUF(level, msg...) do {} while (0) +#define IP_VS_ERR_BUF(msg...) do {} while (0) +#define IP_VS_DBG(level, msg...) do {} while (0) +#define IP_VS_DBG_RL(msg...) do {} while (0) +#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) do {} while (0) +#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) do {} while (0) +#endif + +#define IP_VS_BUG() BUG() +#define IP_VS_ERR_RL(msg, ...) \ + do { \ + if (net_ratelimit()) \ + pr_err(msg, ##__VA_ARGS__); \ + } while (0) + +#ifdef CONFIG_IP_VS_DEBUG +#define EnterFunction(level) \ + do { \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG \ + pr_fmt("Enter: %s, %s line %i\n"), \ + __func__, __FILE__, __LINE__); \ + } while (0) +#define LeaveFunction(level) \ + do { \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG \ + pr_fmt("Leave: %s, %s line %i\n"), \ + __func__, __FILE__, __LINE__); \ + } while (0) +#else +#define EnterFunction(level) do {} while (0) +#define LeaveFunction(level) do {} while (0) +#endif + +#define IP_VS_WAIT_WHILE(expr) while (expr) { cpu_relax(); } + + +/* + * The port number of FTP service (in network order). + */ +#define FTPPORT cpu_to_be16(21) +#define FTPDATA cpu_to_be16(20) + +/* + * TCP State Values + */ +enum { + IP_VS_TCP_S_NONE = 0, + IP_VS_TCP_S_ESTABLISHED, + IP_VS_TCP_S_SYN_SENT, + IP_VS_TCP_S_SYN_RECV, + IP_VS_TCP_S_FIN_WAIT, + IP_VS_TCP_S_TIME_WAIT, + IP_VS_TCP_S_CLOSE, + IP_VS_TCP_S_CLOSE_WAIT, + IP_VS_TCP_S_LAST_ACK, + IP_VS_TCP_S_LISTEN, + IP_VS_TCP_S_SYNACK, + IP_VS_TCP_S_LAST +}; + +/* + * UDP State Values + */ +enum { + IP_VS_UDP_S_NORMAL, + IP_VS_UDP_S_LAST, +}; + +/* + * ICMP State Values + */ +enum { + IP_VS_ICMP_S_NORMAL, + IP_VS_ICMP_S_LAST, +}; + +/* + * SCTP State Values + */ +enum ip_vs_sctp_states { + IP_VS_SCTP_S_NONE, + IP_VS_SCTP_S_INIT_CLI, + IP_VS_SCTP_S_INIT_SER, + IP_VS_SCTP_S_INIT_ACK_CLI, + IP_VS_SCTP_S_INIT_ACK_SER, + IP_VS_SCTP_S_ECHO_CLI, + IP_VS_SCTP_S_ECHO_SER, + IP_VS_SCTP_S_ESTABLISHED, + IP_VS_SCTP_S_SHUT_CLI, + IP_VS_SCTP_S_SHUT_SER, + IP_VS_SCTP_S_SHUT_ACK_CLI, + IP_VS_SCTP_S_SHUT_ACK_SER, + IP_VS_SCTP_S_CLOSED, + IP_VS_SCTP_S_LAST +}; + +/* + * Delta sequence info structure + * Each ip_vs_conn has 2 (output AND input seq. changes). + * Only used in the VS/NAT. + */ +struct ip_vs_seq { + __u32 init_seq; /* Add delta from this seq */ + __u32 delta; /* Delta in sequence numbers */ + __u32 previous_delta; /* Delta in sequence numbers + before last resized pkt */ +}; + + +/* + * IPVS statistics objects + */ +struct ip_vs_estimator { + struct list_head list; + + u64 last_inbytes; + u64 last_outbytes; + u32 last_conns; + u32 last_inpkts; + u32 last_outpkts; + + u32 cps; + u32 inpps; + u32 outpps; + u32 inbps; + u32 outbps; +}; + +struct ip_vs_stats { + struct ip_vs_stats_user ustats; /* statistics */ + struct ip_vs_estimator est; /* estimator */ + + spinlock_t lock; /* spin lock */ +}; + +struct dst_entry; +struct iphdr; +struct ip_vs_conn; +struct ip_vs_app; +struct sk_buff; + +struct ip_vs_protocol { + struct ip_vs_protocol *next; + char *name; + u16 protocol; + u16 num_states; + int dont_defrag; + atomic_t appcnt; /* counter of proto app incs */ + int *timeout_table; /* protocol timeout table */ + + void (*init)(struct ip_vs_protocol *pp); + + void (*exit)(struct ip_vs_protocol *pp); + + int (*conn_schedule)(int af, struct sk_buff *skb, + struct ip_vs_protocol *pp, + int *verdict, struct ip_vs_conn **cpp); + + struct ip_vs_conn * + (*conn_in_get)(int af, + const struct sk_buff *skb, + struct ip_vs_protocol *pp, + const struct ip_vs_iphdr *iph, + unsigned int proto_off, + int inverse); + + struct ip_vs_conn * + (*conn_out_get)(int af, + const struct sk_buff *skb, + struct ip_vs_protocol *pp, + const struct ip_vs_iphdr *iph, + unsigned int proto_off, + int inverse); + + int (*snat_handler)(struct sk_buff *skb, + struct ip_vs_protocol *pp, struct ip_vs_conn *cp); + + int (*dnat_handler)(struct sk_buff *skb, + struct ip_vs_protocol *pp, struct ip_vs_conn *cp); + + int (*csum_check)(int af, struct sk_buff *skb, + struct ip_vs_protocol *pp); + + const char *(*state_name)(int state); + + int (*state_transition)(struct ip_vs_conn *cp, int direction, + const struct sk_buff *skb, + struct ip_vs_protocol *pp); + + int (*register_app)(struct ip_vs_app *inc); + + void (*unregister_app)(struct ip_vs_app *inc); + + int (*app_conn_bind)(struct ip_vs_conn *cp); + + void (*debug_packet)(struct ip_vs_protocol *pp, + const struct sk_buff *skb, + int offset, + const char *msg); + + void (*timeout_change)(struct ip_vs_protocol *pp, int flags); + + int (*set_state_timeout)(struct ip_vs_protocol *pp, char *sname, int to); +}; + +extern struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto); + +/* + * IP_VS structure allocated for each dynamically scheduled connection + */ +struct ip_vs_conn { + struct list_head c_list; /* hashed list heads */ + + /* Protocol, addresses and port numbers */ + u16 af; /* address family */ + union nf_inet_addr caddr; /* client address */ + union nf_inet_addr vaddr; /* virtual address */ + union nf_inet_addr daddr; /* destination address */ + __be16 cport; + __be16 vport; + __be16 dport; + __u16 protocol; /* Which protocol (TCP/UDP) */ + + /* counter and timer */ + atomic_t refcnt; /* reference count */ + struct timer_list timer; /* Expiration timer */ + volatile unsigned long timeout; /* timeout */ + + /* Flags and state transition */ + spinlock_t lock; /* lock for state transition */ + volatile __u16 flags; /* status flags */ + volatile __u16 state; /* state info */ + volatile __u16 old_state; /* old state, to be used for + * state transition triggerd + * synchronization + */ + + /* Control members */ + struct ip_vs_conn *control; /* Master control connection */ + atomic_t n_control; /* Number of controlled ones */ + struct ip_vs_dest *dest; /* real server */ + atomic_t in_pkts; /* incoming packet counter */ + + /* packet transmitter for different forwarding methods. If it + mangles the packet, it must return NF_DROP or better NF_STOLEN, + otherwise this must be changed to a sk_buff **. + */ + int (*packet_xmit)(struct sk_buff *skb, struct ip_vs_conn *cp, + struct ip_vs_protocol *pp); + + /* Note: we can group the following members into a structure, + in order to save more space, and the following members are + only used in VS/NAT anyway */ + struct ip_vs_app *app; /* bound ip_vs_app object */ + void *app_data; /* Application private data */ + struct ip_vs_seq in_seq; /* incoming seq. struct */ + struct ip_vs_seq out_seq; /* outgoing seq. struct */ +}; + + +/* + * Extended internal versions of struct ip_vs_service_user and + * ip_vs_dest_user for IPv6 support. + * + * We need these to conveniently pass around service and destination + * options, but unfortunately, we also need to keep the old definitions to + * maintain userspace backwards compatibility for the setsockopt interface. + */ +struct ip_vs_service_user_kern { + /* virtual service addresses */ + u16 af; + u16 protocol; + union nf_inet_addr addr; /* virtual ip address */ + u16 port; + u32 fwmark; /* firwall mark of service */ + + /* virtual service options */ + char *sched_name; + unsigned flags; /* virtual service flags */ + unsigned timeout; /* persistent timeout in sec */ + u32 netmask; /* persistent netmask */ +}; + + +struct ip_vs_dest_user_kern { + /* destination server address */ + union nf_inet_addr addr; + u16 port; + + /* real server options */ + unsigned conn_flags; /* connection flags */ + int weight; /* destination weight */ + + /* thresholds for active connections */ + u32 u_threshold; /* upper threshold */ + u32 l_threshold; /* lower threshold */ +}; + + +/* + * The information about the virtual service offered to the net + * and the forwarding entries + */ +struct ip_vs_service { + struct list_head s_list; /* for normal service table */ + struct list_head f_list; /* for fwmark-based service table */ + atomic_t refcnt; /* reference counter */ + atomic_t usecnt; /* use counter */ + + u16 af; /* address family */ + __u16 protocol; /* which protocol (TCP/UDP) */ + union nf_inet_addr addr; /* IP address for virtual service */ + __be16 port; /* port number for the service */ + __u32 fwmark; /* firewall mark of the service */ + unsigned flags; /* service status flags */ + unsigned timeout; /* persistent timeout in ticks */ + __be32 netmask; /* grouping granularity */ + + struct list_head destinations; /* real server d-linked list */ + __u32 num_dests; /* number of servers */ + struct ip_vs_stats stats; /* statistics for the service */ + struct ip_vs_app *inc; /* bind conns to this app inc */ + + /* for scheduling */ + struct ip_vs_scheduler *scheduler; /* bound scheduler object */ + rwlock_t sched_lock; /* lock sched_data */ + void *sched_data; /* scheduler application data */ +}; + + +/* + * The real server destination forwarding entry + * with ip address, port number, and so on. + */ +struct ip_vs_dest { + struct list_head n_list; /* for the dests in the service */ + struct list_head d_list; /* for table with all the dests */ + + u16 af; /* address family */ + union nf_inet_addr addr; /* IP address of the server */ + __be16 port; /* port number of the server */ + volatile unsigned flags; /* dest status flags */ + atomic_t conn_flags; /* flags to copy to conn */ + atomic_t weight; /* server weight */ + + atomic_t refcnt; /* reference counter */ + struct ip_vs_stats stats; /* statistics */ + + /* connection counters and thresholds */ + atomic_t activeconns; /* active connections */ + atomic_t inactconns; /* inactive connections */ + atomic_t persistconns; /* persistent connections */ + __u32 u_threshold; /* upper threshold */ + __u32 l_threshold; /* lower threshold */ + + /* for destination cache */ + spinlock_t dst_lock; /* lock of dst_cache */ + struct dst_entry *dst_cache; /* destination cache entry */ + u32 dst_rtos; /* RT_TOS(tos) for dst */ + + /* for virtual service */ + struct ip_vs_service *svc; /* service it belongs to */ + __u16 protocol; /* which protocol (TCP/UDP) */ + union nf_inet_addr vaddr; /* virtual IP address */ + __be16 vport; /* virtual port number */ + __u32 vfwmark; /* firewall mark of service */ +}; + + +/* + * The scheduler object + */ +struct ip_vs_scheduler { + struct list_head n_list; /* d-linked list head */ + char *name; /* scheduler name */ + atomic_t refcnt; /* reference counter */ + struct module *module; /* THIS_MODULE/NULL */ + + /* scheduler initializing service */ + int (*init_service)(struct ip_vs_service *svc); + /* scheduling service finish */ + int (*done_service)(struct ip_vs_service *svc); + /* scheduler updating service */ + int (*update_service)(struct ip_vs_service *svc); + + /* selecting a server from the given service */ + struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc, + const struct sk_buff *skb); +}; + + +/* + * The application module object (a.k.a. app incarnation) + */ +struct ip_vs_app { + struct list_head a_list; /* member in app list */ + int type; /* IP_VS_APP_TYPE_xxx */ + char *name; /* application module name */ + __u16 protocol; + struct module *module; /* THIS_MODULE/NULL */ + struct list_head incs_list; /* list of incarnations */ + + /* members for application incarnations */ + struct list_head p_list; /* member in proto app list */ + struct ip_vs_app *app; /* its real application */ + __be16 port; /* port number in net order */ + atomic_t usecnt; /* usage counter */ + + /* output hook: return false if can't linearize. diff set for TCP. */ + int (*pkt_out)(struct ip_vs_app *, struct ip_vs_conn *, + struct sk_buff *, int *diff); + + /* input hook: return false if can't linearize. diff set for TCP. */ + int (*pkt_in)(struct ip_vs_app *, struct ip_vs_conn *, + struct sk_buff *, int *diff); + + /* ip_vs_app initializer */ + int (*init_conn)(struct ip_vs_app *, struct ip_vs_conn *); + + /* ip_vs_app finish */ + int (*done_conn)(struct ip_vs_app *, struct ip_vs_conn *); + + + /* not used now */ + int (*bind_conn)(struct ip_vs_app *, struct ip_vs_conn *, + struct ip_vs_protocol *); + + void (*unbind_conn)(struct ip_vs_app *, struct ip_vs_conn *); + + int * timeout_table; + int * timeouts; + int timeouts_size; + + int (*conn_schedule)(struct sk_buff *skb, struct ip_vs_app *app, + int *verdict, struct ip_vs_conn **cpp); + + struct ip_vs_conn * + (*conn_in_get)(const struct sk_buff *skb, struct ip_vs_app *app, + const struct iphdr *iph, unsigned int proto_off, + int inverse); + + struct ip_vs_conn * + (*conn_out_get)(const struct sk_buff *skb, struct ip_vs_app *app, + const struct iphdr *iph, unsigned int proto_off, + int inverse); + + int (*state_transition)(struct ip_vs_conn *cp, int direction, + const struct sk_buff *skb, + struct ip_vs_app *app); + + void (*timeout_change)(struct ip_vs_app *app, int flags); +}; + + +/* + * IPVS core functions + * (from ip_vs_core.c) + */ +extern const char *ip_vs_proto_name(unsigned proto); +extern void ip_vs_init_hash_table(struct list_head *table, int rows); +#define IP_VS_INIT_HASH_TABLE(t) ip_vs_init_hash_table((t), ARRAY_SIZE((t))) + +#define IP_VS_APP_TYPE_FTP 1 + +/* + * ip_vs_conn handling functions + * (from ip_vs_conn.c) + */ + +enum { + IP_VS_DIR_INPUT = 0, + IP_VS_DIR_OUTPUT, + IP_VS_DIR_INPUT_ONLY, + IP_VS_DIR_LAST, +}; + +extern struct ip_vs_conn *ip_vs_conn_in_get +(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port, + const union nf_inet_addr *d_addr, __be16 d_port); + +extern struct ip_vs_conn *ip_vs_ct_in_get +(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port, + const union nf_inet_addr *d_addr, __be16 d_port); + +struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb, + struct ip_vs_protocol *pp, + const struct ip_vs_iphdr *iph, + unsigned int proto_off, + int inverse); + +extern struct ip_vs_conn *ip_vs_conn_out_get +(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port, + const union nf_inet_addr *d_addr, __be16 d_port); + +struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb, + struct ip_vs_protocol *pp, + const struct ip_vs_iphdr *iph, + unsigned int proto_off, + int inverse); + +/* put back the conn without restarting its timer */ +static inline void __ip_vs_conn_put(struct ip_vs_conn *cp) +{ + atomic_dec(&cp->refcnt); +} +extern void ip_vs_conn_put(struct ip_vs_conn *cp); +extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport); + +extern struct ip_vs_conn * +ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport, + const union nf_inet_addr *vaddr, __be16 vport, + const union nf_inet_addr *daddr, __be16 dport, unsigned flags, + struct ip_vs_dest *dest); +extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp); + +extern const char * ip_vs_state_name(__u16 proto, int state); + +extern void ip_vs_tcp_conn_listen(struct ip_vs_conn *cp); +extern int ip_vs_check_template(struct ip_vs_conn *ct); +extern void ip_vs_random_dropentry(void); +extern int ip_vs_conn_init(void); +extern void ip_vs_conn_cleanup(void); + +static inline void ip_vs_control_del(struct ip_vs_conn *cp) +{ + struct ip_vs_conn *ctl_cp = cp->control; + if (!ctl_cp) { + IP_VS_ERR_BUF("request control DEL for uncontrolled: " + "%s:%d to %s:%d\n", + IP_VS_DBG_ADDR(cp->af, &cp->caddr), + ntohs(cp->cport), + IP_VS_DBG_ADDR(cp->af, &cp->vaddr), + ntohs(cp->vport)); + + return; + } + + IP_VS_DBG_BUF(7, "DELeting control for: " + "cp.dst=%s:%d ctl_cp.dst=%s:%d\n", + IP_VS_DBG_ADDR(cp->af, &cp->caddr), + ntohs(cp->cport), + IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr), + ntohs(ctl_cp->cport)); + + cp->control = NULL; + if (atomic_read(&ctl_cp->n_control) == 0) { + IP_VS_ERR_BUF("BUG control DEL with n=0 : " + "%s:%d to %s:%d\n", + IP_VS_DBG_ADDR(cp->af, &cp->caddr), + ntohs(cp->cport), + IP_VS_DBG_ADDR(cp->af, &cp->vaddr), + ntohs(cp->vport)); + + return; + } + atomic_dec(&ctl_cp->n_control); +} + +static inline void +ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp) +{ + if (cp->control) { + IP_VS_ERR_BUF("request control ADD for already controlled: " + "%s:%d to %s:%d\n", + IP_VS_DBG_ADDR(cp->af, &cp->caddr), + ntohs(cp->cport), + IP_VS_DBG_ADDR(cp->af, &cp->vaddr), + ntohs(cp->vport)); + + ip_vs_control_del(cp); + } + + IP_VS_DBG_BUF(7, "ADDing control for: " + "cp.dst=%s:%d ctl_cp.dst=%s:%d\n", + IP_VS_DBG_ADDR(cp->af, &cp->caddr), + ntohs(cp->cport), + IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr), + ntohs(ctl_cp->cport)); + + cp->control = ctl_cp; + atomic_inc(&ctl_cp->n_control); +} + + +/* + * IPVS application functions + * (from ip_vs_app.c) + */ +#define IP_VS_APP_MAX_PORTS 8 +extern int register_ip_vs_app(struct ip_vs_app *app); +extern void unregister_ip_vs_app(struct ip_vs_app *app); +extern int ip_vs_bind_app(struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern void ip_vs_unbind_app(struct ip_vs_conn *cp); +extern int +register_ip_vs_app_inc(struct ip_vs_app *app, __u16 proto, __u16 port); +extern int ip_vs_app_inc_get(struct ip_vs_app *inc); +extern void ip_vs_app_inc_put(struct ip_vs_app *inc); + +extern int ip_vs_app_pkt_out(struct ip_vs_conn *, struct sk_buff *skb); +extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff *skb); +extern int ip_vs_app_init(void); +extern void ip_vs_app_cleanup(void); + + +/* + * IPVS protocol functions (from ip_vs_proto.c) + */ +extern int ip_vs_protocol_init(void); +extern void ip_vs_protocol_cleanup(void); +extern void ip_vs_protocol_timeout_change(int flags); +extern int *ip_vs_create_timeout_table(int *table, int size); +extern int +ip_vs_set_state_timeout(int *table, int num, const char *const *names, + const char *name, int to); +extern void +ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb, + int offset, const char *msg); + +extern struct ip_vs_protocol ip_vs_protocol_tcp; +extern struct ip_vs_protocol ip_vs_protocol_udp; +extern struct ip_vs_protocol ip_vs_protocol_icmp; +extern struct ip_vs_protocol ip_vs_protocol_esp; +extern struct ip_vs_protocol ip_vs_protocol_ah; +extern struct ip_vs_protocol ip_vs_protocol_sctp; + +/* + * Registering/unregistering scheduler functions + * (from ip_vs_sched.c) + */ +extern int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); +extern int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler); +extern int ip_vs_bind_scheduler(struct ip_vs_service *svc, + struct ip_vs_scheduler *scheduler); +extern int ip_vs_unbind_scheduler(struct ip_vs_service *svc); +extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); +extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); +extern struct ip_vs_conn * +ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb); +extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, + struct ip_vs_protocol *pp); + + +/* + * IPVS control data and functions (from ip_vs_ctl.c) + */ +extern int sysctl_ip_vs_cache_bypass; +extern int sysctl_ip_vs_expire_nodest_conn; +extern int sysctl_ip_vs_expire_quiescent_template; +extern int sysctl_ip_vs_sync_threshold[2]; +extern int sysctl_ip_vs_nat_icmp_send; +extern struct ip_vs_stats ip_vs_stats; +extern const struct ctl_path net_vs_ctl_path[]; + +extern struct ip_vs_service * +ip_vs_service_get(int af, __u32 fwmark, __u16 protocol, + const union nf_inet_addr *vaddr, __be16 vport); + +static inline void ip_vs_service_put(struct ip_vs_service *svc) +{ + atomic_dec(&svc->usecnt); +} + +extern struct ip_vs_dest * +ip_vs_lookup_real_service(int af, __u16 protocol, + const union nf_inet_addr *daddr, __be16 dport); + +extern int ip_vs_use_count_inc(void); +extern void ip_vs_use_count_dec(void); +extern int ip_vs_control_init(void); +extern void ip_vs_control_cleanup(void); +extern struct ip_vs_dest * +ip_vs_find_dest(int af, const union nf_inet_addr *daddr, __be16 dport, + const union nf_inet_addr *vaddr, __be16 vport, __u16 protocol); +extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp); + + +/* + * IPVS sync daemon data and function prototypes + * (from ip_vs_sync.c) + */ +extern volatile int ip_vs_sync_state; +extern volatile int ip_vs_master_syncid; +extern volatile int ip_vs_backup_syncid; +extern char ip_vs_master_mcast_ifn[IP_VS_IFNAME_MAXLEN]; +extern char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; +extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid); +extern int stop_sync_thread(int state); +extern void ip_vs_sync_conn(struct ip_vs_conn *cp); + + +/* + * IPVS rate estimator prototypes (from ip_vs_est.c) + */ +extern int ip_vs_estimator_init(void); +extern void ip_vs_estimator_cleanup(void); +extern void ip_vs_new_estimator(struct ip_vs_stats *stats); +extern void ip_vs_kill_estimator(struct ip_vs_stats *stats); +extern void ip_vs_zero_estimator(struct ip_vs_stats *stats); + +/* + * Various IPVS packet transmitters (from ip_vs_xmit.c) + */ +extern int ip_vs_null_xmit +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_bypass_xmit +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_nat_xmit +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_tunnel_xmit +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_dr_xmit +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_icmp_xmit +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset); +extern void ip_vs_dst_reset(struct ip_vs_dest *dest); + +#ifdef CONFIG_IP_VS_IPV6 +extern int ip_vs_bypass_xmit_v6 +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_nat_xmit_v6 +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_tunnel_xmit_v6 +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_dr_xmit_v6 +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); +extern int ip_vs_icmp_xmit_v6 +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, + int offset); +#endif + +/* + * This is a simple mechanism to ignore packets when + * we are loaded. Just set ip_vs_drop_rate to 'n' and + * we start to drop 1/rate of the packets + */ +extern int ip_vs_drop_rate; +extern int ip_vs_drop_counter; + +static __inline__ int ip_vs_todrop(void) +{ + if (!ip_vs_drop_rate) return 0; + if (--ip_vs_drop_counter > 0) return 0; + ip_vs_drop_counter = ip_vs_drop_rate; + return 1; +} + +/* + * ip_vs_fwd_tag returns the forwarding tag of the connection + */ +#define IP_VS_FWD_METHOD(cp) (cp->flags & IP_VS_CONN_F_FWD_MASK) + +static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp) +{ + char fwd; + + switch (IP_VS_FWD_METHOD(cp)) { + case IP_VS_CONN_F_MASQ: + fwd = 'M'; break; + case IP_VS_CONN_F_LOCALNODE: + fwd = 'L'; break; + case IP_VS_CONN_F_TUNNEL: + fwd = 'T'; break; + case IP_VS_CONN_F_DROUTE: + fwd = 'R'; break; + case IP_VS_CONN_F_BYPASS: + fwd = 'B'; break; + default: + fwd = '?'; break; + } + return fwd; +} + +extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp, + struct ip_vs_conn *cp, int dir); + +#ifdef CONFIG_IP_VS_IPV6 +extern void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp, + struct ip_vs_conn *cp, int dir); +#endif + +extern __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset); + +static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum) +{ + __be32 diff[2] = { ~old, new }; + + return csum_partial(diff, sizeof(diff), oldsum); +} + +#ifdef CONFIG_IP_VS_IPV6 +static inline __wsum ip_vs_check_diff16(const __be32 *old, const __be32 *new, + __wsum oldsum) +{ + __be32 diff[8] = { ~old[3], ~old[2], ~old[1], ~old[0], + new[3], new[2], new[1], new[0] }; + + return csum_partial(diff, sizeof(diff), oldsum); +} +#endif + +static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum) +{ + __be16 diff[2] = { ~old, new }; + + return csum_partial(diff, sizeof(diff), oldsum); +} + +extern void ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, + int outin); + +#endif /* __KERNEL__ */ + +#endif /* _NET_IP_VS_H */ diff --git a/include/net/ipcomp.h b/include/net/ipcomp.h new file mode 100644 index 00000000..cc4f30cd --- /dev/null +++ b/include/net/ipcomp.h @@ -0,0 +1,29 @@ +#ifndef _NET_IPCOMP_H +#define _NET_IPCOMP_H + +#include <linux/types.h> + +#define IPCOMP_SCRATCH_SIZE 65400 + +struct crypto_comp; + +struct ipcomp_data { + u16 threshold; + struct crypto_comp * __percpu *tfms; +}; + +struct ip_comp_hdr; +struct sk_buff; +struct xfrm_state; + +int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb); +int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb); +void ipcomp_destroy(struct xfrm_state *x); +int ipcomp_init_state(struct xfrm_state *x); + +static inline struct ip_comp_hdr *ip_comp_hdr(const struct sk_buff *skb) +{ + return (struct ip_comp_hdr *)skb_transport_header(skb); +} + +#endif diff --git a/include/net/ipconfig.h b/include/net/ipconfig.h new file mode 100644 index 00000000..c74cc1bd --- /dev/null +++ b/include/net/ipconfig.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 1997 Martin Mares + * + * Automatic IP Layer Configuration + */ + +/* The following are initdata: */ + +extern int ic_proto_enabled; /* Protocols enabled (see IC_xxx) */ +extern int ic_set_manually; /* IPconfig parameters set manually */ + +extern __be32 ic_myaddr; /* My IP address */ +extern __be32 ic_gateway; /* Gateway IP address */ + +extern __be32 ic_servaddr; /* Boot server IP address */ + +extern __be32 root_server_addr; /* Address of NFS server */ +extern u8 root_server_path[]; /* Path to mount as root */ + + +/* bits in ic_proto_{enabled,used} */ +#define IC_PROTO 0xFF /* Protocols mask: */ +#define IC_BOOTP 0x01 /* BOOTP (or DHCP, see below) */ +#define IC_RARP 0x02 /* RARP */ +#define IC_USE_DHCP 0x100 /* If on, use DHCP instead of BOOTP */ diff --git a/include/net/ipip.h b/include/net/ipip.h new file mode 100644 index 00000000..65caea8b --- /dev/null +++ b/include/net/ipip.h @@ -0,0 +1,65 @@ +#ifndef __NET_IPIP_H +#define __NET_IPIP_H 1 + +#include <linux/if_tunnel.h> +#include <net/ip.h> + +/* Keep error state on tunnel for 30 sec */ +#define IPTUNNEL_ERR_TIMEO (30*HZ) + +/* 6rd prefix/relay information */ +struct ip_tunnel_6rd_parm { + struct in6_addr prefix; + __be32 relay_prefix; + u16 prefixlen; + u16 relay_prefixlen; +}; + +struct ip_tunnel { + struct ip_tunnel *next; + struct net_device *dev; + + int err_count; /* Number of arrived ICMP errors */ + unsigned long err_time; /* Time when the last ICMP error arrived */ + + /* These four fields used only by GRE */ + __u32 i_seqno; /* The last seen seqno */ + __u32 o_seqno; /* The last output seqno */ + int hlen; /* Precalculated GRE header length */ + int mlink; + + struct ip_tunnel_parm parms; + + /* for SIT */ +#ifdef CONFIG_IPV6_SIT_6RD + struct ip_tunnel_6rd_parm ip6rd; +#endif + struct ip_tunnel_prl_entry *prl; /* potential router list */ + unsigned int prl_count; /* # of entries in PRL */ +}; + +struct ip_tunnel_prl_entry { + struct ip_tunnel_prl_entry *next; + __be32 addr; + u16 flags; + struct rcu_head rcu_head; +}; + +#define IPTUNNEL_XMIT() do { \ + int err; \ + int pkt_len = skb->len - skb_transport_offset(skb); \ + \ + skb->ip_summed = CHECKSUM_NONE; \ + ip_select_ident(iph, &rt->dst, NULL); \ + \ + err = ip_local_out(skb); \ + if (likely(net_xmit_eval(err) == 0)) { \ + txq->tx_bytes += pkt_len; \ + txq->tx_packets++; \ + } else { \ + stats->tx_errors++; \ + stats->tx_aborted_errors++; \ + } \ +} while (0) + +#endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h new file mode 100644 index 00000000..1f841241 --- /dev/null +++ b/include/net/ipv6.h @@ -0,0 +1,656 @@ +/* + * Linux INET6 implementation + * + * Authors: + * Pedro Roque <roque@di.fc.ul.pt> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _NET_IPV6_H +#define _NET_IPV6_H + +#include <linux/ipv6.h> +#include <linux/hardirq.h> +#include <net/if_inet6.h> +#include <net/ndisc.h> +#include <net/flow.h> +#include <net/snmp.h> + +#define SIN6_LEN_RFC2133 24 + +#define IPV6_MAXPLEN 65535 + +/* + * NextHeader field of IPv6 header + */ + +#define NEXTHDR_HOP 0 /* Hop-by-hop option header. */ +#define NEXTHDR_TCP 6 /* TCP segment. */ +#define NEXTHDR_UDP 17 /* UDP message. */ +#define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */ +#define NEXTHDR_ROUTING 43 /* Routing header. */ +#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */ +#define NEXTHDR_ESP 50 /* Encapsulating security payload. */ +#define NEXTHDR_AUTH 51 /* Authentication header. */ +#define NEXTHDR_ICMP 58 /* ICMP for IPv6. */ +#define NEXTHDR_NONE 59 /* No next header */ +#define NEXTHDR_DEST 60 /* Destination options header. */ +#define NEXTHDR_MOBILITY 135 /* Mobility header. */ + +#define NEXTHDR_MAX 255 + + + +#define IPV6_DEFAULT_HOPLIMIT 64 +#define IPV6_DEFAULT_MCASTHOPS 1 + +/* + * Addr type + * + * type - unicast | multicast + * scope - local | site | global + * v4 - compat + * v4mapped + * any + * loopback + */ + +#define IPV6_ADDR_ANY 0x0000U + +#define IPV6_ADDR_UNICAST 0x0001U +#define IPV6_ADDR_MULTICAST 0x0002U + +#define IPV6_ADDR_LOOPBACK 0x0010U +#define IPV6_ADDR_LINKLOCAL 0x0020U +#define IPV6_ADDR_SITELOCAL 0x0040U + +#define IPV6_ADDR_COMPATv4 0x0080U + +#define IPV6_ADDR_SCOPE_MASK 0x00f0U + +#define IPV6_ADDR_MAPPED 0x1000U + +/* + * Addr scopes + */ +#ifdef __KERNEL__ +#define IPV6_ADDR_MC_SCOPE(a) \ + ((a)->s6_addr[1] & 0x0f) /* nonstandard */ +#define __IPV6_ADDR_SCOPE_INVALID -1 +#endif +#define IPV6_ADDR_SCOPE_NODELOCAL 0x01 +#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 +#define IPV6_ADDR_SCOPE_SITELOCAL 0x05 +#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 +#define IPV6_ADDR_SCOPE_GLOBAL 0x0e + +/* + * fragmentation header + */ + +struct frag_hdr { + __u8 nexthdr; + __u8 reserved; + __be16 frag_off; + __be32 identification; +}; + +#define IP6_MF 0x0001 + +#ifdef __KERNEL__ + +#include <net/sock.h> + +/* sysctls */ +extern int sysctl_mld_max_msf; +extern struct ctl_path net_ipv6_ctl_path[]; + +#define _DEVINC(net, statname, modifier, idev, field) \ +({ \ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_INC_STATS##modifier((_idev)->stats.statname, (field)); \ + SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\ +}) + +#define _DEVADD(net, statname, modifier, idev, field, val) \ +({ \ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_ADD_STATS##modifier((_idev)->stats.statname, (field), (val)); \ + SNMP_ADD_STATS##modifier((net)->mib.statname##_statistics, (field), (val));\ +}) + +#define _DEVUPD(net, statname, modifier, idev, field, val) \ +({ \ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_UPD_PO_STATS##modifier((_idev)->stats.statname, field, (val)); \ + SNMP_UPD_PO_STATS##modifier((net)->mib.statname##_statistics, field, (val));\ +}) + +/* MIBs */ + +#define IP6_INC_STATS(net, idev,field) \ + _DEVINC(net, ipv6, 64, idev, field) +#define IP6_INC_STATS_BH(net, idev,field) \ + _DEVINC(net, ipv6, 64_BH, idev, field) +#define IP6_ADD_STATS(net, idev,field,val) \ + _DEVADD(net, ipv6, 64, idev, field, val) +#define IP6_ADD_STATS_BH(net, idev,field,val) \ + _DEVADD(net, ipv6, 64_BH, idev, field, val) +#define IP6_UPD_PO_STATS(net, idev,field,val) \ + _DEVUPD(net, ipv6, 64, idev, field, val) +#define IP6_UPD_PO_STATS_BH(net, idev,field,val) \ + _DEVUPD(net, ipv6, 64_BH, idev, field, val) +#define ICMP6_INC_STATS(net, idev, field) \ + _DEVINC(net, icmpv6, , idev, field) +#define ICMP6_INC_STATS_BH(net, idev, field) \ + _DEVINC(net, icmpv6, _BH, idev, field) + +#define ICMP6MSGOUT_INC_STATS(net, idev, field) \ + _DEVINC(net, icmpv6msg, , idev, field +256) +#define ICMP6MSGOUT_INC_STATS_BH(net, idev, field) \ + _DEVINC(net, icmpv6msg, _BH, idev, field +256) +#define ICMP6MSGIN_INC_STATS_BH(net, idev, field) \ + _DEVINC(net, icmpv6msg, _BH, idev, field) + +struct ip6_ra_chain { + struct ip6_ra_chain *next; + struct sock *sk; + int sel; + void (*destructor)(struct sock *); +}; + +extern struct ip6_ra_chain *ip6_ra_chain; +extern rwlock_t ip6_ra_lock; + +/* + This structure is prepared by protocol, when parsing + ancillary data and passed to IPv6. + */ + +struct ipv6_txoptions { + /* Length of this structure */ + int tot_len; + + /* length of extension headers */ + + __u16 opt_flen; /* after fragment hdr */ + __u16 opt_nflen; /* before fragment hdr */ + + struct ipv6_opt_hdr *hopopt; + struct ipv6_opt_hdr *dst0opt; + struct ipv6_rt_hdr *srcrt; /* Routing Header */ + struct ipv6_opt_hdr *dst1opt; + + /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */ +}; + +struct ip6_flowlabel { + struct ip6_flowlabel *next; + __be32 label; + atomic_t users; + struct in6_addr dst; + struct ipv6_txoptions *opt; + unsigned long linger; + u8 share; + u32 owner; + unsigned long lastuse; + unsigned long expires; + struct net *fl_net; +}; + +#define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) +#define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF) + +struct ipv6_fl_socklist { + struct ipv6_fl_socklist *next; + struct ip6_flowlabel *fl; +}; + +extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); +extern struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, + struct ip6_flowlabel * fl, + struct ipv6_txoptions * fopt); +extern void fl6_free_socklist(struct sock *sk); +extern int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); +extern int ip6_flowlabel_init(void); +extern void ip6_flowlabel_cleanup(void); + +static inline void fl6_sock_release(struct ip6_flowlabel *fl) +{ + if (fl) + atomic_dec(&fl->users); +} + +extern int ip6_ra_control(struct sock *sk, int sel); + +extern int ipv6_parse_hopopts(struct sk_buff *skb); + +extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); +extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, + int newtype, + struct ipv6_opt_hdr __user *newopt, + int newoptlen); +struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, + struct ipv6_txoptions *opt); + +extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb); + +int ip6_frag_nqueues(struct net *net); +int ip6_frag_mem(struct net *net); + +#define IPV6_FRAG_HIGH_THRESH (256 * 1024) /* 262144 */ +#define IPV6_FRAG_LOW_THRESH (192 * 1024) /* 196608 */ +#define IPV6_FRAG_TIMEOUT (60 * HZ) /* 60 seconds */ + +extern int __ipv6_addr_type(const struct in6_addr *addr); +static inline int ipv6_addr_type(const struct in6_addr *addr) +{ + return __ipv6_addr_type(addr) & 0xffff; +} + +static inline int ipv6_addr_scope(const struct in6_addr *addr) +{ + return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK; +} + +static inline int __ipv6_addr_src_scope(int type) +{ + return (type == IPV6_ADDR_ANY ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16)); +} + +static inline int ipv6_addr_src_scope(const struct in6_addr *addr) +{ + return __ipv6_addr_src_scope(__ipv6_addr_type(addr)); +} + +static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2) +{ + return memcmp(a1, a2, sizeof(struct in6_addr)); +} + +static inline int +ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m, + const struct in6_addr *a2) +{ + return (!!(((a1->s6_addr32[0] ^ a2->s6_addr32[0]) & m->s6_addr32[0]) | + ((a1->s6_addr32[1] ^ a2->s6_addr32[1]) & m->s6_addr32[1]) | + ((a1->s6_addr32[2] ^ a2->s6_addr32[2]) & m->s6_addr32[2]) | + ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3]))); +} + +static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2) +{ + memcpy(a1, a2, sizeof(struct in6_addr)); +} + +static inline void ipv6_addr_prefix(struct in6_addr *pfx, + const struct in6_addr *addr, + int plen) +{ + /* caller must guarantee 0 <= plen <= 128 */ + int o = plen >> 3, + b = plen & 0x7; + + memset(pfx->s6_addr, 0, sizeof(pfx->s6_addr)); + memcpy(pfx->s6_addr, addr, o); + if (b != 0) + pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b); +} + +static inline void ipv6_addr_set(struct in6_addr *addr, + __be32 w1, __be32 w2, + __be32 w3, __be32 w4) +{ + addr->s6_addr32[0] = w1; + addr->s6_addr32[1] = w2; + addr->s6_addr32[2] = w3; + addr->s6_addr32[3] = w4; +} + +static inline int ipv6_addr_equal(const struct in6_addr *a1, + const struct in6_addr *a2) +{ + return (((a1->s6_addr32[0] ^ a2->s6_addr32[0]) | + (a1->s6_addr32[1] ^ a2->s6_addr32[1]) | + (a1->s6_addr32[2] ^ a2->s6_addr32[2]) | + (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0); +} + +static inline int __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2, + unsigned int prefixlen) +{ + unsigned pdw, pbi; + + /* check complete u32 in prefix */ + pdw = prefixlen >> 5; + if (pdw && memcmp(a1, a2, pdw << 2)) + return 0; + + /* check incomplete u32 in prefix */ + pbi = prefixlen & 0x1f; + if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi)))) + return 0; + + return 1; +} + +static inline int ipv6_prefix_equal(const struct in6_addr *a1, + const struct in6_addr *a2, + unsigned int prefixlen) +{ + return __ipv6_prefix_equal(a1->s6_addr32, a2->s6_addr32, + prefixlen); +} + +struct inet_frag_queue; + +enum ip6_defrag_users { + IP6_DEFRAG_LOCAL_DELIVER, + IP6_DEFRAG_CONNTRACK_IN, + __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX, + IP6_DEFRAG_CONNTRACK_OUT, + __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX, + IP6_DEFRAG_CONNTRACK_BRIDGE_IN, + __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX, +}; + +struct ip6_create_arg { + __be32 id; + u32 user; + struct in6_addr *src; + struct in6_addr *dst; +}; + +void ip6_frag_init(struct inet_frag_queue *q, void *a); +int ip6_frag_match(struct inet_frag_queue *q, void *a); + +static inline int ipv6_addr_any(const struct in6_addr *a) +{ + return ((a->s6_addr32[0] | a->s6_addr32[1] | + a->s6_addr32[2] | a->s6_addr32[3] ) == 0); +} + +static inline int ipv6_addr_loopback(const struct in6_addr *a) +{ + return ((a->s6_addr32[0] | a->s6_addr32[1] | + a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0); +} + +static inline int ipv6_addr_v4mapped(const struct in6_addr *a) +{ + return ((a->s6_addr32[0] | a->s6_addr32[1] | + (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0); +} + +/* + * Check for a RFC 4843 ORCHID address + * (Overlay Routable Cryptographic Hash Identifiers) + */ +static inline int ipv6_addr_orchid(const struct in6_addr *a) +{ + return ((a->s6_addr32[0] & htonl(0xfffffff0)) + == htonl(0x20010010)); +} + +static inline void ipv6_addr_set_v4mapped(const __be32 addr, + struct in6_addr *v4mapped) +{ + ipv6_addr_set(v4mapped, + 0, 0, + htonl(0x0000FFFF), + addr); +} + +/* + * find the first different bit between two addresses + * length of address must be a multiple of 32bits + */ +static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen) +{ + const __be32 *a1 = token1, *a2 = token2; + int i; + + addrlen >>= 2; + + for (i = 0; i < addrlen; i++) { + __be32 xb = a1[i] ^ a2[i]; + if (xb) + return i * 32 + 31 - __fls(ntohl(xb)); + } + + /* + * we should *never* get to this point since that + * would mean the addrs are equal + * + * However, we do get to it 8) And exacly, when + * addresses are equal 8) + * + * ip route add 1111::/128 via ... + * ip route add 1111::/64 via ... + * and we are here. + * + * Ideally, this function should stop comparison + * at prefix length. It does not, but it is still OK, + * if returned value is greater than prefix length. + * --ANK (980803) + */ + return (addrlen << 5); +} + +static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2) +{ + return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); +} + +static __inline__ void ipv6_select_ident(struct frag_hdr *fhdr) +{ + static u32 ipv6_fragmentation_id = 1; + static DEFINE_SPINLOCK(ip6_id_lock); + + spin_lock_bh(&ip6_id_lock); + fhdr->identification = htonl(ipv6_fragmentation_id); + if (++ipv6_fragmentation_id == 0) + ipv6_fragmentation_id = 1; + spin_unlock_bh(&ip6_id_lock); +} + +/* + * Prototypes exported by ipv6 + */ + +/* + * rcv function (called from netdevice level) + */ + +extern int ipv6_rcv(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt, + struct net_device *orig_dev); + +extern int ip6_rcv_finish(struct sk_buff *skb); + +/* + * upper-layer output functions + */ +extern int ip6_xmit(struct sock *sk, + struct sk_buff *skb, + struct flowi *fl, + struct ipv6_txoptions *opt); + +extern int ip6_nd_hdr(struct sock *sk, + struct sk_buff *skb, + struct net_device *dev, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + int proto, int len); + +extern int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); + +extern int ip6_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), + void *from, + int length, + int transhdrlen, + int hlimit, + int tclass, + struct ipv6_txoptions *opt, + struct flowi *fl, + struct rt6_info *rt, + unsigned int flags, + int dontfrag); + +extern int ip6_push_pending_frames(struct sock *sk); + +extern void ip6_flush_pending_frames(struct sock *sk); + +extern int ip6_dst_lookup(struct sock *sk, + struct dst_entry **dst, + struct flowi *fl); +extern int ip6_dst_blackhole(struct sock *sk, + struct dst_entry **dst, + struct flowi *fl); +extern int ip6_sk_dst_lookup(struct sock *sk, + struct dst_entry **dst, + struct flowi *fl); + +/* + * skb processing functions + */ + +extern int ip6_output(struct sk_buff *skb); +extern int ip6_forward(struct sk_buff *skb); +extern int ip6_input(struct sk_buff *skb); +extern int ip6_mc_input(struct sk_buff *skb); + +extern int __ip6_local_out(struct sk_buff *skb); +extern int ip6_local_out(struct sk_buff *skb); + +/* + * Extension header (options) processing + */ + +extern void ipv6_push_nfrag_opts(struct sk_buff *skb, + struct ipv6_txoptions *opt, + u8 *proto, + struct in6_addr **daddr_p); +extern void ipv6_push_frag_opts(struct sk_buff *skb, + struct ipv6_txoptions *opt, + u8 *proto); + +extern int ipv6_skip_exthdr(const struct sk_buff *, int start, + u8 *nexthdrp); + +extern int ipv6_ext_hdr(u8 nexthdr); + +extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type); + +extern struct in6_addr *fl6_update_dst(struct flowi *fl, + const struct ipv6_txoptions *opt, + struct in6_addr *orig); + +/* + * socket options (ipv6_sockglue.c) + */ + +extern int ipv6_setsockopt(struct sock *sk, int level, + int optname, + char __user *optval, + unsigned int optlen); +extern int ipv6_getsockopt(struct sock *sk, int level, + int optname, + char __user *optval, + int __user *optlen); +extern int compat_ipv6_setsockopt(struct sock *sk, + int level, + int optname, + char __user *optval, + unsigned int optlen); +extern int compat_ipv6_getsockopt(struct sock *sk, + int level, + int optname, + char __user *optval, + int __user *optlen); + +extern int ip6_datagram_connect(struct sock *sk, + struct sockaddr *addr, int addr_len); + +extern int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len); +extern int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len); +extern void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port, + u32 info, u8 *payload); +extern void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info); +extern void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu); + +extern int inet6_release(struct socket *sock); +extern int inet6_bind(struct socket *sock, struct sockaddr *uaddr, + int addr_len); +extern int inet6_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer); +extern int inet6_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); + +extern int inet6_hash_connect(struct inet_timewait_death_row *death_row, + struct sock *sk); + +/* + * reassembly.c + */ +extern const struct proto_ops inet6_stream_ops; +extern const struct proto_ops inet6_dgram_ops; + +struct group_source_req; +struct group_filter; + +extern int ip6_mc_source(int add, int omode, struct sock *sk, + struct group_source_req *pgsr); +extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf); +extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, + struct group_filter __user *optval, + int __user *optlen); +extern unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, + const struct in6_addr *daddr, u32 rnd); + +#ifdef CONFIG_PROC_FS +extern int ac6_proc_init(struct net *net); +extern void ac6_proc_exit(struct net *net); +extern int raw6_proc_init(void); +extern void raw6_proc_exit(void); +extern int tcp6_proc_init(struct net *net); +extern void tcp6_proc_exit(struct net *net); +extern int udp6_proc_init(struct net *net); +extern void udp6_proc_exit(struct net *net); +extern int udplite6_proc_init(void); +extern void udplite6_proc_exit(void); +extern int ipv6_misc_proc_init(void); +extern void ipv6_misc_proc_exit(void); +extern int snmp6_register_dev(struct inet6_dev *idev); +extern int snmp6_unregister_dev(struct inet6_dev *idev); + +#else +static inline int ac6_proc_init(struct net *net) { return 0; } +static inline void ac6_proc_exit(struct net *net) { } +static inline int snmp6_register_dev(struct inet6_dev *idev) { return 0; } +static inline int snmp6_unregister_dev(struct inet6_dev *idev) { return 0; } +#endif + +#ifdef CONFIG_SYSCTL +extern ctl_table ipv6_route_table_template[]; +extern ctl_table ipv6_icmp_table_template[]; + +extern struct ctl_table *ipv6_icmp_sysctl_init(struct net *net); +extern struct ctl_table *ipv6_route_sysctl_init(struct net *net); +extern int ipv6_sysctl_register(void); +extern void ipv6_sysctl_unregister(void); +extern int ipv6_static_sysctl_register(void); +extern void ipv6_static_sysctl_unregister(void); +#endif + +#endif /* __KERNEL__ */ +#endif /* _NET_IPV6_H */ diff --git a/include/net/ipx.h b/include/net/ipx.h new file mode 100644 index 00000000..05d7e4a8 --- /dev/null +++ b/include/net/ipx.h @@ -0,0 +1,162 @@ +#ifndef _NET_INET_IPX_H_ +#define _NET_INET_IPX_H_ +/* + * The following information is in its entirety obtained from: + * + * Novell 'IPX Router Specification' Version 1.10 + * Part No. 107-000029-001 + * + * Which is available from ftp.novell.com + */ + +#include <linux/netdevice.h> +#include <net/datalink.h> +#include <linux/ipx.h> +#include <linux/list.h> +#include <linux/slab.h> + +struct ipx_address { + __be32 net; + __u8 node[IPX_NODE_LEN]; + __be16 sock; +}; + +#define ipx_broadcast_node "\377\377\377\377\377\377" +#define ipx_this_node "\0\0\0\0\0\0" + +#define IPX_MAX_PPROP_HOPS 8 + +struct ipxhdr { + __be16 ipx_checksum __packed; +#define IPX_NO_CHECKSUM cpu_to_be16(0xFFFF) + __be16 ipx_pktsize __packed; + __u8 ipx_tctrl; + __u8 ipx_type; +#define IPX_TYPE_UNKNOWN 0x00 +#define IPX_TYPE_RIP 0x01 /* may also be 0 */ +#define IPX_TYPE_SAP 0x04 /* may also be 0 */ +#define IPX_TYPE_SPX 0x05 /* SPX protocol */ +#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */ +#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast */ + struct ipx_address ipx_dest __packed; + struct ipx_address ipx_source __packed; +}; + +static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb) +{ + return (struct ipxhdr *)skb_transport_header(skb); +} + +struct ipx_interface { + /* IPX address */ + __be32 if_netnum; + unsigned char if_node[IPX_NODE_LEN]; + atomic_t refcnt; + + /* physical device info */ + struct net_device *if_dev; + struct datalink_proto *if_dlink; + __be16 if_dlink_type; + + /* socket support */ + unsigned short if_sknum; + struct hlist_head if_sklist; + spinlock_t if_sklist_lock; + + /* administrative overhead */ + int if_ipx_offset; + unsigned char if_internal; + unsigned char if_primary; + + struct list_head node; /* node in ipx_interfaces list */ +}; + +struct ipx_route { + __be32 ir_net; + struct ipx_interface *ir_intrfc; + unsigned char ir_routed; + unsigned char ir_router_node[IPX_NODE_LEN]; + struct list_head node; /* node in ipx_routes list */ + atomic_t refcnt; +}; + +#ifdef __KERNEL__ +struct ipx_cb { + u8 ipx_tctrl; + __be32 ipx_dest_net; + __be32 ipx_source_net; + struct { + __be32 netnum; + int index; + } last_hop; +}; + +#include <net/sock.h> + +struct ipx_sock { + /* struct sock has to be the first member of ipx_sock */ + struct sock sk; + struct ipx_address dest_addr; + struct ipx_interface *intrfc; + __be16 port; +#ifdef CONFIG_IPX_INTERN + unsigned char node[IPX_NODE_LEN]; +#endif + unsigned short type; + /* + * To handle special ncp connection-handling sockets for mars_nwe, + * the connection number must be stored in the socket. + */ + unsigned short ipx_ncp_conn; +}; + +static inline struct ipx_sock *ipx_sk(struct sock *sk) +{ + return (struct ipx_sock *)sk; +} + +#define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0])) +#endif + +#define IPX_MIN_EPHEMERAL_SOCKET 0x4000 +#define IPX_MAX_EPHEMERAL_SOCKET 0x7fff + +extern struct list_head ipx_routes; +extern rwlock_t ipx_routes_lock; + +extern struct list_head ipx_interfaces; +extern struct ipx_interface *ipx_interfaces_head(void); +extern spinlock_t ipx_interfaces_lock; + +extern struct ipx_interface *ipx_primary_net; + +extern int ipx_proc_init(void); +extern void ipx_proc_exit(void); + +extern const char *ipx_frame_name(__be16); +extern const char *ipx_device_name(struct ipx_interface *intrfc); + +static __inline__ void ipxitf_hold(struct ipx_interface *intrfc) +{ + atomic_inc(&intrfc->refcnt); +} + +extern void ipxitf_down(struct ipx_interface *intrfc); + +static __inline__ void ipxitf_put(struct ipx_interface *intrfc) +{ + if (atomic_dec_and_test(&intrfc->refcnt)) + ipxitf_down(intrfc); +} + +static __inline__ void ipxrtr_hold(struct ipx_route *rt) +{ + atomic_inc(&rt->refcnt); +} + +static __inline__ void ipxrtr_put(struct ipx_route *rt) +{ + if (atomic_dec_and_test(&rt->refcnt)) + kfree(rt); +} +#endif /* _NET_INET_IPX_H_ */ diff --git a/include/net/irda/af_irda.h b/include/net/irda/af_irda.h new file mode 100644 index 00000000..0df57493 --- /dev/null +++ b/include/net/irda/af_irda.h @@ -0,0 +1,87 @@ +/********************************************************************* + * + * Filename: af_irda.h + * Version: 1.0 + * Description: IrDA sockets declarations + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Dec 9 21:13:12 1997 + * Modified at: Fri Jan 28 13:16:32 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef AF_IRDA_H +#define AF_IRDA_H + +#include <linux/irda.h> +#include <net/irda/irda.h> +#include <net/irda/iriap.h> /* struct iriap_cb */ +#include <net/irda/irias_object.h> /* struct ias_value */ +#include <net/irda/irlmp.h> /* struct lsap_cb */ +#include <net/irda/irttp.h> /* struct tsap_cb */ +#include <net/irda/discovery.h> /* struct discovery_t */ +#include <net/sock.h> + +/* IrDA Socket */ +struct irda_sock { + /* struct sock has to be the first member of irda_sock */ + struct sock sk; + __u32 saddr; /* my local address */ + __u32 daddr; /* peer address */ + + struct lsap_cb *lsap; /* LSAP used by Ultra */ + __u8 pid; /* Protocol IP (PID) used by Ultra */ + + struct tsap_cb *tsap; /* TSAP used by this connection */ + __u8 dtsap_sel; /* remote TSAP address */ + __u8 stsap_sel; /* local TSAP address */ + + __u32 max_sdu_size_rx; + __u32 max_sdu_size_tx; + __u32 max_data_size; + __u8 max_header_size; + struct qos_info qos_tx; + + __u16_host_order mask; /* Hint bits mask */ + __u16_host_order hints; /* Hint bits */ + + void *ckey; /* IrLMP client handle */ + void *skey; /* IrLMP service handle */ + + struct ias_object *ias_obj; /* Our service name + lsap in IAS */ + struct iriap_cb *iriap; /* Used to query remote IAS */ + struct ias_value *ias_result; /* Result of remote IAS query */ + + hashbin_t *cachelog; /* Result of discovery query */ + __u32 cachedaddr; /* Result of selective discovery query */ + + int nslots; /* Number of slots to use for discovery */ + + int errno; /* status of the IAS query */ + + wait_queue_head_t query_wait; /* Wait for the answer to a query */ + struct timer_list watchdog; /* Timeout for discovery */ + + LOCAL_FLOW tx_flow; + LOCAL_FLOW rx_flow; +}; + +static inline struct irda_sock *irda_sk(struct sock *sk) +{ + return (struct irda_sock *)sk; +} + +#endif /* AF_IRDA_H */ diff --git a/include/net/irda/crc.h b/include/net/irda/crc.h new file mode 100644 index 00000000..f202296d --- /dev/null +++ b/include/net/irda/crc.h @@ -0,0 +1,29 @@ +/********************************************************************* + * + * Filename: crc.h + * Version: + * Description: CRC routines + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Sun May 2 20:25:23 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + ********************************************************************/ + +#ifndef IRDA_CRC_H +#define IRDA_CRC_H + +#include <linux/types.h> +#include <linux/crc-ccitt.h> + +#define INIT_FCS 0xffff /* Initial FCS value */ +#define GOOD_FCS 0xf0b8 /* Good final FCS value */ + +/* Recompute the FCS with one more character appended. */ +#define irda_fcs(fcs, c) crc_ccitt_byte(fcs, c) + +/* Recompute the FCS with len bytes appended. */ +#define irda_calc_crc16(fcs, buf, len) crc_ccitt(fcs, buf, len) + +#endif diff --git a/include/net/irda/discovery.h b/include/net/irda/discovery.h new file mode 100644 index 00000000..0ce93398 --- /dev/null +++ b/include/net/irda/discovery.h @@ -0,0 +1,97 @@ +/********************************************************************* + * + * Filename: discovery.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Apr 6 16:53:53 1999 + * Modified at: Tue Oct 5 10:05:10 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef DISCOVERY_H +#define DISCOVERY_H + +#include <asm/param.h> + +#include <net/irda/irda.h> +#include <net/irda/irqueue.h> /* irda_queue_t */ +#include <net/irda/irlap_event.h> /* LAP_REASON */ + +#define DISCOVERY_EXPIRE_TIMEOUT (2*sysctl_discovery_timeout*HZ) +#define DISCOVERY_DEFAULT_SLOTS 0 + +/* + * This type is used by the protocols that transmit 16 bits words in + * little endian format. A little endian machine stores MSB of word in + * byte[1] and LSB in byte[0]. A big endian machine stores MSB in byte[0] + * and LSB in byte[1]. + * + * This structure is used in the code for things that are endian neutral + * but that fit in a word so that we can manipulate them efficiently. + * By endian neutral, I mean things that are really an array of bytes, + * and always used as such, for example the hint bits. Jean II + */ +typedef union { + __u16 word; + __u8 byte[2]; +} __u16_host_order; + +/* Types of discovery */ +typedef enum { + DISCOVERY_LOG, /* What's in our discovery log */ + DISCOVERY_ACTIVE, /* Doing our own discovery on the medium */ + DISCOVERY_PASSIVE, /* Peer doing discovery on the medium */ + EXPIRY_TIMEOUT, /* Entry expired due to timeout */ +} DISCOVERY_MODE; + +#define NICKNAME_MAX_LEN 21 + +/* Basic discovery information about a peer */ +typedef struct irda_device_info discinfo_t; /* linux/irda.h */ + +/* + * The DISCOVERY structure is used for both discovery requests and responses + */ +typedef struct discovery_t { + irda_queue_t q; /* Must be first! */ + + discinfo_t data; /* Basic discovery information */ + int name_len; /* Length of nickname */ + + LAP_REASON condition; /* More info about the discovery */ + int gen_addr_bit; /* Need to generate a new device + * address? */ + int nslots; /* Number of slots to use when + * discovering */ + unsigned long timestamp; /* Last time discovered */ + unsigned long firststamp; /* First time discovered */ +} discovery_t; + +void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery); +void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log); +void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force); +struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, + __u16 mask, int old_entries); + +#endif diff --git a/include/net/irda/ircomm_core.h b/include/net/irda/ircomm_core.h new file mode 100644 index 00000000..69b610ac --- /dev/null +++ b/include/net/irda/ircomm_core.h @@ -0,0 +1,108 @@ +/********************************************************************* + * + * Filename: ircomm_core.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 08:58:43 1999 + * Modified at: Mon Dec 13 11:52:29 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRCOMM_CORE_H +#define IRCOMM_CORE_H + +#include <net/irda/irda.h> +#include <net/irda/irqueue.h> +#include <net/irda/ircomm_event.h> + +#define IRCOMM_MAGIC 0x98347298 +#define IRCOMM_HEADER_SIZE 1 + +struct ircomm_cb; /* Forward decl. */ + +/* + * A small call-table, so we don't have to check the service-type whenever + * we want to do something + */ +typedef struct { + int (*data_request)(struct ircomm_cb *, struct sk_buff *, int clen); + int (*connect_request)(struct ircomm_cb *, struct sk_buff *, + struct ircomm_info *); + int (*connect_response)(struct ircomm_cb *, struct sk_buff *); + int (*disconnect_request)(struct ircomm_cb *, struct sk_buff *, + struct ircomm_info *); +} call_t; + +struct ircomm_cb { + irda_queue_t queue; + magic_t magic; + + notify_t notify; + call_t issue; + + int state; + int line; /* Which TTY line we are using */ + + struct tsap_cb *tsap; + struct lsap_cb *lsap; + + __u8 dlsap_sel; /* Destination LSAP/TSAP selector */ + __u8 slsap_sel; /* Source LSAP/TSAP selector */ + + __u32 saddr; /* Source device address (link we are using) */ + __u32 daddr; /* Destination device address */ + + int max_header_size; /* Header space we must reserve for each frame */ + int max_data_size; /* The amount of data we can fill in each frame */ + + LOCAL_FLOW flow_status; /* Used by ircomm_lmp */ + int pkt_count; /* Number of frames we have sent to IrLAP */ + + __u8 service_type; +}; + +extern hashbin_t *ircomm; + +struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line); +int ircomm_close(struct ircomm_cb *self); + +int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb); +void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb); +void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb); +int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb); +int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, + __u32 saddr, __u32 daddr, struct sk_buff *skb, + __u8 service_type); +void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info); +void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info); +int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata); +int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata); +void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, + struct ircomm_info *info); +void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow); + +#define ircomm_is_connected(self) (self->state == IRCOMM_CONN) + +#endif diff --git a/include/net/irda/ircomm_event.h b/include/net/irda/ircomm_event.h new file mode 100644 index 00000000..bc0c6f31 --- /dev/null +++ b/include/net/irda/ircomm_event.h @@ -0,0 +1,85 @@ +/********************************************************************* + * + * Filename: ircomm_event.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 23:51:13 1999 + * Modified at: Thu Jun 10 08:36:25 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRCOMM_EVENT_H +#define IRCOMM_EVENT_H + +#include <net/irda/irmod.h> + +typedef enum { + IRCOMM_IDLE, + IRCOMM_WAITI, + IRCOMM_WAITR, + IRCOMM_CONN, +} IRCOMM_STATE; + +/* IrCOMM Events */ +typedef enum { + IRCOMM_CONNECT_REQUEST, + IRCOMM_CONNECT_RESPONSE, + IRCOMM_TTP_CONNECT_INDICATION, + IRCOMM_LMP_CONNECT_INDICATION, + IRCOMM_TTP_CONNECT_CONFIRM, + IRCOMM_LMP_CONNECT_CONFIRM, + + IRCOMM_LMP_DISCONNECT_INDICATION, + IRCOMM_TTP_DISCONNECT_INDICATION, + IRCOMM_DISCONNECT_REQUEST, + + IRCOMM_TTP_DATA_INDICATION, + IRCOMM_LMP_DATA_INDICATION, + IRCOMM_DATA_REQUEST, + IRCOMM_CONTROL_REQUEST, + IRCOMM_CONTROL_INDICATION, +} IRCOMM_EVENT; + +/* + * Used for passing information through the state-machine + */ +struct ircomm_info { + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + __u8 dlsap_sel; + LM_REASON reason; /* Reason for disconnect */ + __u32 max_data_size; + __u32 max_header_size; + + struct qos_info *qos; +}; + +extern const char *const ircomm_state[]; + +struct ircomm_cb; /* Forward decl. */ + +int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb, struct ircomm_info *info); +void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state); + +#endif diff --git a/include/net/irda/ircomm_lmp.h b/include/net/irda/ircomm_lmp.h new file mode 100644 index 00000000..ae02106b --- /dev/null +++ b/include/net/irda/ircomm_lmp.h @@ -0,0 +1,38 @@ +/********************************************************************* + * + * Filename: ircomm_lmp.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 10:06:07 1999 + * Modified at: Fri Aug 13 07:32:32 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRCOMM_LMP_H +#define IRCOMM_LMP_H + +#include <net/irda/ircomm_core.h> + +int ircomm_open_lsap(struct ircomm_cb *self); + +#endif diff --git a/include/net/irda/ircomm_param.h b/include/net/irda/ircomm_param.h new file mode 100644 index 00000000..e6678800 --- /dev/null +++ b/include/net/irda/ircomm_param.h @@ -0,0 +1,149 @@ +/********************************************************************* + * + * Filename: ircomm_param.h + * Version: 1.0 + * Description: Parameter handling for the IrCOMM protocol + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Jun 7 08:47:28 1999 + * Modified at: Wed Aug 25 13:46:33 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRCOMM_PARAMS_H +#define IRCOMM_PARAMS_H + +#include <net/irda/parameters.h> + +/* Parameters common to all service types */ +#define IRCOMM_SERVICE_TYPE 0x00 +#define IRCOMM_PORT_TYPE 0x01 /* Only used in LM-IAS */ +#define IRCOMM_PORT_NAME 0x02 /* Only used in LM-IAS */ + +/* Parameters for both 3 wire and 9 wire */ +#define IRCOMM_DATA_RATE 0x10 +#define IRCOMM_DATA_FORMAT 0x11 +#define IRCOMM_FLOW_CONTROL 0x12 +#define IRCOMM_XON_XOFF 0x13 +#define IRCOMM_ENQ_ACK 0x14 +#define IRCOMM_LINE_STATUS 0x15 +#define IRCOMM_BREAK 0x16 + +/* Parameters for 9 wire */ +#define IRCOMM_DTE 0x20 +#define IRCOMM_DCE 0x21 +#define IRCOMM_POLL 0x22 + +/* Service type (details) */ +#define IRCOMM_3_WIRE_RAW 0x01 +#define IRCOMM_3_WIRE 0x02 +#define IRCOMM_9_WIRE 0x04 +#define IRCOMM_CENTRONICS 0x08 + +/* Port type (details) */ +#define IRCOMM_SERIAL 0x00 +#define IRCOMM_PARALLEL 0x01 + +/* Data format (details) */ +#define IRCOMM_WSIZE_5 0x00 +#define IRCOMM_WSIZE_6 0x01 +#define IRCOMM_WSIZE_7 0x02 +#define IRCOMM_WSIZE_8 0x03 + +#define IRCOMM_1_STOP_BIT 0x00 +#define IRCOMM_2_STOP_BIT 0x04 /* 1.5 if char len 5 */ + +#define IRCOMM_PARITY_DISABLE 0x00 +#define IRCOMM_PARITY_ENABLE 0x08 + +#define IRCOMM_PARITY_ODD 0x00 +#define IRCOMM_PARITY_EVEN 0x10 +#define IRCOMM_PARITY_MARK 0x20 +#define IRCOMM_PARITY_SPACE 0x30 + +/* Flow control */ +#define IRCOMM_XON_XOFF_IN 0x01 +#define IRCOMM_XON_XOFF_OUT 0x02 +#define IRCOMM_RTS_CTS_IN 0x04 +#define IRCOMM_RTS_CTS_OUT 0x08 +#define IRCOMM_DSR_DTR_IN 0x10 +#define IRCOMM_DSR_DTR_OUT 0x20 +#define IRCOMM_ENQ_ACK_IN 0x40 +#define IRCOMM_ENQ_ACK_OUT 0x80 + +/* Line status */ +#define IRCOMM_OVERRUN_ERROR 0x02 +#define IRCOMM_PARITY_ERROR 0x04 +#define IRCOMM_FRAMING_ERROR 0x08 + +/* DTE (Data terminal equipment) line settings */ +#define IRCOMM_DELTA_DTR 0x01 +#define IRCOMM_DELTA_RTS 0x02 +#define IRCOMM_DTR 0x04 +#define IRCOMM_RTS 0x08 + +/* DCE (Data communications equipment) line settings */ +#define IRCOMM_DELTA_CTS 0x01 /* Clear to send has changed */ +#define IRCOMM_DELTA_DSR 0x02 /* Data set ready has changed */ +#define IRCOMM_DELTA_RI 0x04 /* Ring indicator has changed */ +#define IRCOMM_DELTA_CD 0x08 /* Carrier detect has changed */ +#define IRCOMM_CTS 0x10 /* Clear to send is high */ +#define IRCOMM_DSR 0x20 /* Data set ready is high */ +#define IRCOMM_RI 0x40 /* Ring indicator is high */ +#define IRCOMM_CD 0x80 /* Carrier detect is high */ +#define IRCOMM_DCE_DELTA_ANY 0x0f + +/* + * Parameter state + */ +struct ircomm_params { + /* General control params */ + __u8 service_type; + __u8 port_type; + char port_name[32]; + + /* Control params for 3- and 9-wire service type */ + __u32 data_rate; /* Data rate in bps */ + __u8 data_format; + __u8 flow_control; + char xonxoff[2]; + char enqack[2]; + __u8 line_status; + __u8 _break; + + __u8 null_modem; + + /* Control params for 9-wire service type */ + __u8 dte; + __u8 dce; + __u8 poll; + + /* Control params for Centronics service type */ +}; + +struct ircomm_tty_cb; /* Forward decl. */ + +int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush); + +extern pi_param_info_t ircomm_param_info; + +#endif /* IRCOMM_PARAMS_H */ + diff --git a/include/net/irda/ircomm_ttp.h b/include/net/irda/ircomm_ttp.h new file mode 100644 index 00000000..403081ed --- /dev/null +++ b/include/net/irda/ircomm_ttp.h @@ -0,0 +1,39 @@ +/********************************************************************* + * + * Filename: ircomm_ttp.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 10:06:07 1999 + * Modified at: Fri Aug 13 07:32:22 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRCOMM_TTP_H +#define IRCOMM_TTP_H + +#include <net/irda/ircomm_core.h> + +int ircomm_open_tsap(struct ircomm_cb *self); + +#endif + diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h new file mode 100644 index 00000000..eea2e615 --- /dev/null +++ b/include/net/irda/ircomm_tty.h @@ -0,0 +1,138 @@ +/********************************************************************* + * + * Filename: ircomm_tty.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Jun 6 23:24:22 1999 + * Modified at: Fri Jan 28 13:16:57 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRCOMM_TTY_H +#define IRCOMM_TTY_H + +#include <linux/serial.h> +#include <linux/termios.h> +#include <linux/timer.h> +#include <linux/tty.h> /* struct tty_struct */ + +#include <net/irda/irias_object.h> +#include <net/irda/ircomm_core.h> +#include <net/irda/ircomm_param.h> + +#define IRCOMM_TTY_PORTS 32 +#define IRCOMM_TTY_MAGIC 0x3432 +#define IRCOMM_TTY_MAJOR 161 +#define IRCOMM_TTY_MINOR 0 + +/* This is used as an initial value to max_header_size before the proper + * value is filled in (5 for ttp, 4 for lmp). This allow us to detect + * the state of the underlying connection. - Jean II */ +#define IRCOMM_TTY_HDR_UNINITIALISED 16 +/* Same for payload size. See qos.c for the smallest max data size */ +#define IRCOMM_TTY_DATA_UNINITIALISED (64 - IRCOMM_TTY_HDR_UNINITIALISED) + +/* Those are really defined in include/linux/serial.h - Jean II */ +#define ASYNC_B_INITIALIZED 31 /* Serial port was initialized */ +#define ASYNC_B_NORMAL_ACTIVE 29 /* Normal device is active */ +#define ASYNC_B_CLOSING 27 /* Serial port is closing */ + +/* + * IrCOMM TTY driver state + */ +struct ircomm_tty_cb { + irda_queue_t queue; /* Must be first */ + magic_t magic; + + int state; /* Connect state */ + + struct tty_struct *tty; + struct ircomm_cb *ircomm; /* IrCOMM layer instance */ + + struct sk_buff *tx_skb; /* Transmit buffer */ + struct sk_buff *ctrl_skb; /* Control data buffer */ + + /* Parameters */ + struct ircomm_params settings; + + __u8 service_type; /* The service that we support */ + int client; /* True if we are a client */ + LOCAL_FLOW flow; /* IrTTP flow status */ + + int line; + unsigned long flags; + + __u8 dlsap_sel; + __u8 slsap_sel; + + __u32 saddr; + __u32 daddr; + + __u32 max_data_size; /* Max data we can transmit in one packet */ + __u32 max_header_size; /* The amount of header space we must reserve */ + __u32 tx_data_size; /* Max data size of current tx_skb */ + + struct iriap_cb *iriap; /* Instance used for querying remote IAS */ + struct ias_object* obj; + void *skey; + void *ckey; + + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + struct timer_list watchdog_timer; + struct work_struct tqueue; + + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + + int open_count; + int blocked_open; /* # of blocked opens */ + + /* Protect concurent access to : + * o self->open_count + * o self->ctrl_skb + * o self->tx_skb + * Maybe other things may gain to be protected as well... + * Jean II */ + spinlock_t spinlock; +}; + +void ircomm_tty_start(struct tty_struct *tty); +void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self); + +extern int ircomm_tty_tiocmget(struct tty_struct *tty, struct file *file); +extern int ircomm_tty_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); +extern int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +extern void ircomm_tty_set_termios(struct tty_struct *tty, + struct ktermios *old_termios); + +#endif + + + + + + + diff --git a/include/net/irda/ircomm_tty_attach.h b/include/net/irda/ircomm_tty_attach.h new file mode 100644 index 00000000..0a63bbb9 --- /dev/null +++ b/include/net/irda/ircomm_tty_attach.h @@ -0,0 +1,94 @@ +/********************************************************************* + * + * Filename: ircomm_tty_attach.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Wed Jun 9 15:55:18 1999 + * Modified at: Fri Dec 10 21:04:55 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRCOMM_TTY_ATTACH_H +#define IRCOMM_TTY_ATTACH_H + +#include <net/irda/ircomm_tty.h> + +typedef enum { + IRCOMM_TTY_IDLE, + IRCOMM_TTY_SEARCH, + IRCOMM_TTY_QUERY_PARAMETERS, + IRCOMM_TTY_QUERY_LSAP_SEL, + IRCOMM_TTY_SETUP, + IRCOMM_TTY_READY, +} IRCOMM_TTY_STATE; + +/* IrCOMM TTY Events */ +typedef enum { + IRCOMM_TTY_ATTACH_CABLE, + IRCOMM_TTY_DETACH_CABLE, + IRCOMM_TTY_DATA_REQUEST, + IRCOMM_TTY_DATA_INDICATION, + IRCOMM_TTY_DISCOVERY_REQUEST, + IRCOMM_TTY_DISCOVERY_INDICATION, + IRCOMM_TTY_CONNECT_CONFIRM, + IRCOMM_TTY_CONNECT_INDICATION, + IRCOMM_TTY_DISCONNECT_REQUEST, + IRCOMM_TTY_DISCONNECT_INDICATION, + IRCOMM_TTY_WD_TIMER_EXPIRED, + IRCOMM_TTY_GOT_PARAMETERS, + IRCOMM_TTY_GOT_LSAPSEL, +} IRCOMM_TTY_EVENT; + +/* Used for passing information through the state-machine */ +struct ircomm_tty_info { + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + __u8 dlsap_sel; +}; + +extern const char *const ircomm_state[]; +extern const char *const ircomm_tty_state[]; + +int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, + struct sk_buff *skb, struct ircomm_tty_info *info); + + +int ircomm_tty_attach_cable(struct ircomm_tty_cb *self); +void ircomm_tty_detach_cable(struct ircomm_tty_cb *self); +void ircomm_tty_connect_confirm(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); +void ircomm_tty_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb); +void ircomm_tty_connect_indication(void *instance, void *sap, + struct qos_info *qos, + __u32 max_sdu_size, + __u8 max_header_size, + struct sk_buff *skb); +int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self); +void ircomm_tty_link_established(struct ircomm_tty_cb *self); + +#endif /* IRCOMM_TTY_ATTACH_H */ diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h new file mode 100644 index 00000000..3bed61d3 --- /dev/null +++ b/include/net/irda/irda.h @@ -0,0 +1,131 @@ +/********************************************************************* + * + * Filename: irda.h + * Version: 1.0 + * Description: IrDA common include file for kernel internal use + * Status: Stable + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Dec 9 21:13:12 1997 + * Modified at: Fri Jan 28 13:16:32 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef NET_IRDA_H +#define NET_IRDA_H + +#include <linux/skbuff.h> /* struct sk_buff */ +#include <linux/kernel.h> +#include <linux/if.h> /* sa_family_t in <linux/irda.h> */ +#include <linux/irda.h> + +typedef __u32 magic_t; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* Hack to do small backoff when setting media busy in IrLAP */ +#ifndef SMALL +#define SMALL 5 +#endif + +#ifndef IRDA_MIN /* Lets not mix this MIN with other header files */ +#define IRDA_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef IRDA_ALIGN +# define IRDA_ALIGN __attribute__((aligned)) +#endif + +#ifdef CONFIG_IRDA_DEBUG + +extern unsigned int irda_debug; + +/* use 0 for production, 1 for verification, >2 for debug */ +#define IRDA_DEBUG_LEVEL 0 + +#define IRDA_DEBUG(n, args...) \ +do { if (irda_debug >= (n)) \ + printk(KERN_DEBUG args); \ +} while (0) +#define IRDA_ASSERT(expr, func) \ +do { if(!(expr)) { \ + printk( "Assertion failed! %s:%s:%d %s\n", \ + __FILE__,__func__,__LINE__,(#expr) ); \ + func } } while (0) +#define IRDA_ASSERT_LABEL(label) label +#else +#define IRDA_DEBUG(n, args...) do { } while (0) +#define IRDA_ASSERT(expr, func) do { (void)(expr); } while (0) +#define IRDA_ASSERT_LABEL(label) +#endif /* CONFIG_IRDA_DEBUG */ + +#define IRDA_WARNING(args...) do { if (net_ratelimit()) printk(KERN_WARNING args); } while (0) +#define IRDA_MESSAGE(args...) do { if (net_ratelimit()) printk(KERN_INFO args); } while (0) +#define IRDA_ERROR(args...) do { if (net_ratelimit()) printk(KERN_ERR args); } while (0) + +/* + * Magic numbers used by Linux-IrDA. Random numbers which must be unique to + * give the best protection + */ + +#define IRTTY_MAGIC 0x2357 +#define LAP_MAGIC 0x1357 +#define LMP_MAGIC 0x4321 +#define LMP_LSAP_MAGIC 0x69333 +#define LMP_LAP_MAGIC 0x3432 +#define IRDA_DEVICE_MAGIC 0x63454 +#define IAS_MAGIC 0x007 +#define TTP_MAGIC 0x241169 +#define TTP_TSAP_MAGIC 0x4345 +#define IROBEX_MAGIC 0x341324 +#define HB_MAGIC 0x64534 +#define IRLAN_MAGIC 0x754 +#define IAS_OBJECT_MAGIC 0x34234 +#define IAS_ATTRIB_MAGIC 0x45232 +#define IRDA_TASK_MAGIC 0x38423 + +#define IAS_DEVICE_ID 0x0000 /* Defined by IrDA, IrLMP section 4.1 (page 68) */ +#define IAS_PNP_ID 0xd342 +#define IAS_OBEX_ID 0x34323 +#define IAS_IRLAN_ID 0x34234 +#define IAS_IRCOMM_ID 0x2343 +#define IAS_IRLPT_ID 0x9876 + +struct net_device; +struct packet_type; + +extern void irda_proc_register(void); +extern void irda_proc_unregister(void); + +extern int irda_sysctl_register(void); +extern void irda_sysctl_unregister(void); + +extern int irsock_init(void); +extern void irsock_cleanup(void); + +extern int irda_nl_register(void); +extern void irda_nl_unregister(void); + +extern int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev); + +#endif /* NET_IRDA_H */ diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h new file mode 100644 index 00000000..94c852d4 --- /dev/null +++ b/include/net/irda/irda_device.h @@ -0,0 +1,287 @@ +/********************************************************************* + * + * Filename: irda_device.h + * Version: 0.9 + * Description: Contains various declarations used by the drivers + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Apr 14 12:41:42 1998 + * Modified at: Mon Mar 20 09:08:57 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>, + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +/* + * This header contains all the IrDA definitions a driver really + * needs, and therefore the driver should not need to include + * any other IrDA headers - Jean II + */ + +#ifndef IRDA_DEVICE_H +#define IRDA_DEVICE_H + +#include <linux/tty.h> +#include <linux/netdevice.h> +#include <linux/spinlock.h> +#include <linux/skbuff.h> /* struct sk_buff */ +#include <linux/irda.h> +#include <linux/types.h> + +#include <net/pkt_sched.h> +#include <net/irda/irda.h> +#include <net/irda/qos.h> /* struct qos_info */ +#include <net/irda/irqueue.h> /* irda_queue_t */ + +/* A few forward declarations (to make compiler happy) */ +struct irlap_cb; + +/* Some non-standard interface flags (should not conflict with any in if.h) */ +#define IFF_SIR 0x0001 /* Supports SIR speeds */ +#define IFF_MIR 0x0002 /* Supports MIR speeds */ +#define IFF_FIR 0x0004 /* Supports FIR speeds */ +#define IFF_VFIR 0x0008 /* Supports VFIR speeds */ +#define IFF_PIO 0x0010 /* Supports PIO transfer of data */ +#define IFF_DMA 0x0020 /* Supports DMA transfer of data */ +#define IFF_SHM 0x0040 /* Supports shared memory data transfers */ +#define IFF_DONGLE 0x0080 /* Interface has a dongle attached */ +#define IFF_AIR 0x0100 /* Supports Advanced IR (AIR) standards */ + +#define IO_XMIT 0x01 +#define IO_RECV 0x02 + +typedef enum { + IRDA_IRLAP, /* IrDA mode, and deliver to IrLAP */ + IRDA_RAW, /* IrDA mode */ + SHARP_ASK, + TV_REMOTE, /* Also known as Consumer Electronics IR */ +} INFRARED_MODE; + +typedef enum { + IRDA_TASK_INIT, /* All tasks are initialized with this state */ + IRDA_TASK_DONE, /* Signals that the task is finished */ + IRDA_TASK_WAIT, + IRDA_TASK_WAIT1, + IRDA_TASK_WAIT2, + IRDA_TASK_WAIT3, + IRDA_TASK_CHILD_INIT, /* Initializing child task */ + IRDA_TASK_CHILD_WAIT, /* Waiting for child task to finish */ + IRDA_TASK_CHILD_DONE /* Child task is finished */ +} IRDA_TASK_STATE; + +struct irda_task; +typedef int (*IRDA_TASK_CALLBACK) (struct irda_task *task); + +struct irda_task { + irda_queue_t q; + magic_t magic; + + IRDA_TASK_STATE state; + IRDA_TASK_CALLBACK function; + IRDA_TASK_CALLBACK finished; + + struct irda_task *parent; + struct timer_list timer; + + void *instance; /* Instance being called */ + void *param; /* Parameter to be used by instance */ +}; + +/* Dongle info */ +struct dongle_reg; +typedef struct { + struct dongle_reg *issue; /* Registration info */ + struct net_device *dev; /* Device we are attached to */ + struct irda_task *speed_task; /* Task handling speed change */ + struct irda_task *reset_task; /* Task handling reset */ + __u32 speed; /* Current speed */ + + /* Callbacks to the IrDA device driver */ + int (*set_mode)(struct net_device *, int mode); + int (*read)(struct net_device *dev, __u8 *buf, int len); + int (*write)(struct net_device *dev, __u8 *buf, int len); + int (*set_dtr_rts)(struct net_device *dev, int dtr, int rts); +} dongle_t; + +/* Dongle registration info */ +struct dongle_reg { + irda_queue_t q; /* Must be first */ + IRDA_DONGLE type; + + void (*open)(dongle_t *dongle, struct qos_info *qos); + void (*close)(dongle_t *dongle); + int (*reset)(struct irda_task *task); + int (*change_speed)(struct irda_task *task); + struct module *owner; +}; + +/* + * Per-packet information we need to hide inside sk_buff + * (must not exceed 48 bytes, check with struct sk_buff) + * The default_qdisc_pad field is a temporary hack. + */ +struct irda_skb_cb { + unsigned int default_qdisc_pad; + magic_t magic; /* Be sure that we can trust the information */ + __u32 next_speed; /* The Speed to be set *after* this frame */ + __u16 mtt; /* Minimum turn around time */ + __u16 xbofs; /* Number of xbofs required, used by SIR mode */ + __u16 next_xbofs; /* Number of xbofs required *after* this frame */ + void *context; /* May be used by drivers */ + void (*destructor)(struct sk_buff *skb); /* Used for flow control */ + __u16 xbofs_delay; /* Number of xbofs used for generating the mtt */ + __u8 line; /* Used by IrCOMM in IrLPT mode */ +}; + +/* Chip specific info */ +typedef struct { + int cfg_base; /* Config register IO base */ + int sir_base; /* SIR IO base */ + int fir_base; /* FIR IO base */ + int mem_base; /* Shared memory base */ + int sir_ext; /* Length of SIR iobase */ + int fir_ext; /* Length of FIR iobase */ + int irq, irq2; /* Interrupts used */ + int dma, dma2; /* DMA channel(s) used */ + int fifo_size; /* FIFO size */ + int irqflags; /* interrupt flags (ie, IRQF_SHARED|IRQF_DISABLED) */ + int direction; /* Link direction, used by some FIR drivers */ + int enabled; /* Powered on? */ + int suspended; /* Suspended by APM */ + __u32 speed; /* Currently used speed */ + __u32 new_speed; /* Speed we must change to when Tx is finished */ + int dongle_id; /* Dongle or transceiver currently used */ +} chipio_t; + +/* IO buffer specific info (inspired by struct sk_buff) */ +typedef struct { + int state; /* Receiving state (transmit state not used) */ + int in_frame; /* True if receiving frame */ + + __u8 *head; /* start of buffer */ + __u8 *data; /* start of data in buffer */ + + int len; /* current length of data */ + int truesize; /* total allocated size of buffer */ + __u16 fcs; + + struct sk_buff *skb; /* ZeroCopy Rx in async_unwrap_char() */ +} iobuff_t; + +/* Maximum SIR frame (skb) that we expect to receive *unwrapped*. + * Max LAP MTU (I field) is 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40). + * Max LAP header is 2 bytes (for now). + * Max CRC is 2 bytes at SIR, 4 bytes at FIR. + * Need 1 byte for skb_reserve() to align IP header for IrLAN. + * Add a few extra bytes just to be safe (buffer is power of two anyway) + * Jean II */ +#define IRDA_SKB_MAX_MTU 2064 +/* Maximum SIR frame that we expect to send, wrapped (i.e. with XBOFS + * and escaped characters on top of above). */ +#define IRDA_SIR_MAX_FRAME 4269 + +/* The SIR unwrapper async_unwrap_char() will use a Rx-copy-break mechanism + * when using the optional ZeroCopy Rx, where only small frames are memcpy + * to a smaller skb to save memory. This is the threshold under which copy + * will happen (and over which it won't happen). + * Some FIR drivers may use this #define as well... + * This is the same value as various Ethernet drivers. - Jean II */ +#define IRDA_RX_COPY_THRESHOLD 256 + +/* Function prototypes */ +int irda_device_init(void); +void irda_device_cleanup(void); + +/* IrLAP entry points used by the drivers. + * We declare them here to avoid the driver pulling a whole bunch stack + * headers they don't really need - Jean II */ +struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, + const char *hw_name); +void irlap_close(struct irlap_cb *self); + +/* Interface to be uses by IrLAP */ +void irda_device_set_media_busy(struct net_device *dev, int status); +int irda_device_is_media_busy(struct net_device *dev); +int irda_device_is_receiving(struct net_device *dev); + +/* Interface for internal use */ +static inline int irda_device_txqueue_empty(const struct net_device *dev) +{ + return qdisc_all_tx_empty(dev); +} +int irda_device_set_raw_mode(struct net_device* self, int status); +struct net_device *alloc_irdadev(int sizeof_priv); + +void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode); + +/* + * Function irda_get_mtt (skb) + * + * Utility function for getting the minimum turnaround time out of + * the skb, where it has been hidden in the cb field. + */ +static inline __u16 irda_get_mtt(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->mtt : 10000; +} + +/* + * Function irda_get_next_speed (skb) + * + * Extract the speed that should be set *after* this frame from the skb + * + * Note : return -1 for user space frames + */ +static inline __u32 irda_get_next_speed(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->next_speed : -1; +} + +/* + * Function irda_get_next_xbofs (skb) + * + * Extract the xbofs that should be set for this frame from the skb + * + * Note : default to 10 for user space frames + */ +static inline __u16 irda_get_xbofs(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->xbofs : 10; +} + +/* + * Function irda_get_next_xbofs (skb) + * + * Extract the xbofs that should be set *after* this frame from the skb + * + * Note : return -1 for user space frames + */ +static inline __u16 irda_get_next_xbofs(const struct sk_buff *skb) +{ + const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; + return (cb->magic == LAP_MAGIC) ? cb->next_xbofs : -1; +} +#endif /* IRDA_DEVICE_H */ + + diff --git a/include/net/irda/iriap.h b/include/net/irda/iriap.h new file mode 100644 index 00000000..fcc89649 --- /dev/null +++ b/include/net/irda/iriap.h @@ -0,0 +1,108 @@ +/********************************************************************* + * + * Filename: iriap.h + * Version: 0.5 + * Description: Information Access Protocol (IAP) + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Aug 21 00:02:07 1997 + * Modified at: Sat Dec 25 16:42:09 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRIAP_H +#define IRIAP_H + +#include <linux/types.h> +#include <linux/skbuff.h> + +#include <net/irda/iriap_event.h> +#include <net/irda/irias_object.h> +#include <net/irda/irqueue.h> /* irda_queue_t */ +#include <net/irda/timer.h> /* struct timer_list */ + +#define IAP_LST 0x80 +#define IAP_ACK 0x40 + +#define IAS_SERVER 0 +#define IAS_CLIENT 1 + +/* IrIAP Op-codes */ +#define GET_INFO_BASE 0x01 +#define GET_OBJECTS 0x02 +#define GET_VALUE 0x03 +#define GET_VALUE_BY_CLASS 0x04 +#define GET_OBJECT_INFO 0x05 +#define GET_ATTRIB_NAMES 0x06 + +#define IAS_SUCCESS 0 +#define IAS_CLASS_UNKNOWN 1 +#define IAS_ATTRIB_UNKNOWN 2 +#define IAS_DISCONNECT 10 + +typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id, + struct ias_value *value, void *priv); + +struct iriap_cb { + irda_queue_t q; /* Must be first */ + magic_t magic; /* Magic cookie */ + + int mode; /* Client or server */ + + __u32 saddr; + __u32 daddr; + __u8 operation; + + struct sk_buff *request_skb; + struct lsap_cb *lsap; + __u8 slsap_sel; + + /* Client states */ + IRIAP_STATE client_state; + IRIAP_STATE call_state; + + /* Server states */ + IRIAP_STATE server_state; + IRIAP_STATE r_connect_state; + + CONFIRM_CALLBACK confirm; + void *priv; /* Used to identify client */ + + __u8 max_header_size; + __u32 max_data_size; + + struct timer_list watchdog_timer; +}; + +int iriap_init(void); +void iriap_cleanup(void); + +struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, + CONFIRM_CALLBACK callback); +void iriap_close(struct iriap_cb *self); + +int iriap_getvaluebyclass_request(struct iriap_cb *self, + __u32 saddr, __u32 daddr, + char *name, char *attr); +void iriap_connect_request(struct iriap_cb *self); +void iriap_send_ack( struct iriap_cb *self); +void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb); + +void iriap_register_server(void); + +#endif + + diff --git a/include/net/irda/iriap_event.h b/include/net/irda/iriap_event.h new file mode 100644 index 00000000..89747f06 --- /dev/null +++ b/include/net/irda/iriap_event.h @@ -0,0 +1,85 @@ +/********************************************************************* + * + * Filename: iriap_event.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Sun Oct 31 22:02:54 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRIAP_FSM_H +#define IRIAP_FSM_H + +/* Forward because of circular include dependecies */ +struct iriap_cb; + +/* IrIAP states */ +typedef enum { + /* Client */ + S_DISCONNECT, + S_CONNECTING, + S_CALL, + + /* S-Call */ + S_MAKE_CALL, + S_CALLING, + S_OUTSTANDING, + S_REPLYING, + S_WAIT_FOR_CALL, + S_WAIT_ACTIVE, + + /* Server */ + R_DISCONNECT, + R_CALL, + + /* R-Connect */ + R_WAITING, + R_WAIT_ACTIVE, + R_RECEIVING, + R_EXECUTE, + R_RETURNING, +} IRIAP_STATE; + +typedef enum { + IAP_CALL_REQUEST, + IAP_CALL_REQUEST_GVBC, + IAP_CALL_RESPONSE, + IAP_RECV_F_LST, + IAP_LM_DISCONNECT_INDICATION, + IAP_LM_CONNECT_INDICATION, + IAP_LM_CONNECT_CONFIRM, +} IRIAP_EVENT; + +void iriap_next_client_state (struct iriap_cb *self, IRIAP_STATE state); +void iriap_next_call_state (struct iriap_cb *self, IRIAP_STATE state); +void iriap_next_server_state (struct iriap_cb *self, IRIAP_STATE state); +void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state); + + +void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +void iriap_do_call_event (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); + +void iriap_do_server_event (struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); +void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, + struct sk_buff *skb); + +#endif /* IRIAP_FSM_H */ + diff --git a/include/net/irda/irias_object.h b/include/net/irda/irias_object.h new file mode 100644 index 00000000..83f78081 --- /dev/null +++ b/include/net/irda/irias_object.h @@ -0,0 +1,108 @@ +/********************************************************************* + * + * Filename: irias_object.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Oct 1 22:49:50 1998 + * Modified at: Wed Dec 15 11:20:57 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef LM_IAS_OBJECT_H +#define LM_IAS_OBJECT_H + +#include <net/irda/irda.h> +#include <net/irda/irqueue.h> + +/* LM-IAS Attribute types */ +#define IAS_MISSING 0 +#define IAS_INTEGER 1 +#define IAS_OCT_SEQ 2 +#define IAS_STRING 3 + +/* Object ownership of attributes (user or kernel) */ +#define IAS_KERNEL_ATTR 0 +#define IAS_USER_ATTR 1 + +/* + * LM-IAS Object + */ +struct ias_object { + irda_queue_t q; /* Must be first! */ + magic_t magic; + + char *name; + int id; + hashbin_t *attribs; +}; + +/* + * Values used by LM-IAS attributes + */ +struct ias_value { + __u8 type; /* Value description */ + __u8 owner; /* Managed from user/kernel space */ + int charset; /* Only used by string type */ + int len; + + /* Value */ + union { + int integer; + char *string; + __u8 *oct_seq; + } t; +}; + +/* + * Attributes used by LM-IAS objects + */ +struct ias_attrib { + irda_queue_t q; /* Must be first! */ + int magic; + + char *name; /* Attribute name */ + struct ias_value *value; /* Attribute value */ +}; + +struct ias_object *irias_new_object(char *name, int id); +void irias_insert_object(struct ias_object *obj); +int irias_delete_object(struct ias_object *obj); +int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib, + int cleanobject); +void __irias_delete_object(struct ias_object *obj); + +void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, + int user); +void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, + int user); +void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, + int len, int user); +int irias_object_change_attribute(char *obj_name, char *attrib_name, + struct ias_value *new_value); +struct ias_object *irias_find_object(char *name); +struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name); + +struct ias_value *irias_new_string_value(char *string); +struct ias_value *irias_new_integer_value(int integer); +struct ias_value *irias_new_octseq_value(__u8 *octseq , int len); +struct ias_value *irias_new_missing_value(void); +void irias_delete_value(struct ias_value *value); + +extern struct ias_value irias_missing; +extern hashbin_t *irias_objects; + +#endif diff --git a/include/net/irda/irlan_client.h b/include/net/irda/irlan_client.h new file mode 100644 index 00000000..fa8455ed --- /dev/null +++ b/include/net/irda/irlan_client.h @@ -0,0 +1,42 @@ +/********************************************************************* + * + * Filename: irlan_client.h + * Version: 0.3 + * Description: IrDA LAN access layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Thu Apr 22 14:13:34 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_CLIENT_H +#define IRLAN_CLIENT_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#include <net/irda/irias_object.h> +#include <net/irda/irlan_event.h> + +void irlan_client_discovery_indication(discinfo_t *, DISCOVERY_MODE, void *); +void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr); + +void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb); +void irlan_client_get_value_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv); +#endif diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h new file mode 100644 index 00000000..73cacb3a --- /dev/null +++ b/include/net/irda/irlan_common.h @@ -0,0 +1,230 @@ +/********************************************************************* + * + * Filename: irlan_common.h + * Version: 0.8 + * Description: IrDA LAN access layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sun Oct 31 19:41:24 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_H +#define IRLAN_H + +#include <asm/param.h> /* for HZ */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#include <net/irda/irttp.h> + +#define IRLAN_MTU 1518 +#define IRLAN_TIMEOUT 10*HZ /* 10 seconds */ + +/* Command packet types */ +#define CMD_GET_PROVIDER_INFO 0 +#define CMD_GET_MEDIA_CHAR 1 +#define CMD_OPEN_DATA_CHANNEL 2 +#define CMD_CLOSE_DATA_CHAN 3 +#define CMD_RECONNECT_DATA_CHAN 4 +#define CMD_FILTER_OPERATION 5 + +/* Some responses */ +#define RSP_SUCCESS 0 +#define RSP_INSUFFICIENT_RESOURCES 1 +#define RSP_INVALID_COMMAND_FORMAT 2 +#define RSP_COMMAND_NOT_SUPPORTED 3 +#define RSP_PARAM_NOT_SUPPORTED 4 +#define RSP_VALUE_NOT_SUPPORTED 5 +#define RSP_NOT_OPEN 6 +#define RSP_AUTHENTICATION_REQUIRED 7 +#define RSP_INVALID_PASSWORD 8 +#define RSP_PROTOCOL_ERROR 9 +#define RSP_ASYNCHRONOUS_ERROR 255 + +/* Media types */ +#define MEDIA_802_3 1 +#define MEDIA_802_5 2 + +/* Filter parameters */ +#define DATA_CHAN 1 +#define FILTER_TYPE 2 +#define FILTER_MODE 3 + +/* Filter types */ +#define IRLAN_DIRECTED 0x01 +#define IRLAN_FUNCTIONAL 0x02 +#define IRLAN_GROUP 0x04 +#define IRLAN_MAC_FRAME 0x08 +#define IRLAN_MULTICAST 0x10 +#define IRLAN_BROADCAST 0x20 +#define IRLAN_IPX_SOCKET 0x40 + +/* Filter modes */ +#define ALL 1 +#define FILTER 2 +#define NONE 3 + +/* Filter operations */ +#define GET 1 +#define CLEAR 2 +#define ADD 3 +#define REMOVE 4 +#define DYNAMIC 5 + +/* Access types */ +#define ACCESS_DIRECT 1 +#define ACCESS_PEER 2 +#define ACCESS_HOSTED 3 + +#define IRLAN_BYTE 0 +#define IRLAN_SHORT 1 +#define IRLAN_ARRAY 2 + +/* IrLAN sits on top if IrTTP */ +#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER) +/* 1 byte for the command code and 1 byte for the parameter count */ +#define IRLAN_CMD_HEADER 2 + +#define IRLAN_STRING_PARAMETER_LEN(name, value) (1 + strlen((name)) + 2 \ + + strlen ((value))) +#define IRLAN_BYTE_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 1) +#define IRLAN_SHORT_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 2) + +/* + * IrLAN client + */ +struct irlan_client_cb { + int state; + + int open_retries; + + struct tsap_cb *tsap_ctrl; + __u32 max_sdu_size; + __u8 max_header_size; + + int access_type; /* Access type of provider */ + __u8 reconnect_key[255]; + __u8 key_len; + + __u16 recv_arb_val; + __u16 max_frame; + int filter_type; + + int unicast_open; + int broadcast_open; + + int tx_busy; + struct sk_buff_head txq; /* Transmit control queue */ + + struct iriap_cb *iriap; + + struct timer_list kick_timer; +}; + +/* + * IrLAN provider + */ +struct irlan_provider_cb { + int state; + + struct tsap_cb *tsap_ctrl; + __u32 max_sdu_size; + __u8 max_header_size; + + /* + * Store some values here which are used by the provider to parse + * the filter operations + */ + int data_chan; + int filter_type; + int filter_mode; + int filter_operation; + int filter_entry; + int access_type; /* Access type */ + __u16 send_arb_val; + + __u8 mac_address[6]; /* Generated MAC address for peer device */ +}; + +/* + * IrLAN control block + */ +struct irlan_cb { + int magic; + struct list_head dev_list; + struct net_device *dev; /* Ethernet device structure*/ + struct net_device_stats stats; + + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + int disconnect_reason; /* Why we got disconnected */ + + int media; /* Media type */ + __u8 version[2]; /* IrLAN version */ + + struct tsap_cb *tsap_data; /* Data TSAP */ + + int use_udata; /* Use Unit Data transfers */ + + __u8 stsap_sel_data; /* Source data TSAP selector */ + __u8 dtsap_sel_data; /* Destination data TSAP selector */ + __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */ + + struct irlan_client_cb client; /* Client specific fields */ + struct irlan_provider_cb provider; /* Provider specific fields */ + + __u32 max_sdu_size; + __u8 max_header_size; + + wait_queue_head_t open_wait; + struct timer_list watchdog_timer; +}; + +void irlan_close(struct irlan_cb *self); +void irlan_close_tsaps(struct irlan_cb *self); + +int irlan_register_netdev(struct irlan_cb *self); +void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel); +void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout); + +void irlan_open_data_tsap(struct irlan_cb *self); + +int irlan_run_ctrl_tx_queue(struct irlan_cb *self); + +struct irlan_cb *irlan_get_any(void); +void irlan_get_provider_info(struct irlan_cb *self); +void irlan_get_media_char(struct irlan_cb *self); +void irlan_open_data_channel(struct irlan_cb *self); +void irlan_close_data_channel(struct irlan_cb *self); +void irlan_set_multicast_filter(struct irlan_cb *self, int status); +void irlan_set_broadcast_filter(struct irlan_cb *self, int status); + +int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value); +int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value); +int irlan_insert_string_param(struct sk_buff *skb, char *param, char *value); +int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *value, + __u16 value_len); + +int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len); + +#endif + + diff --git a/include/net/irda/irlan_eth.h b/include/net/irda/irlan_eth.h new file mode 100644 index 00000000..de5c8169 --- /dev/null +++ b/include/net/irda/irlan_eth.h @@ -0,0 +1,32 @@ +/********************************************************************* + * + * Filename: irlan_eth.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Thu Oct 15 08:36:58 1998 + * Modified at: Fri May 14 23:29:00 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_ETH_H +#define IRLAN_ETH_H + +struct net_device *alloc_irlandev(const char *name); +int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb); + +void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow); +#endif diff --git a/include/net/irda/irlan_event.h b/include/net/irda/irlan_event.h new file mode 100644 index 00000000..6d9539f0 --- /dev/null +++ b/include/net/irda/irlan_event.h @@ -0,0 +1,81 @@ +/********************************************************************* + * + * Filename: irlan_event.h + * Version: + * Description: LAN access + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Tue Feb 2 09:45:17 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_EVENT_H +#define IRLAN_EVENT_H + +#include <linux/kernel.h> +#include <linux/skbuff.h> + +#include <net/irda/irlan_common.h> + +typedef enum { + IRLAN_IDLE, + IRLAN_QUERY, + IRLAN_CONN, + IRLAN_INFO, + IRLAN_MEDIA, + IRLAN_OPEN, + IRLAN_WAIT, + IRLAN_ARB, + IRLAN_DATA, + IRLAN_CLOSE, + IRLAN_SYNC +} IRLAN_STATE; + +typedef enum { + IRLAN_DISCOVERY_INDICATION, + IRLAN_IAS_PROVIDER_AVAIL, + IRLAN_IAS_PROVIDER_NOT_AVAIL, + IRLAN_LAP_DISCONNECT, + IRLAN_LMP_DISCONNECT, + IRLAN_CONNECT_COMPLETE, + IRLAN_DATA_INDICATION, + IRLAN_DATA_CONNECT_INDICATION, + IRLAN_RETRY_CONNECT, + + IRLAN_CONNECT_INDICATION, + IRLAN_GET_INFO_CMD, + IRLAN_GET_MEDIA_CMD, + IRLAN_OPEN_DATA_CMD, + IRLAN_FILTER_CONFIG_CMD, + + IRLAN_CHECK_CON_ARB, + IRLAN_PROVIDER_SIGNAL, + + IRLAN_WATCHDOG_TIMEOUT, +} IRLAN_EVENT; + +extern char *irlan_state[]; + +void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); + +void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event, + struct sk_buff *skb); + +void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state); +void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state); + +#endif diff --git a/include/net/irda/irlan_filter.h b/include/net/irda/irlan_filter.h new file mode 100644 index 00000000..a5a25394 --- /dev/null +++ b/include/net/irda/irlan_filter.h @@ -0,0 +1,35 @@ +/********************************************************************* + * + * Filename: irlan_filter.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Fri Jan 29 15:24:08 1999 + * Modified at: Sun Feb 7 23:35:31 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_FILTER_H +#define IRLAN_FILTER_H + +void irlan_check_command_param(struct irlan_cb *self, char *param, + char *value); +void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb); +#ifdef CONFIG_PROC_FS +void irlan_print_filter(struct seq_file *seq, int filter_type); +#endif + +#endif /* IRLAN_FILTER_H */ diff --git a/include/net/irda/irlan_provider.h b/include/net/irda/irlan_provider.h new file mode 100644 index 00000000..92f3b0e1 --- /dev/null +++ b/include/net/irda/irlan_provider.h @@ -0,0 +1,52 @@ +/********************************************************************* + * + * Filename: irlan_provider.h + * Version: 0.1 + * Description: IrDA LAN access layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:37 1997 + * Modified at: Sun May 9 12:26:11 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAN_SERVER_H +#define IRLAN_SERVER_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#include <net/irda/irlan_common.h> + +void irlan_provider_ctrl_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *skb); + + +void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *); + +int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb); +int irlan_provider_parse_command(struct irlan_cb *self, int cmd, + struct sk_buff *skb); + +void irlan_provider_send_reply(struct irlan_cb *self, int command, + int ret_code); +int irlan_provider_open_ctrl_tsap(struct irlan_cb *self); + +#endif + + diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h new file mode 100644 index 00000000..9d0c78ea --- /dev/null +++ b/include/net/irda/irlap.h @@ -0,0 +1,311 @@ +/********************************************************************* + * + * Filename: irlap.h + * Version: 0.8 + * Description: An IrDA LAP driver for Linux + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Fri Dec 10 13:21:17 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLAP_H +#define IRLAP_H + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/timer.h> + +#include <net/irda/irqueue.h> /* irda_queue_t */ +#include <net/irda/qos.h> /* struct qos_info */ +#include <net/irda/discovery.h> /* discovery_t */ +#include <net/irda/irlap_event.h> /* IRLAP_STATE, ... */ +#include <net/irda/irmod.h> /* struct notify_t */ + +#define CONFIG_IRDA_DYNAMIC_WINDOW 1 + +#define LAP_RELIABLE 1 +#define LAP_UNRELIABLE 0 + +#define LAP_ADDR_HEADER 1 /* IrLAP Address Header */ +#define LAP_CTRL_HEADER 1 /* IrLAP Control Header */ + +/* May be different when we get VFIR */ +#define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER) + +/* Each IrDA device gets a random 32 bits IRLAP device address */ +#define LAP_ALEN 4 + +#define BROADCAST 0xffffffff /* Broadcast device address */ +#define CBROADCAST 0xfe /* Connection broadcast address */ +#define XID_FORMAT 0x01 /* Discovery XID format */ + +/* Nobody seems to use this constant. */ +#define LAP_WINDOW_SIZE 8 +/* We keep the LAP queue very small to minimise the amount of buffering. + * this improve latency and reduce resource consumption. + * This work only because we have synchronous refilling of IrLAP through + * the flow control mechanism (via scheduler and IrTTP). + * 2 buffers is the minimum we can work with, one that we send while polling + * IrTTP, and another to know that we should not send the pf bit. + * Jean II */ +#define LAP_HIGH_THRESHOLD 2 +/* Some rare non TTP clients don't implement flow control, and + * so don't comply with the above limit (and neither with this one). + * For IAP and management, it doesn't matter, because they never transmit much. + *.For IrLPT, this should be fixed. + * - Jean II */ +#define LAP_MAX_QUEUE 10 +/* Please note that all IrDA management frames (LMP/TTP conn req/disc and + * IAS queries) fall in the second category and are sent to LAP even if TTP + * is stopped. This means that those frames will wait only a maximum of + * two (2) data frames before beeing sent on the "wire", which speed up + * new socket setup when the link is saturated. + * Same story for two sockets competing for the medium : if one saturates + * the LAP, when the other want to transmit it only has to wait for + * maximum three (3) packets (2 + one scheduling), which improve performance + * of delay sensitive applications. + * Jean II */ + +#define NR_EXPECTED 1 +#define NR_UNEXPECTED 0 +#define NR_INVALID -1 + +#define NS_EXPECTED 1 +#define NS_UNEXPECTED 0 +#define NS_INVALID -1 + +/* + * Meta information passed within the IrLAP state machine + */ +struct irlap_info { + __u8 caddr; /* Connection address */ + __u8 control; /* Frame type */ + __u8 cmd; + + __u32 saddr; + __u32 daddr; + + int pf; /* Poll/final bit set */ + + __u8 nr; /* Sequence number of next frame expected */ + __u8 ns; /* Sequence number of frame sent */ + + int S; /* Number of slots */ + int slot; /* Random chosen slot */ + int s; /* Current slot */ + + discovery_t *discovery; /* Discovery information */ +}; + +/* Main structure of IrLAP */ +struct irlap_cb { + irda_queue_t q; /* Must be first */ + magic_t magic; + + /* Device we are attached to */ + struct net_device *netdev; + char hw_name[2*IFNAMSIZ + 1]; + + /* Connection state */ + volatile IRLAP_STATE state; /* Current state */ + + /* Timers used by IrLAP */ + struct timer_list query_timer; + struct timer_list slot_timer; + struct timer_list discovery_timer; + struct timer_list final_timer; + struct timer_list poll_timer; + struct timer_list wd_timer; + struct timer_list backoff_timer; + + /* Media busy stuff */ + struct timer_list media_busy_timer; + int media_busy; + + /* Timeouts which will be different with different turn time */ + int slot_timeout; + int poll_timeout; + int final_timeout; + int wd_timeout; + + struct sk_buff_head txq; /* Frames to be transmitted */ + struct sk_buff_head txq_ultra; + + __u8 caddr; /* Connection address */ + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + + int retry_count; /* Times tried to establish connection */ + int add_wait; /* True if we are waiting for frame */ + + __u8 connect_pending; + __u8 disconnect_pending; + + /* To send a faster RR if tx queue empty */ +#ifdef CONFIG_IRDA_FAST_RR + int fast_RR_timeout; + int fast_RR; +#endif /* CONFIG_IRDA_FAST_RR */ + + int N1; /* N1 * F-timer = Negitiated link disconnect warning threshold */ + int N2; /* N2 * F-timer = Negitiated link disconnect time */ + int N3; /* Connection retry count */ + + int local_busy; + int remote_busy; + int xmitflag; + + __u8 vs; /* Next frame to be sent */ + __u8 vr; /* Next frame to be received */ + __u8 va; /* Last frame acked */ + int window; /* Nr of I-frames allowed to send */ + int window_size; /* Current negotiated window size */ + +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW + __u32 line_capacity; /* Number of bytes allowed to send */ + __u32 bytes_left; /* Number of bytes still allowed to transmit */ +#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ + + struct sk_buff_head wx_list; + + __u8 ack_required; + + /* XID parameters */ + __u8 S; /* Number of slots */ + __u8 slot; /* Random chosen slot */ + __u8 s; /* Current slot */ + int frame_sent; /* Have we sent reply? */ + + hashbin_t *discovery_log; + discovery_t *discovery_cmd; + + __u32 speed; /* Link speed */ + + struct qos_info qos_tx; /* QoS requested by peer */ + struct qos_info qos_rx; /* QoS requested by self */ + struct qos_info *qos_dev; /* QoS supported by device */ + + notify_t notify; /* Callbacks to IrLMP */ + + int mtt_required; /* Minumum turnaround time required */ + int xbofs_delay; /* Nr of XBOF's used to MTT */ + int bofs_count; /* Negotiated extra BOFs */ + int next_bofs; /* Negotiated extra BOFs after next frame */ + + int mode; /* IrLAP mode (primary, secondary or monitor) */ +}; + +/* + * Function prototypes + */ +int irlap_init(void); +void irlap_cleanup(void); + +struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, + const char *hw_name); +void irlap_close(struct irlap_cb *self); + +void irlap_connect_request(struct irlap_cb *self, __u32 daddr, + struct qos_info *qos, int sniff); +void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb); +void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb); +void irlap_connect_confirm(struct irlap_cb *, struct sk_buff *skb); + +void irlap_data_indication(struct irlap_cb *, struct sk_buff *, int unreliable); +void irlap_data_request(struct irlap_cb *, struct sk_buff *, int unreliable); + +#ifdef CONFIG_IRDA_ULTRA +void irlap_unitdata_request(struct irlap_cb *, struct sk_buff *); +void irlap_unitdata_indication(struct irlap_cb *, struct sk_buff *); +#endif /* CONFIG_IRDA_ULTRA */ + +void irlap_disconnect_request(struct irlap_cb *); +void irlap_disconnect_indication(struct irlap_cb *, LAP_REASON reason); + +void irlap_status_indication(struct irlap_cb *, int quality_of_link); + +void irlap_test_request(__u8 *info, int len); + +void irlap_discovery_request(struct irlap_cb *, discovery_t *discovery); +void irlap_discovery_confirm(struct irlap_cb *, hashbin_t *discovery_log); +void irlap_discovery_indication(struct irlap_cb *, discovery_t *discovery); + +void irlap_reset_indication(struct irlap_cb *self); +void irlap_reset_confirm(void); + +void irlap_update_nr_received(struct irlap_cb *, int nr); +int irlap_validate_nr_received(struct irlap_cb *, int nr); +int irlap_validate_ns_received(struct irlap_cb *, int ns); + +int irlap_generate_rand_time_slot(int S, int s); +void irlap_initiate_connection_state(struct irlap_cb *); +void irlap_flush_all_queues(struct irlap_cb *); +void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *); + +void irlap_apply_default_connection_parameters(struct irlap_cb *self); +void irlap_apply_connection_parameters(struct irlap_cb *self, int now); + +#define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER) +#define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq) + +/* Return TRUE if the node is in primary mode (i.e. master) + * - Jean II */ +static inline int irlap_is_primary(struct irlap_cb *self) +{ + int ret; + switch(self->state) { + case LAP_XMIT_P: + case LAP_NRM_P: + ret = 1; + break; + case LAP_XMIT_S: + case LAP_NRM_S: + ret = 0; + break; + default: + ret = -1; + } + return(ret); +} + +/* Clear a pending IrLAP disconnect. - Jean II */ +static inline void irlap_clear_disconnect(struct irlap_cb *self) +{ + self->disconnect_pending = FALSE; +} + +/* + * Function irlap_next_state (self, state) + * + * Switches state and provides debug information + * + */ +static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) +{ + /* + if (!self || self->magic != LAP_MAGIC) + return; + + IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]); + */ + self->state = state; +} + +#endif diff --git a/include/net/irda/irlap_event.h b/include/net/irda/irlap_event.h new file mode 100644 index 00000000..4c90824c --- /dev/null +++ b/include/net/irda/irlap_event.h @@ -0,0 +1,131 @@ +/********************************************************************* + * + * + * Filename: irlap_event.h + * Version: 0.1 + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Aug 16 00:59:29 1997 + * Modified at: Tue Dec 21 11:20:30 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRLAP_EVENT_H +#define IRLAP_EVENT_H + +#include <net/irda/irda.h> + +/* A few forward declarations (to make compiler happy) */ +struct irlap_cb; +struct irlap_info; + +/* IrLAP States */ +typedef enum { + LAP_NDM, /* Normal disconnected mode */ + LAP_QUERY, + LAP_REPLY, + LAP_CONN, /* Connect indication */ + LAP_SETUP, /* Setting up connection */ + LAP_OFFLINE, /* A really boring state */ + LAP_XMIT_P, + LAP_PCLOSE, + LAP_NRM_P, /* Normal response mode as primary */ + LAP_RESET_WAIT, + LAP_RESET, + LAP_NRM_S, /* Normal response mode as secondary */ + LAP_XMIT_S, + LAP_SCLOSE, + LAP_RESET_CHECK, +} IRLAP_STATE; + +/* IrLAP Events */ +typedef enum { + /* Services events */ + DISCOVERY_REQUEST, + CONNECT_REQUEST, + CONNECT_RESPONSE, + DISCONNECT_REQUEST, + DATA_REQUEST, + RESET_REQUEST, + RESET_RESPONSE, + + /* Send events */ + SEND_I_CMD, + SEND_UI_FRAME, + + /* Receive events */ + RECV_DISCOVERY_XID_CMD, + RECV_DISCOVERY_XID_RSP, + RECV_SNRM_CMD, + RECV_TEST_CMD, + RECV_TEST_RSP, + RECV_UA_RSP, + RECV_DM_RSP, + RECV_RD_RSP, + RECV_I_CMD, + RECV_I_RSP, + RECV_UI_FRAME, + RECV_FRMR_RSP, + RECV_RR_CMD, + RECV_RR_RSP, + RECV_RNR_CMD, + RECV_RNR_RSP, + RECV_REJ_CMD, + RECV_REJ_RSP, + RECV_SREJ_CMD, + RECV_SREJ_RSP, + RECV_DISC_CMD, + + /* Timer events */ + SLOT_TIMER_EXPIRED, + QUERY_TIMER_EXPIRED, + FINAL_TIMER_EXPIRED, + POLL_TIMER_EXPIRED, + DISCOVERY_TIMER_EXPIRED, + WD_TIMER_EXPIRED, + BACKOFF_TIMER_EXPIRED, + MEDIA_BUSY_TIMER_EXPIRED, +} IRLAP_EVENT; + +/* + * Disconnect reason code + */ +typedef enum { /* FIXME check the two first reason codes */ + LAP_DISC_INDICATION=1, /* Received a disconnect request from peer */ + LAP_NO_RESPONSE, /* To many retransmits without response */ + LAP_RESET_INDICATION, /* To many retransmits, or invalid nr/ns */ + LAP_FOUND_NONE, /* No devices were discovered */ + LAP_MEDIA_BUSY, + LAP_PRIMARY_CONFLICT, +} LAP_REASON; + +extern const char *const irlap_state[]; + +void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +void irlap_print_event(IRLAP_EVENT event); + +extern int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb); + +#endif diff --git a/include/net/irda/irlap_frame.h b/include/net/irda/irlap_frame.h new file mode 100644 index 00000000..6b1dc4f8 --- /dev/null +++ b/include/net/irda/irlap_frame.h @@ -0,0 +1,169 @@ +/********************************************************************* + * + * Filename: irlap_frame.h + * Version: 0.9 + * Description: IrLAP frame declarations + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Aug 19 10:27:26 1997 + * Modified at: Sat Dec 25 21:07:26 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRLAP_FRAME_H +#define IRLAP_FRAME_H + +#include <linux/skbuff.h> + +#include <net/irda/irda.h> + +/* A few forward declarations (to make compiler happy) */ +struct irlap_cb; +struct discovery_t; + +/* Frame types and templates */ +#define INVALID 0xff + +/* Unnumbered (U) commands */ +#define SNRM_CMD 0x83 /* Set Normal Response Mode */ +#define DISC_CMD 0x43 /* Disconnect */ +#define XID_CMD 0x2f /* Exchange Station Identification */ +#define TEST_CMD 0xe3 /* Test */ + +/* Unnumbered responses */ +#define RNRM_RSP 0x83 /* Request Normal Response Mode */ +#define UA_RSP 0x63 /* Unnumbered Acknowledgement */ +#define FRMR_RSP 0x87 /* Frame Reject */ +#define DM_RSP 0x0f /* Disconnect Mode */ +#define RD_RSP 0x43 /* Request Disconnection */ +#define XID_RSP 0xaf /* Exchange Station Identification */ +#define TEST_RSP 0xe3 /* Test frame */ + +/* Supervisory (S) */ +#define RR 0x01 /* Receive Ready */ +#define REJ 0x09 /* Reject */ +#define RNR 0x05 /* Receive Not Ready */ +#define SREJ 0x0d /* Selective Reject */ + +/* Information (I) */ +#define I_FRAME 0x00 /* Information Format */ +#define UI_FRAME 0x03 /* Unnumbered Information */ + +#define CMD_FRAME 0x01 +#define RSP_FRAME 0x00 + +#define PF_BIT 0x10 /* Poll/final bit */ + +/* Some IrLAP field lengths */ +/* + * Only baud rate triplet is 4 bytes (PV can be 2 bytes). + * All others params (7) are 3 bytes, so that's 7*3 + 1*4 bytes. + */ +#define IRLAP_NEGOCIATION_PARAMS_LEN 25 +#define IRLAP_DISCOVERY_INFO_LEN 32 + +struct disc_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct xid_frame { + __u8 caddr; /* Connection address */ + __u8 control; + __u8 ident; /* Should always be XID_FORMAT */ + __le32 saddr; /* Source device address */ + __le32 daddr; /* Destination device address */ + __u8 flags; /* Discovery flags */ + __u8 slotnr; + __u8 version; +} __packed; + +struct test_frame { + __u8 caddr; /* Connection address */ + __u8 control; + __le32 saddr; /* Source device address */ + __le32 daddr; /* Destination device address */ +} __packed; + +struct ua_frame { + __u8 caddr; + __u8 control; + __le32 saddr; /* Source device address */ + __le32 daddr; /* Dest device address */ +} __packed; + +struct dm_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct rd_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct rr_frame { + __u8 caddr; /* Connection address */ + __u8 control; +} __packed; + +struct i_frame { + __u8 caddr; + __u8 control; +} __packed; + +struct snrm_frame { + __u8 caddr; + __u8 control; + __le32 saddr; + __le32 daddr; + __u8 ncaddr; +} __packed; + +void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb); +void irlap_send_discovery_xid_frame(struct irlap_cb *, int S, __u8 s, + __u8 command, + struct discovery_t *discovery); +void irlap_send_snrm_frame(struct irlap_cb *, struct qos_info *); +void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, + struct sk_buff *cmd); +void irlap_send_ua_response_frame(struct irlap_cb *, struct qos_info *); +void irlap_send_dm_frame(struct irlap_cb *self); +void irlap_send_rd_frame(struct irlap_cb *self); +void irlap_send_disc_frame(struct irlap_cb *self); +void irlap_send_rr_frame(struct irlap_cb *self, int command); + +void irlap_send_data_primary(struct irlap_cb *, struct sk_buff *); +void irlap_send_data_primary_poll(struct irlap_cb *, struct sk_buff *); +void irlap_send_data_secondary(struct irlap_cb *, struct sk_buff *); +void irlap_send_data_secondary_final(struct irlap_cb *, struct sk_buff *); +void irlap_resend_rejected_frames(struct irlap_cb *, int command); +void irlap_resend_rejected_frame(struct irlap_cb *self, int command); + +void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, + __u8 caddr, int command); + +extern int irlap_insert_qos_negotiation_params(struct irlap_cb *self, + struct sk_buff *skb); + +#endif diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h new file mode 100644 index 00000000..3ffc1d0f --- /dev/null +++ b/include/net/irda/irlmp.h @@ -0,0 +1,294 @@ +/********************************************************************* + * + * Filename: irlmp.h + * Version: 0.9 + * Description: IrDA Link Management Protocol (LMP) layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 17 20:54:32 1997 + * Modified at: Fri Dec 10 13:23:01 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLMP_H +#define IRLMP_H + +#include <asm/param.h> /* for HZ */ + +#include <linux/types.h> + +#include <net/irda/irda.h> +#include <net/irda/qos.h> +#include <net/irda/irlap.h> /* LAP_MAX_HEADER, ... */ +#include <net/irda/irlmp_event.h> +#include <net/irda/irqueue.h> +#include <net/irda/discovery.h> + +/* LSAP-SEL's */ +#define LSAP_MASK 0x7f +#define LSAP_IAS 0x00 +#define LSAP_ANY 0xff +#define LSAP_MAX 0x6f /* 0x70-0x7f are reserved */ +#define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */ + +#define DEV_ADDR_ANY 0xffffffff + +#define LMP_HEADER 2 /* Dest LSAP + Source LSAP */ +#define LMP_CONTROL_HEADER 4 /* LMP_HEADER + opcode + parameter */ +#define LMP_PID_HEADER 1 /* Used by Ultra */ +#define LMP_MAX_HEADER (LMP_CONTROL_HEADER+LAP_MAX_HEADER) + +#define LM_MAX_CONNECTIONS 10 + +#define LM_IDLE_TIMEOUT 2*HZ /* 2 seconds for now */ + +typedef enum { + S_PNP = 0, + S_PDA, + S_COMPUTER, + S_PRINTER, + S_MODEM, + S_FAX, + S_LAN, + S_TELEPHONY, + S_COMM, + S_OBEX, + S_ANY, + S_END, +} SERVICE; + +/* For selective discovery */ +typedef void (*DISCOVERY_CALLBACK1) (discinfo_t *, DISCOVERY_MODE, void *); +/* For expiry (the same) */ +typedef void (*DISCOVERY_CALLBACK2) (discinfo_t *, DISCOVERY_MODE, void *); + +typedef struct { + irda_queue_t queue; /* Must be first */ + + __u16_host_order hints; /* Hint bits */ +} irlmp_service_t; + +typedef struct { + irda_queue_t queue; /* Must be first */ + + __u16_host_order hint_mask; + + DISCOVERY_CALLBACK1 disco_callback; /* Selective discovery */ + DISCOVERY_CALLBACK2 expir_callback; /* Selective expiration */ + void *priv; /* Used to identify client */ +} irlmp_client_t; + +/* + * Information about each logical LSAP connection + */ +struct lsap_cb { + irda_queue_t queue; /* Must be first */ + magic_t magic; + + unsigned long connected; /* set_bit used on this */ + int persistent; + + __u8 slsap_sel; /* Source (this) LSAP address */ + __u8 dlsap_sel; /* Destination LSAP address (if connected) */ +#ifdef CONFIG_IRDA_ULTRA + __u8 pid; /* Used by connectionless LSAP */ +#endif /* CONFIG_IRDA_ULTRA */ + struct sk_buff *conn_skb; /* Store skb here while connecting */ + + struct timer_list watchdog_timer; + + LSAP_STATE lsap_state; /* Connection state */ + notify_t notify; /* Indication/Confirm entry points */ + struct qos_info qos; /* QoS for this connection */ + + struct lap_cb *lap; /* Pointer to LAP connection structure */ +}; + +/* + * Used for caching the last slsap->dlsap->handle mapping + * + * We don't need to keep/match the remote address in the cache because + * we are associated with a specific LAP (which implies it). + * Jean II + */ +typedef struct { + int valid; + + __u8 slsap_sel; + __u8 dlsap_sel; + struct lsap_cb *lsap; +} CACHE_ENTRY; + +/* + * Information about each registred IrLAP layer + */ +struct lap_cb { + irda_queue_t queue; /* Must be first */ + magic_t magic; + + int reason; /* LAP disconnect reason */ + + IRLMP_STATE lap_state; + + struct irlap_cb *irlap; /* Instance of IrLAP layer */ + hashbin_t *lsaps; /* LSAP associated with this link */ + struct lsap_cb *flow_next; /* Next lsap to be polled for Tx */ + + __u8 caddr; /* Connection address */ + __u32 saddr; /* Source device address */ + __u32 daddr; /* Destination device address */ + + struct qos_info *qos; /* LAP QoS for this session */ + struct timer_list idle_timer; + +#ifdef CONFIG_IRDA_CACHE_LAST_LSAP + /* The lsap cache was moved from struct irlmp_cb to here because + * it must be associated with the specific LAP. Also, this + * improves performance. - Jean II */ + CACHE_ENTRY cache; /* Caching last slsap->dlsap->handle mapping */ +#endif +}; + +/* + * Main structure for IrLMP + */ +struct irlmp_cb { + magic_t magic; + + __u8 conflict_flag; + + discovery_t discovery_cmd; /* Discovery command to use by IrLAP */ + discovery_t discovery_rsp; /* Discovery response to use by IrLAP */ + + /* Last lsap picked automatically by irlmp_find_free_slsap() */ + int last_lsap_sel; + + struct timer_list discovery_timer; + + hashbin_t *links; /* IrLAP connection table */ + hashbin_t *unconnected_lsaps; + hashbin_t *clients; + hashbin_t *services; + + hashbin_t *cachelog; /* Current discovery log */ + + int running; + + __u16_host_order hints; /* Hint bits */ +}; + +/* Prototype declarations */ +int irlmp_init(void); +void irlmp_cleanup(void); +struct lsap_cb *irlmp_open_lsap(__u8 slsap, notify_t *notify, __u8 pid); +void irlmp_close_lsap( struct lsap_cb *self); + +__u16 irlmp_service_to_hint(int service); +void *irlmp_register_service(__u16 hints); +int irlmp_unregister_service(void *handle); +void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, + DISCOVERY_CALLBACK2 expir_clb, void *priv); +int irlmp_unregister_client(void *handle); +int irlmp_update_client(void *handle, __u16 hint_mask, + DISCOVERY_CALLBACK1 disco_clb, + DISCOVERY_CALLBACK2 expir_clb, void *priv); + +void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *); +void irlmp_unregister_link(__u32 saddr); + +int irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel, + __u32 saddr, __u32 daddr, + struct qos_info *, struct sk_buff *); +void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb); +int irlmp_connect_response(struct lsap_cb *, struct sk_buff *); +void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *); +struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance); + +void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, + struct sk_buff *userdata); +int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata); + +void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE mode); +void irlmp_discovery_request(int nslots); +discinfo_t *irlmp_get_discoveries(int *pn, __u16 mask, int nslots); +void irlmp_do_expiry(void); +void irlmp_do_discovery(int nslots); +discovery_t *irlmp_get_discovery_response(void); +void irlmp_discovery_expiry(discinfo_t *expiry, int number); + +int irlmp_data_request(struct lsap_cb *, struct sk_buff *); +void irlmp_data_indication(struct lsap_cb *, struct sk_buff *); + +int irlmp_udata_request(struct lsap_cb *, struct sk_buff *); +void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *); + +#ifdef CONFIG_IRDA_ULTRA +int irlmp_connless_data_request(struct lsap_cb *, struct sk_buff *, __u8); +void irlmp_connless_data_indication(struct lsap_cb *, struct sk_buff *); +#endif /* CONFIG_IRDA_ULTRA */ + +void irlmp_status_indication(struct lap_cb *, LINK_STATUS link, LOCK_STATUS lock); +void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow); + +LM_REASON irlmp_convert_lap_reason(LAP_REASON); + +static inline __u32 irlmp_get_saddr(const struct lsap_cb *self) +{ + return (self && self->lap) ? self->lap->saddr : 0; +} + +static inline __u32 irlmp_get_daddr(const struct lsap_cb *self) +{ + return (self && self->lap) ? self->lap->daddr : 0; +} + +extern const char *irlmp_reasons[]; +extern int sysctl_discovery_timeout; +extern int sysctl_discovery_slots; +extern int sysctl_discovery; +extern int sysctl_lap_keepalive_time; /* in ms, default is LM_IDLE_TIMEOUT */ +extern struct irlmp_cb *irlmp; + +/* Check if LAP queue is full. + * Used by IrTTP for low control, see comments in irlap.h - Jean II */ +static inline int irlmp_lap_tx_queue_full(struct lsap_cb *self) +{ + if (self == NULL) + return 0; + if (self->lap == NULL) + return 0; + if (self->lap->irlap == NULL) + return 0; + + return(IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD); +} + +/* After doing a irlmp_dup(), this get one of the two socket back into + * a state where it's waiting incomming connections. + * Note : this can be used *only* if the socket is not yet connected + * (i.e. NO irlmp_connect_response() done on this socket). + * - Jean II */ +static inline void irlmp_listen(struct lsap_cb *self) +{ + self->dlsap_sel = LSAP_ANY; + self->lap = NULL; + self->lsap_state = LSAP_DISCONNECTED; + /* Started when we received the LM_CONNECT_INDICATION */ + del_timer(&self->watchdog_timer); +} + +#endif diff --git a/include/net/irda/irlmp_event.h b/include/net/irda/irlmp_event.h new file mode 100644 index 00000000..9e4ec17a --- /dev/null +++ b/include/net/irda/irlmp_event.h @@ -0,0 +1,98 @@ +/********************************************************************* + * + * Filename: irlmp_event.h + * Version: 0.1 + * Description: IrDA-LMP event handling + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Thu Jul 8 12:18:54 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRLMP_EVENT_H +#define IRLMP_EVENT_H + +/* A few forward declarations (to make compiler happy) */ +struct irlmp_cb; +struct lsap_cb; +struct lap_cb; +struct discovery_t; + +/* LAP states */ +typedef enum { + /* IrLAP connection control states */ + LAP_STANDBY, /* No LAP connection */ + LAP_U_CONNECT, /* Starting LAP connection */ + LAP_ACTIVE, /* LAP connection is active */ +} IRLMP_STATE; + +/* LSAP connection control states */ +typedef enum { + LSAP_DISCONNECTED, /* No LSAP connection */ + LSAP_CONNECT, /* Connect indication from peer */ + LSAP_CONNECT_PEND, /* Connect request from service user */ + LSAP_DATA_TRANSFER_READY, /* LSAP connection established */ + LSAP_SETUP, /* Trying to set up LSAP connection */ + LSAP_SETUP_PEND, /* Request to start LAP connection */ +} LSAP_STATE; + +typedef enum { + /* LSAP events */ + LM_CONNECT_REQUEST, + LM_CONNECT_CONFIRM, + LM_CONNECT_RESPONSE, + LM_CONNECT_INDICATION, + + LM_DISCONNECT_INDICATION, + LM_DISCONNECT_REQUEST, + + LM_DATA_REQUEST, + LM_UDATA_REQUEST, + LM_DATA_INDICATION, + LM_UDATA_INDICATION, + + LM_WATCHDOG_TIMEOUT, + + /* IrLAP events */ + LM_LAP_CONNECT_REQUEST, + LM_LAP_CONNECT_INDICATION, + LM_LAP_CONNECT_CONFIRM, + LM_LAP_DISCONNECT_INDICATION, + LM_LAP_DISCONNECT_REQUEST, + LM_LAP_DISCOVERY_REQUEST, + LM_LAP_DISCOVERY_CONFIRM, + LM_LAP_IDLE_TIMEOUT, +} IRLMP_EVENT; + +extern const char *const irlmp_state[]; +extern const char *const irlsap_state[]; + +void irlmp_watchdog_timer_expired(void *data); +void irlmp_discovery_timer_expired(void *data); +void irlmp_idle_timer_expired(void *data); + +void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb); +int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb); + +#endif /* IRLMP_EVENT_H */ + + + + diff --git a/include/net/irda/irlmp_frame.h b/include/net/irda/irlmp_frame.h new file mode 100644 index 00000000..1906eb71 --- /dev/null +++ b/include/net/irda/irlmp_frame.h @@ -0,0 +1,62 @@ +/********************************************************************* + * + * Filename: irlmp_frame.h + * Version: 0.9 + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Aug 19 02:09:59 1997 + * Modified at: Fri Dec 10 13:21:53 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRMLP_FRAME_H +#define IRMLP_FRAME_H + +#include <linux/skbuff.h> + +#include <net/irda/discovery.h> + +/* IrLMP frame opcodes */ +#define CONNECT_CMD 0x01 +#define CONNECT_CNF 0x81 +#define DISCONNECT 0x02 +#define ACCESSMODE_CMD 0x03 +#define ACCESSMODE_CNF 0x83 + +#define CONTROL_BIT 0x80 + +void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, + int expedited, struct sk_buff *skb); +void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, + __u8 opcode, struct sk_buff *skb); +void irlmp_link_data_indication(struct lap_cb *, struct sk_buff *, + int unreliable); +#ifdef CONFIG_IRDA_ULTRA +void irlmp_link_unitdata_indication(struct lap_cb *, struct sk_buff *); +#endif /* CONFIG_IRDA_ULTRA */ + +void irlmp_link_connect_indication(struct lap_cb *, __u32 saddr, __u32 daddr, + struct qos_info *qos, struct sk_buff *skb); +void irlmp_link_connect_request(__u32 daddr); +void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, + struct sk_buff *skb); +void irlmp_link_disconnect_indication(struct lap_cb *, struct irlap_cb *, + LAP_REASON reason, struct sk_buff *); +void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log); +void irlmp_link_discovery_indication(struct lap_cb *, discovery_t *discovery); + +#endif diff --git a/include/net/irda/irmod.h b/include/net/irda/irmod.h new file mode 100644 index 00000000..86f0dbb8 --- /dev/null +++ b/include/net/irda/irmod.h @@ -0,0 +1,109 @@ +/********************************************************************* + * + * Filename: irmod.h + * Version: 0.3 + * Description: IrDA module and utilities functions + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Dec 15 13:58:52 1997 + * Modified at: Fri Jan 28 13:15:24 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charg. + * + ********************************************************************/ + +#ifndef IRMOD_H +#define IRMOD_H + +/* Misc status information */ +typedef enum { + STATUS_OK, + STATUS_ABORTED, + STATUS_NO_ACTIVITY, + STATUS_NOISY, + STATUS_REMOTE, +} LINK_STATUS; + +typedef enum { + LOCK_NO_CHANGE, + LOCK_LOCKED, + LOCK_UNLOCKED, +} LOCK_STATUS; + +typedef enum { FLOW_STOP, FLOW_START } LOCAL_FLOW; + +/* + * IrLMP disconnect reasons. The order is very important, since they + * correspond to disconnect reasons sent in IrLMP disconnect frames, so + * please do not touch :-) + */ +typedef enum { + LM_USER_REQUEST = 1, /* User request */ + LM_LAP_DISCONNECT, /* Unexpected IrLAP disconnect */ + LM_CONNECT_FAILURE, /* Failed to establish IrLAP connection */ + LM_LAP_RESET, /* IrLAP reset */ + LM_INIT_DISCONNECT, /* Link Management initiated disconnect */ + LM_LSAP_NOTCONN, /* Data delivered on unconnected LSAP */ + LM_NON_RESP_CLIENT, /* Non responsive LM-MUX client */ + LM_NO_AVAIL_CLIENT, /* No available LM-MUX client */ + LM_CONN_HALF_OPEN, /* Connection is half open */ + LM_BAD_SOURCE_ADDR, /* Illegal source address (i.e 0x00) */ +} LM_REASON; +#define LM_UNKNOWN 0xff /* Unspecified disconnect reason */ + +/* A few forward declarations (to make compiler happy) */ +struct qos_info; /* in <net/irda/qos.h> */ + +/* + * Notify structure used between transport and link management layers + */ +typedef struct { + int (*data_indication)(void *priv, void *sap, struct sk_buff *skb); + int (*udata_indication)(void *priv, void *sap, struct sk_buff *skb); + void (*connect_confirm)(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 max_header_size, struct sk_buff *skb); + void (*connect_indication)(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_size, + __u8 max_header_size, struct sk_buff *skb); + void (*disconnect_indication)(void *instance, void *sap, + LM_REASON reason, struct sk_buff *); + void (*flow_indication)(void *instance, void *sap, LOCAL_FLOW flow); + void (*status_indication)(void *instance, + LINK_STATUS link, LOCK_STATUS lock); + void *instance; /* Layer instance pointer */ + char name[16]; /* Name of layer */ +} notify_t; + +#define NOTIFY_MAX_NAME 16 + +/* Zero the notify structure */ +void irda_notify_init(notify_t *notify); + +/* Locking wrapper - Note the inverted logic on irda_lock(). + * Those function basically return false if the lock is already in the + * position you want to set it. - Jean II */ +#define irda_lock(lock) (! test_and_set_bit(0, (void *) (lock))) +#define irda_unlock(lock) (test_and_clear_bit(0, (void *) (lock))) + +#endif /* IRMOD_H */ + + + + + + + + + diff --git a/include/net/irda/irqueue.h b/include/net/irda/irqueue.h new file mode 100644 index 00000000..37f512bd --- /dev/null +++ b/include/net/irda/irqueue.h @@ -0,0 +1,96 @@ +/********************************************************************* + * + * Filename: irqueue.h + * Version: 0.3 + * Description: General queue implementation + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Tue Jun 9 13:26:50 1998 + * Modified at: Thu Oct 7 13:25:16 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no> + * Copyright (c) 1998, Dag Brattli + * All Rights Reserved. + * + * This code is taken from the Vortex Operating System written by Aage + * Kvalnes and has been ported to Linux and Linux/IR by Dag Brattli + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#include <linux/types.h> +#include <linux/spinlock.h> + +#ifndef IRDA_QUEUE_H +#define IRDA_QUEUE_H + +#define NAME_SIZE 32 + +/* + * Hash types (some flags can be xored) + * See comments in irqueue.c for which one to use... + */ +#define HB_NOLOCK 0 /* No concurent access prevention */ +#define HB_LOCK 1 /* Prevent concurent write with global lock */ + +/* + * Hash defines + */ +#define HASHBIN_SIZE 8 +#define HASHBIN_MASK 0x7 + +#ifndef IRDA_ALIGN +#define IRDA_ALIGN __attribute__((aligned)) +#endif + +#define Q_NULL { NULL, NULL, "", 0 } + +typedef void (*FREE_FUNC)(void *arg); + +struct irda_queue { + struct irda_queue *q_next; + struct irda_queue *q_prev; + + char q_name[NAME_SIZE]; + long q_hash; /* Must be able to cast a (void *) */ +}; +typedef struct irda_queue irda_queue_t; + +typedef struct hashbin_t { + __u32 magic; + int hb_type; + int hb_size; + spinlock_t hb_spinlock; /* HB_LOCK - Can be used by the user */ + + irda_queue_t* hb_queue[HASHBIN_SIZE] IRDA_ALIGN; + + irda_queue_t* hb_current; +} hashbin_t; + +hashbin_t *hashbin_new(int type); +int hashbin_delete(hashbin_t* hashbin, FREE_FUNC func); +int hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func); +void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, + const char* name); +void* hashbin_remove(hashbin_t* hashbin, long hashv, const char* name); +void* hashbin_remove_first(hashbin_t *hashbin); +void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry); +void* hashbin_find(hashbin_t* hashbin, long hashv, const char* name); +void* hashbin_lock_find(hashbin_t* hashbin, long hashv, const char* name); +void* hashbin_find_next(hashbin_t* hashbin, long hashv, const char* name, + void ** pnext); +irda_queue_t *hashbin_get_first(hashbin_t *hashbin); +irda_queue_t *hashbin_get_next(hashbin_t *hashbin); + +#define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size + +#endif diff --git a/include/net/irda/irttp.h b/include/net/irda/irttp.h new file mode 100644 index 00000000..11aee7a2 --- /dev/null +++ b/include/net/irda/irttp.h @@ -0,0 +1,210 @@ +/********************************************************************* + * + * Filename: irttp.h + * Version: 1.0 + * Description: Tiny Transport Protocol (TTP) definitions + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sun Aug 31 20:14:31 1997 + * Modified at: Sun Dec 12 13:09:07 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef IRTTP_H +#define IRTTP_H + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> + +#include <net/irda/irda.h> +#include <net/irda/irlmp.h> /* struct lsap_cb */ +#include <net/irda/qos.h> /* struct qos_info */ +#include <net/irda/irqueue.h> + +#define TTP_MAX_CONNECTIONS LM_MAX_CONNECTIONS +#define TTP_HEADER 1 +#define TTP_MAX_HEADER (TTP_HEADER + LMP_MAX_HEADER) +#define TTP_SAR_HEADER 5 +#define TTP_PARAMETERS 0x80 +#define TTP_MORE 0x80 + +/* Transmission queue sizes */ +/* Worst case scenario, two window of data - Jean II */ +#define TTP_TX_MAX_QUEUE 14 +/* We need to keep at least 5 frames to make sure that we can refill + * appropriately the LAP layer. LAP keeps only two buffers, and we need + * to have 7 to make a full window - Jean II */ +#define TTP_TX_LOW_THRESHOLD 5 +/* Most clients are synchronous with respect to flow control, so we can + * keep a low number of Tx buffers in TTP - Jean II */ +#define TTP_TX_HIGH_THRESHOLD 7 + +/* Receive queue sizes */ +/* Minimum of credit that the peer should hold. + * If the peer has less credits than 9 frames, we will explicitly send + * him some credits (through irttp_give_credit() and a specific frame). + * Note that when we give credits it's likely that it won't be sent in + * this LAP window, but in the next one. So, we make sure that the peer + * has something to send while waiting for credits (one LAP window == 7 + * + 1 frames while he process the credits). - Jean II */ +#define TTP_RX_MIN_CREDIT 8 +/* This is the default maximum number of credits held by the peer, so the + * default maximum number of frames he can send us before needing flow + * control answer from us (this may be negociated differently at TSAP setup). + * We want to minimise the number of times we have to explicitly send some + * credit to the peer, hoping we can piggyback it on the return data. In + * particular, it doesn't make sense for us to send credit more than once + * per LAP window. + * Moreover, giving credits has some latency, so we need strictly more than + * a LAP window, otherwise we may already have credits in our Tx queue. + * But on the other hand, we don't want to keep too many Rx buffer here + * before starting to flow control the other end, so make it exactly one + * LAP window + 1 + MIN_CREDITS. - Jean II */ +#define TTP_RX_DEFAULT_CREDIT 16 +/* Maximum number of credits we can allow the peer to have, and therefore + * maximum Rx queue size. + * Note that we try to deliver packets to the higher layer every time we + * receive something, so in normal mode the Rx queue will never contains + * more than one or two packets. - Jean II */ +#define TTP_RX_MAX_CREDIT 21 + +/* What clients should use when calling ttp_open_tsap() */ +#define DEFAULT_INITIAL_CREDIT TTP_RX_DEFAULT_CREDIT + +/* Some priorities for disconnect requests */ +#define P_NORMAL 0 +#define P_HIGH 1 + +#define TTP_SAR_DISABLE 0 +#define TTP_SAR_UNBOUND 0xffffffff + +/* Parameters */ +#define TTP_MAX_SDU_SIZE 0x01 + +/* + * This structure contains all data associated with one instance of a TTP + * connection. + */ +struct tsap_cb { + irda_queue_t q; /* Must be first */ + magic_t magic; /* Just in case */ + + __u8 stsap_sel; /* Source TSAP */ + __u8 dtsap_sel; /* Destination TSAP */ + + struct lsap_cb *lsap; /* Corresponding LSAP to this TSAP */ + + __u8 connected; /* TSAP connected */ + + __u8 initial_credit; /* Initial credit to give peer */ + + int avail_credit; /* Available credit to return to peer */ + int remote_credit; /* Credit held by peer TTP entity */ + int send_credit; /* Credit held by local TTP entity */ + + struct sk_buff_head tx_queue; /* Frames to be transmitted */ + struct sk_buff_head rx_queue; /* Received frames */ + struct sk_buff_head rx_fragments; + int tx_queue_lock; + int rx_queue_lock; + spinlock_t lock; + + notify_t notify; /* Callbacks to client layer */ + + struct net_device_stats stats; + struct timer_list todo_timer; + + __u32 max_seg_size; /* Max data that fit into an IrLAP frame */ + __u8 max_header_size; + + int rx_sdu_busy; /* RxSdu.busy */ + __u32 rx_sdu_size; /* Current size of a partially received frame */ + __u32 rx_max_sdu_size; /* Max receive user data size */ + + int tx_sdu_busy; /* TxSdu.busy */ + __u32 tx_max_sdu_size; /* Max transmit user data size */ + + int close_pend; /* Close, but disconnect_pend */ + unsigned long disconnect_pend; /* Disconnect, but still data to send */ + struct sk_buff *disconnect_skb; +}; + +struct irttp_cb { + magic_t magic; + hashbin_t *tsaps; +}; + +int irttp_init(void); +void irttp_cleanup(void); + +struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify); +int irttp_close_tsap(struct tsap_cb *self); + +int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb); +int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb); + +int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, + __u32 saddr, __u32 daddr, + struct qos_info *qos, __u32 max_sdu_size, + struct sk_buff *userdata); +int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, + struct sk_buff *userdata); +int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *skb, + int priority); +void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow); +struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance); + +static inline __u32 irttp_get_saddr(struct tsap_cb *self) +{ + return irlmp_get_saddr(self->lsap); +} + +static inline __u32 irttp_get_daddr(struct tsap_cb *self) +{ + return irlmp_get_daddr(self->lsap); +} + +static inline __u32 irttp_get_max_seg_size(struct tsap_cb *self) +{ + return self->max_seg_size; +} + +/* After doing a irttp_dup(), this get one of the two socket back into + * a state where it's waiting incomming connections. + * Note : this can be used *only* if the socket is not yet connected + * (i.e. NO irttp_connect_response() done on this socket). + * - Jean II */ +static inline void irttp_listen(struct tsap_cb *self) +{ + irlmp_listen(self->lsap); + self->dtsap_sel = LSAP_ANY; +} + +/* Return TRUE if the node is in primary mode (i.e. master) + * - Jean II */ +static inline int irttp_is_primary(struct tsap_cb *self) +{ + if ((self == NULL) || + (self->lsap == NULL) || + (self->lsap->lap == NULL) || + (self->lsap->lap->irlap == NULL)) + return -2; + return(irlap_is_primary(self->lsap->lap->irlap)); +} + +#endif /* IRTTP_H */ diff --git a/include/net/irda/parameters.h b/include/net/irda/parameters.h new file mode 100644 index 00000000..c0d93884 --- /dev/null +++ b/include/net/irda/parameters.h @@ -0,0 +1,102 @@ +/********************************************************************* + * + * Filename: parameters.h + * Version: 1.0 + * Description: A more general way to handle (pi,pl,pv) parameters + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Jun 7 08:47:28 1999 + * Modified at: Sun Jan 30 14:05:14 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Michel Dänzer <daenzer@debian.org>, 10/2001 + * - simplify irda_pv_t to avoid endianness issues + * + ********************************************************************/ + +#ifndef IRDA_PARAMS_H +#define IRDA_PARAMS_H + +/* + * The currently supported types. Beware not to change the sequence since + * it a good reason why the sized integers has a value equal to their size + */ +typedef enum { + PV_INTEGER, /* Integer of any (pl) length */ + PV_INT_8_BITS, /* Integer of 8 bits in length */ + PV_INT_16_BITS, /* Integer of 16 bits in length */ + PV_STRING, /* \0 terminated string */ + PV_INT_32_BITS, /* Integer of 32 bits in length */ + PV_OCT_SEQ, /* Octet sequence */ + PV_NO_VALUE /* Does not contain any value (pl=0) */ +} PV_TYPE; + +/* Bit 7 of type field */ +#define PV_BIG_ENDIAN 0x80 +#define PV_LITTLE_ENDIAN 0x00 +#define PV_MASK 0x7f /* To mask away endian bit */ + +#define PV_PUT 0 +#define PV_GET 1 + +typedef union { + char *c; + __u32 i; + __u32 *ip; +} irda_pv_t; + +typedef struct { + __u8 pi; + __u8 pl; + irda_pv_t pv; +} irda_param_t; + +typedef int (*PI_HANDLER)(void *self, irda_param_t *param, int get); +typedef int (*PV_HANDLER)(void *self, __u8 *buf, int len, __u8 pi, + PV_TYPE type, PI_HANDLER func); + +typedef struct { + PI_HANDLER func; /* Handler for this parameter identifier */ + PV_TYPE type; /* Data type for this parameter */ +} pi_minor_info_t; + +typedef struct { + pi_minor_info_t *pi_minor_call_table; + int len; +} pi_major_info_t; + +typedef struct { + pi_major_info_t *tables; + int len; + __u8 pi_mask; + int pi_major_offset; +} pi_param_info_t; + +int irda_param_pack(__u8 *buf, char *fmt, ...); + +int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, + pi_param_info_t *info); +int irda_param_extract_all(void *self, __u8 *buf, int len, + pi_param_info_t *info); + +#define irda_param_insert_byte(buf,pi,pv) irda_param_pack(buf,"bbb",pi,1,pv) + +#endif /* IRDA_PARAMS_H */ + diff --git a/include/net/irda/qos.h b/include/net/irda/qos.h new file mode 100644 index 00000000..cc577dc0 --- /dev/null +++ b/include/net/irda/qos.h @@ -0,0 +1,103 @@ +/********************************************************************* + * + * Filename: qos.h + * Version: 1.0 + * Description: Quality of Service definitions + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Fri Sep 19 23:21:09 1997 + * Modified at: Thu Dec 2 13:51:54 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#ifndef IRDA_QOS_H +#define IRDA_QOS_H + +#include <linux/skbuff.h> + +#include <net/irda/parameters.h> + +#define PI_BAUD_RATE 0x01 +#define PI_MAX_TURN_TIME 0x82 +#define PI_DATA_SIZE 0x83 +#define PI_WINDOW_SIZE 0x84 +#define PI_ADD_BOFS 0x85 +#define PI_MIN_TURN_TIME 0x86 +#define PI_LINK_DISC 0x08 + +#define IR_115200_MAX 0x3f + +/* Baud rates (first byte) */ +#define IR_2400 0x01 +#define IR_9600 0x02 +#define IR_19200 0x04 +#define IR_38400 0x08 +#define IR_57600 0x10 +#define IR_115200 0x20 +#define IR_576000 0x40 +#define IR_1152000 0x80 + +/* Baud rates (second byte) */ +#define IR_4000000 0x01 +#define IR_16000000 0x02 + +/* Quality of Service information */ +typedef struct { + __u32 value; + __u16 bits; /* LSB is first byte, MSB is second byte */ +} qos_value_t; + +struct qos_info { + magic_t magic; + + qos_value_t baud_rate; /* IR_11520O | ... */ + qos_value_t max_turn_time; + qos_value_t data_size; + qos_value_t window_size; + qos_value_t additional_bofs; + qos_value_t min_turn_time; + qos_value_t link_disc_time; + + qos_value_t power; +}; + +extern int sysctl_max_baud_rate; +extern int sysctl_max_inactive_time; + +void irda_init_max_qos_capabilies(struct qos_info *qos); +void irda_qos_compute_intersection(struct qos_info *, struct qos_info *); + +__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time); + +void irda_qos_bits_to_value(struct qos_info *qos); + +/* So simple, how could we not inline those two ? + * Note : one byte is 10 bits if you include start and stop bits + * Jean II */ +#define irlap_min_turn_time_in_bytes(speed, min_turn_time) ( \ + speed * min_turn_time / 10000000 \ +) +#define irlap_xbofs_in_usec(speed, xbofs) ( \ + xbofs * 10000000 / speed \ +) + +#endif + diff --git a/include/net/irda/timer.h b/include/net/irda/timer.h new file mode 100644 index 00000000..cb2615cc --- /dev/null +++ b/include/net/irda/timer.h @@ -0,0 +1,105 @@ +/********************************************************************* + * + * Filename: timer.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Sat Aug 16 00:59:29 1997 + * Modified at: Thu Oct 7 12:25:24 1999 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef TIMER_H +#define TIMER_H + +#include <linux/timer.h> +#include <linux/jiffies.h> + +#include <asm/param.h> /* for HZ */ + +#include <net/irda/irda.h> + +/* A few forward declarations (to make compiler happy) */ +struct irlmp_cb; +struct irlap_cb; +struct lsap_cb; +struct lap_cb; + +/* + * Timeout definitions, some defined in IrLAP 6.13.5 - p. 92 + */ +#define POLL_TIMEOUT (450*HZ/1000) /* Must never exceed 500 ms */ +#define FINAL_TIMEOUT (500*HZ/1000) /* Must never exceed 500 ms */ + +/* + * Normally twice of p-timer. Note 3, IrLAP 6.3.11.2 - p. 60 suggests + * at least twice duration of the P-timer. + */ +#define WD_TIMEOUT (POLL_TIMEOUT*2) + +#define MEDIABUSY_TIMEOUT (500*HZ/1000) /* 500 msec */ +#define SMALLBUSY_TIMEOUT (100*HZ/1000) /* 100 msec - IrLAP 6.13.4 */ + +/* + * Slot timer must never exceed 85 ms, and must always be at least 25 ms, + * suggested to 75-85 msec by IrDA lite. This doesn't work with a lot of + * devices, and other stackes uses a lot more, so it's best we do it as well + * (Note : this is the default value and sysctl overides it - Jean II) + */ +#define SLOT_TIMEOUT (90*HZ/1000) + +/* + * The latest discovery frame (XID) is longer due to the extra discovery + * information (hints, device name...). This is its extra length. + * We use that when setting the query timeout. Jean II + */ +#define XIDEXTRA_TIMEOUT (34*HZ/1000) /* 34 msec */ + +#define WATCHDOG_TIMEOUT (20*HZ) /* 20 sec */ + +typedef void (*TIMER_CALLBACK)(void *); + +static inline void irda_start_timer(struct timer_list *ptimer, int timeout, + void* data, TIMER_CALLBACK callback) +{ + ptimer->function = (void (*)(unsigned long)) callback; + ptimer->data = (unsigned long) data; + + /* Set new value for timer (update or add timer). + * We use mod_timer() because it's more efficient and also + * safer with respect to race conditions - Jean II */ + mod_timer(ptimer, jiffies + timeout); +} + + +void irlap_start_slot_timer(struct irlap_cb *self, int timeout); +void irlap_start_query_timer(struct irlap_cb *self, int S, int s); +void irlap_start_final_timer(struct irlap_cb *self, int timeout); +void irlap_start_wd_timer(struct irlap_cb *self, int timeout); +void irlap_start_backoff_timer(struct irlap_cb *self, int timeout); + +void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout); +void irlap_stop_mbusy_timer(struct irlap_cb *); + +void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout); +void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout); +void irlmp_start_idle_timer(struct lap_cb *, int timeout); +void irlmp_stop_idle_timer(struct lap_cb *self); + +#endif + diff --git a/include/net/irda/wrapper.h b/include/net/irda/wrapper.h new file mode 100644 index 00000000..2942ad6a --- /dev/null +++ b/include/net/irda/wrapper.h @@ -0,0 +1,58 @@ +/********************************************************************* + * + * Filename: wrapper.h + * Version: 1.2 + * Description: IrDA SIR async wrapper layer + * Status: Experimental. + * Author: Dag Brattli <dagb@cs.uit.no> + * Created at: Mon Aug 4 20:40:53 1997 + * Modified at: Tue Jan 11 12:37:29 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> + * + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef WRAPPER_H +#define WRAPPER_H + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> + +#include <net/irda/irda_device.h> /* iobuff_t */ + +#define BOF 0xc0 /* Beginning of frame */ +#define XBOF 0xff +#define EOF 0xc1 /* End of frame */ +#define CE 0x7d /* Control escape */ + +#define STA BOF /* Start flag */ +#define STO EOF /* End flag */ + +#define IRDA_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* States for receving a frame in async mode */ +enum { + OUTSIDE_FRAME, + BEGIN_FRAME, + LINK_ESCAPE, + INSIDE_FRAME +}; + +/* Proto definitions */ +int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize); +void async_unwrap_char(struct net_device *dev, struct net_device_stats *stats, + iobuff_t *buf, __u8 byte); + +#endif diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h new file mode 100644 index 00000000..f82a1e87 --- /dev/null +++ b/include/net/iucv/af_iucv.h @@ -0,0 +1,102 @@ +/* + * Copyright 2006 IBM Corporation + * IUCV protocol stack for Linux on zSeries + * Version 1.0 + * Author(s): Jennifer Hunt <jenhunt@us.ibm.com> + * + */ + +#ifndef __AFIUCV_H +#define __AFIUCV_H + +#include <asm/types.h> +#include <asm/byteorder.h> +#include <linux/list.h> +#include <linux/poll.h> +#include <linux/socket.h> + +#ifndef AF_IUCV +#define AF_IUCV 32 +#define PF_IUCV AF_IUCV +#endif + +/* Connection and socket states */ +enum { + IUCV_CONNECTED = 1, + IUCV_OPEN, + IUCV_BOUND, + IUCV_LISTEN, + IUCV_SEVERED, + IUCV_DISCONN, + IUCV_CLOSING, + IUCV_CLOSED +}; + +#define IUCV_QUEUELEN_DEFAULT 65535 +#define IUCV_CONN_TIMEOUT (HZ * 40) +#define IUCV_DISCONN_TIMEOUT (HZ * 2) +#define IUCV_CONN_IDLE_TIMEOUT (HZ * 60) +#define IUCV_BUFSIZE_DEFAULT 32768 + +/* IUCV socket address */ +struct sockaddr_iucv { + sa_family_t siucv_family; + unsigned short siucv_port; /* Reserved */ + unsigned int siucv_addr; /* Reserved */ + char siucv_nodeid[8]; /* Reserved */ + char siucv_user_id[8]; /* Guest User Id */ + char siucv_name[8]; /* Application Name */ +}; + + +/* Common socket structures and functions */ +struct sock_msg_q { + struct iucv_path *path; + struct iucv_message msg; + struct list_head list; + spinlock_t lock; +}; + +#define iucv_sk(__sk) ((struct iucv_sock *) __sk) + +struct iucv_sock { + struct sock sk; + char src_user_id[8]; + char src_name[8]; + char dst_user_id[8]; + char dst_name[8]; + struct list_head accept_q; + spinlock_t accept_q_lock; + struct sock *parent; + struct iucv_path *path; + struct sk_buff_head send_skb_q; + struct sk_buff_head backlog_skb_q; + struct sock_msg_q message_q; + unsigned int send_tag; + u8 flags; + u16 msglimit; +}; + +/* iucv socket options (SOL_IUCV) */ +#define SO_IPRMDATA_MSG 0x0080 /* send/recv IPRM_DATA msgs */ +#define SO_MSGLIMIT 0x1000 /* get/set IUCV MSGLIMIT */ + +/* iucv related control messages (scm) */ +#define SCM_IUCV_TRGCLS 0x0001 /* target class control message */ + +struct iucv_sock_list { + struct hlist_head head; + rwlock_t lock; + atomic_t autobind_name; +}; + +unsigned int iucv_sock_poll(struct file *file, struct socket *sock, + poll_table *wait); +void iucv_sock_link(struct iucv_sock_list *l, struct sock *s); +void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *s); +int iucv_sock_wait_cnt(struct sock *sk, unsigned long timeo); +void iucv_accept_enqueue(struct sock *parent, struct sock *sk); +void iucv_accept_unlink(struct sock *sk); +struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock); + +#endif /* __IUCV_H */ diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h new file mode 100644 index 00000000..205a3360 --- /dev/null +++ b/include/net/iucv/iucv.h @@ -0,0 +1,461 @@ +/* + * drivers/s390/net/iucv.h + * IUCV base support. + * + * S390 version + * Copyright 2000, 2006 IBM Corporation + * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) + * Xenia Tkatschow (xenia@us.ibm.com) + * Rewritten for af_iucv: + * Martin Schwidefsky <schwidefsky@de.ibm.com> + * + * + * Functionality: + * To explore any of the IUCV functions, one must first register their + * program using iucv_register(). Once your program has successfully + * completed a register, it can exploit the other functions. + * For furthur reference on all IUCV functionality, refer to the + * CP Programming Services book, also available on the web thru + * www.vm.ibm.com/pubs, manual # SC24-6084 + * + * Definition of Return Codes + * - All positive return codes including zero are reflected back + * from CP. The definition of each return code can be found in + * CP Programming Services book. + * - Return Code of: + * -EINVAL: Invalid value + * -ENOMEM: storage allocation failed + */ + +#include <linux/types.h> +#include <linux/slab.h> +#include <asm/debug.h> + +/* + * IUCV option flags usable by device drivers: + * + * IUCV_IPRMDATA Indicates that your program can handle a message in the + * parameter list / a message is sent in the parameter list. + * Used for iucv_path_accept, iucv_path_connect, + * iucv_message_reply, iucv_message_send, iucv_message_send2way. + * IUCV_IPQUSCE Indicates that you do not want to receive messages on this + * path until an iucv_path_resume is issued. + * Used for iucv_path_accept, iucv_path_connect. + * IUCV_IPBUFLST Indicates that an address list is used for the message data. + * Used for iucv_message_receive, iucv_message_send, + * iucv_message_send2way. + * IUCV_IPPRTY Specifies that you want to send priority messages. + * Used for iucv_path_accept, iucv_path_connect, + * iucv_message_reply, iucv_message_send, iucv_message_send2way. + * IUCV_IPSYNC Indicates a synchronous send request. + * Used for iucv_message_send, iucv_message_send2way. + * IUCV_IPANSLST Indicates that an address list is used for the reply data. + * Used for iucv_message_reply, iucv_message_send2way. + * IUCV_IPLOCAL Specifies that the communication partner has to be on the + * local system. If local is specified no target class can be + * specified. + * Used for iucv_path_connect. + * + * All flags are defined in the input field IPFLAGS1 of each function + * and can be found in CP Programming Services. + */ +#define IUCV_IPRMDATA 0x80 +#define IUCV_IPQUSCE 0x40 +#define IUCV_IPBUFLST 0x40 +#define IUCV_IPPRTY 0x20 +#define IUCV_IPANSLST 0x08 +#define IUCV_IPSYNC 0x04 +#define IUCV_IPLOCAL 0x01 + +/* + * iucv_array : Defines buffer array. + * Inside the array may be 31- bit addresses and 31-bit lengths. + * Use a pointer to an iucv_array as the buffer, reply or answer + * parameter on iucv_message_send, iucv_message_send2way, iucv_message_receive + * and iucv_message_reply if IUCV_IPBUFLST or IUCV_IPANSLST are used. + */ +struct iucv_array { + u32 address; + u32 length; +} __attribute__ ((aligned (8))); + +extern struct bus_type iucv_bus; +extern struct device *iucv_root; + +/* + * struct iucv_path + * pathid: 16 bit path identification + * msglim: 16 bit message limit + * flags: properties of the path: IPRMDATA, IPQUSCE, IPPRTY + * handler: address of iucv handler structure + * private: private information of the handler associated with the path + * list: list_head for the iucv_handler path list. + */ +struct iucv_path { + u16 pathid; + u16 msglim; + u8 flags; + void *private; + struct iucv_handler *handler; + struct list_head list; +}; + +/* + * struct iucv_message + * id: 32 bit message id + * audit: 32 bit error information of purged or replied messages + * class: 32 bit target class of a message (source class for replies) + * tag: 32 bit tag to be associated with the message + * length: 32 bit length of the message / reply + * reply_size: 32 bit maximum allowed length of the reply + * rmmsg: 8 byte inline message + * flags: message properties (IUCV_IPPRTY) + */ +struct iucv_message { + u32 id; + u32 audit; + u32 class; + u32 tag; + u32 length; + u32 reply_size; + u8 rmmsg[8]; + u8 flags; +}; + +/* + * struct iucv_handler + * + * A vector of functions that handle IUCV interrupts. Each functions gets + * a parameter area as defined by the CP Programming Services and private + * pointer that is provided by the user of the interface. + */ +struct iucv_handler { + /* + * The path_pending function is called after an iucv interrupt + * type 0x01 has been received. The base code allocates a path + * structure and "asks" the handler if this path belongs to the + * handler. To accept the path the path_pending function needs + * to call iucv_path_accept and return 0. If the callback returns + * a value != 0 the iucv base code will continue with the next + * handler. The order in which the path_pending functions are + * called is the order of the registration of the iucv handlers + * to the base code. + */ + int (*path_pending)(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); + /* + * The path_complete function is called after an iucv interrupt + * type 0x02 has been received for a path that has been established + * for this handler with iucv_path_connect and got accepted by the + * peer with iucv_path_accept. + */ + void (*path_complete)(struct iucv_path *, u8 ipuser[16]); + /* + * The path_severed function is called after an iucv interrupt + * type 0x03 has been received. The communication peer shutdown + * his end of the communication path. The path still exists and + * remaining messages can be received until a iucv_path_sever + * shuts down the other end of the path as well. + */ + void (*path_severed)(struct iucv_path *, u8 ipuser[16]); + /* + * The path_quiesced function is called after an icuv interrupt + * type 0x04 has been received. The communication peer has quiesced + * the path. Delivery of messages is stopped until iucv_path_resume + * has been called. + */ + void (*path_quiesced)(struct iucv_path *, u8 ipuser[16]); + /* + * The path_resumed function is called after an icuv interrupt + * type 0x05 has been received. The communication peer has resumed + * the path. + */ + void (*path_resumed)(struct iucv_path *, u8 ipuser[16]); + /* + * The message_pending function is called after an icuv interrupt + * type 0x06 or type 0x07 has been received. A new message is + * availabe and can be received with iucv_message_receive. + */ + void (*message_pending)(struct iucv_path *, struct iucv_message *); + /* + * The message_complete function is called after an icuv interrupt + * type 0x08 or type 0x09 has been received. A message send with + * iucv_message_send2way has been replied to. The reply can be + * received with iucv_message_receive. + */ + void (*message_complete)(struct iucv_path *, struct iucv_message *); + + struct list_head list; + struct list_head paths; +}; + +/** + * iucv_register: + * @handler: address of iucv handler structure + * @smp: != 0 indicates that the handler can deal with out of order messages + * + * Registers a driver with IUCV. + * + * Returns 0 on success, -ENOMEM if the memory allocation for the pathid + * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus. + */ +int iucv_register(struct iucv_handler *handler, int smp); + +/** + * iucv_unregister + * @handler: address of iucv handler structure + * @smp: != 0 indicates that the handler can deal with out of order messages + * + * Unregister driver from IUCV. + */ +void iucv_unregister(struct iucv_handler *handle, int smp); + +/** + * iucv_path_alloc + * @msglim: initial message limit + * @flags: initial flags + * @gfp: kmalloc allocation flag + * + * Allocate a new path structure for use with iucv_connect. + * + * Returns NULL if the memory allocation failed or a pointer to the + * path structure. + */ +static inline struct iucv_path *iucv_path_alloc(u16 msglim, u8 flags, gfp_t gfp) +{ + struct iucv_path *path; + + path = kzalloc(sizeof(struct iucv_path), gfp); + if (path) { + path->msglim = msglim; + path->flags = flags; + } + return path; +} + +/** + * iucv_path_free + * @path: address of iucv path structure + * + * Frees a path structure. + */ +static inline void iucv_path_free(struct iucv_path *path) +{ + kfree(path); +} + +/** + * iucv_path_accept + * @path: address of iucv path structure + * @handler: address of iucv handler structure + * @userdata: 16 bytes of data reflected to the communication partner + * @private: private data passed to interrupt handlers for this path + * + * This function is issued after the user received a connection pending + * external interrupt and now wishes to complete the IUCV communication path. + * + * Returns the result of the CP IUCV call. + */ +int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, + u8 userdata[16], void *private); + +/** + * iucv_path_connect + * @path: address of iucv path structure + * @handler: address of iucv handler structure + * @userid: 8-byte user identification + * @system: 8-byte target system identification + * @userdata: 16 bytes of data reflected to the communication partner + * @private: private data passed to interrupt handlers for this path + * + * This function establishes an IUCV path. Although the connect may complete + * successfully, you are not able to use the path until you receive an IUCV + * Connection Complete external interrupt. + * + * Returns the result of the CP IUCV call. + */ +int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, + u8 userid[8], u8 system[8], u8 userdata[16], + void *private); + +/** + * iucv_path_quiesce: + * @path: address of iucv path structure + * @userdata: 16 bytes of data reflected to the communication partner + * + * This function temporarily suspends incoming messages on an IUCV path. + * You can later reactivate the path by invoking the iucv_resume function. + * + * Returns the result from the CP IUCV call. + */ +int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]); + +/** + * iucv_path_resume: + * @path: address of iucv path structure + * @userdata: 16 bytes of data reflected to the communication partner + * + * This function resumes incoming messages on an IUCV path that has + * been stopped with iucv_path_quiesce. + * + * Returns the result from the CP IUCV call. + */ +int iucv_path_resume(struct iucv_path *path, u8 userdata[16]); + +/** + * iucv_path_sever + * @path: address of iucv path structure + * @userdata: 16 bytes of data reflected to the communication partner + * + * This function terminates an IUCV path. + * + * Returns the result from the CP IUCV call. + */ +int iucv_path_sever(struct iucv_path *path, u8 userdata[16]); + +/** + * iucv_message_purge + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * @srccls: source class of message + * + * Cancels a message you have sent. + * + * Returns the result from the CP IUCV call. + */ +int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, + u32 srccls); + +/** + * iucv_message_receive + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * @flags: flags that affect how the message is received (IUCV_IPBUFLST) + * @buffer: address of data buffer or address of struct iucv_array + * @size: length of data buffer + * @residual: + * + * This function receives messages that are being sent to you over + * established paths. This function will deal with RMDATA messages + * embedded in struct iucv_message as well. + * + * Locking: local_bh_enable/local_bh_disable + * + * Returns the result from the CP IUCV call. + */ +int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, + u8 flags, void *buffer, size_t size, size_t *residual); + +/** + * __iucv_message_receive + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * @flags: flags that affect how the message is received (IUCV_IPBUFLST) + * @buffer: address of data buffer or address of struct iucv_array + * @size: length of data buffer + * @residual: + * + * This function receives messages that are being sent to you over + * established paths. This function will deal with RMDATA messages + * embedded in struct iucv_message as well. + * + * Locking: no locking. + * + * Returns the result from the CP IUCV call. + */ +int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, + u8 flags, void *buffer, size_t size, + size_t *residual); + +/** + * iucv_message_reject + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * + * The reject function refuses a specified message. Between the time you + * are notified of a message and the time that you complete the message, + * the message may be rejected. + * + * Returns the result from the CP IUCV call. + */ +int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg); + +/** + * iucv_message_reply + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * @flags: how the reply is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) + * @reply: address of data buffer or address of struct iucv_array + * @size: length of reply data buffer + * + * This function responds to the two-way messages that you receive. You + * must identify completely the message to which you wish to reply. ie, + * pathid, msgid, and trgcls. Prmmsg signifies the data is moved into + * the parameter list. + * + * Returns the result from the CP IUCV call. + */ +int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, + u8 flags, void *reply, size_t size); + +/** + * iucv_message_send + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) + * @srccls: source class of message + * @buffer: address of data buffer or address of struct iucv_array + * @size: length of send buffer + * + * This function transmits data to another application. Data to be + * transmitted is in a buffer and this is a one-way message and the + * receiver will not reply to the message. + * + * Locking: local_bh_enable/local_bh_disable + * + * Returns the result from the CP IUCV call. + */ +int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, + u8 flags, u32 srccls, void *buffer, size_t size); + +/** + * __iucv_message_send + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) + * @srccls: source class of message + * @buffer: address of data buffer or address of struct iucv_array + * @size: length of send buffer + * + * This function transmits data to another application. Data to be + * transmitted is in a buffer and this is a one-way message and the + * receiver will not reply to the message. + * + * Locking: no locking. + * + * Returns the result from the CP IUCV call. + */ +int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, + u8 flags, u32 srccls, void *buffer, size_t size); + +/** + * iucv_message_send2way + * @path: address of iucv path structure + * @msg: address of iucv msg structure + * @flags: how the message is sent and the reply is received + * (IUCV_IPRMDATA, IUCV_IPBUFLST, IUCV_IPPRTY, IUCV_ANSLST) + * @srccls: source class of message + * @buffer: address of data buffer or address of struct iucv_array + * @size: length of send buffer + * @ansbuf: address of answer buffer or address of struct iucv_array + * @asize: size of reply buffer + * + * This function transmits data to another application. Data to be + * transmitted is in a buffer. The receiver of the send is expected to + * reply to the message and a buffer is provided into which IUCV moves + * the reply to this message. + * + * Returns the result from the CP IUCV call. + */ +int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, + u8 flags, u32 srccls, void *buffer, size_t size, + void *answer, size_t asize, size_t *residual); diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h new file mode 100644 index 00000000..3afdb21c --- /dev/null +++ b/include/net/iw_handler.h @@ -0,0 +1,587 @@ +/* + * This file define the new driver API for Wireless Extensions + * + * Version : 8 16.3.07 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 2001-2007 Jean Tourrilhes, All Rights Reserved. + */ + +#ifndef _IW_HANDLER_H +#define _IW_HANDLER_H + +/************************** DOCUMENTATION **************************/ +/* + * Initial driver API (1996 -> onward) : + * ----------------------------------- + * The initial API just sends the IOCTL request received from user space + * to the driver (via the driver ioctl handler). The driver has to + * handle all the rest... + * + * The initial API also defines a specific handler in struct net_device + * to handle wireless statistics. + * + * The initial APIs served us well and has proven a reasonably good design. + * However, there is a few shortcommings : + * o No events, everything is a request to the driver. + * o Large ioctl function in driver with gigantic switch statement + * (i.e. spaghetti code). + * o Driver has to mess up with copy_to/from_user, and in many cases + * does it unproperly. Common mistakes are : + * * buffer overflows (no checks or off by one checks) + * * call copy_to/from_user with irq disabled + * o The user space interface is tied to ioctl because of the use + * copy_to/from_user. + * + * New driver API (2002 -> onward) : + * ------------------------------- + * The new driver API is just a bunch of standard functions (handlers), + * each handling a specific Wireless Extension. The driver just export + * the list of handler it supports, and those will be called apropriately. + * + * I tried to keep the main advantage of the previous API (simplicity, + * efficiency and light weight), and also I provide a good dose of backward + * compatibility (most structures are the same, driver can use both API + * simultaneously, ...). + * Hopefully, I've also addressed the shortcomming of the initial API. + * + * The advantage of the new API are : + * o Handling of Extensions in driver broken in small contained functions + * o Tighter checks of ioctl before calling the driver + * o Flexible commit strategy (at least, the start of it) + * o Backward compatibility (can be mixed with old API) + * o Driver doesn't have to worry about memory and user-space issues + * The last point is important for the following reasons : + * o You are now able to call the new driver API from any API you + * want (including from within other parts of the kernel). + * o Common mistakes are avoided (buffer overflow, user space copy + * with irq disabled and so on). + * + * The Drawback of the new API are : + * o bloat (especially kernel) + * o need to migrate existing drivers to new API + * My initial testing shows that the new API adds around 3kB to the kernel + * and save between 0 and 5kB from a typical driver. + * Also, as all structures and data types are unchanged, the migration is + * quite straightforward (but tedious). + * + * --- + * + * The new driver API is defined below in this file. User space should + * not be aware of what's happening down there... + * + * A new kernel wrapper is in charge of validating the IOCTLs and calling + * the appropriate driver handler. This is implemented in : + * # net/core/wireless.c + * + * The driver export the list of handlers in : + * # include/linux/netdevice.h (one place) + * + * The new driver API is available for WIRELESS_EXT >= 13. + * Good luck with migration to the new API ;-) + */ + +/* ---------------------- THE IMPLEMENTATION ---------------------- */ +/* + * Some of the choice I've made are pretty controversials. Defining an + * API is very much weighting compromises. This goes into some of the + * details and the thinking behind the implementation. + * + * Implementation goals : + * -------------------- + * The implementation goals were as follow : + * o Obvious : you should not need a PhD to understand what's happening, + * the benefit is easier maintainance. + * o Flexible : it should accommodate a wide variety of driver + * implementations and be as flexible as the old API. + * o Lean : it should be efficient memory wise to minimise the impact + * on kernel footprint. + * o Transparent to user space : the large number of user space + * applications that use Wireless Extensions should not need + * any modifications. + * + * Array of functions versus Struct of functions + * --------------------------------------------- + * 1) Having an array of functions allow the kernel code to access the + * handler in a single lookup, which is much more efficient (think hash + * table here). + * 2) The only drawback is that driver writer may put their handler in + * the wrong slot. This is trivial to test (I set the frequency, the + * bitrate changes). Once the handler is in the proper slot, it will be + * there forever, because the array is only extended at the end. + * 3) Backward/forward compatibility : adding new handler just require + * extending the array, so you can put newer driver in older kernel + * without having to patch the kernel code (and vice versa). + * + * All handler are of the same generic type + * ---------------------------------------- + * That's a feature !!! + * 1) Having a generic handler allow to have generic code, which is more + * efficient. If each of the handler was individually typed I would need + * to add a big switch in the kernel (== more bloat). This solution is + * more scalable, adding new Wireless Extensions doesn't add new code. + * 2) You can use the same handler in different slots of the array. For + * hardware, it may be more efficient or logical to handle multiple + * Wireless Extensions with a single function, and the API allow you to + * do that. (An example would be a single record on the card to control + * both bitrate and frequency, the handler would read the old record, + * modify it according to info->cmd and rewrite it). + * + * Functions prototype uses union iwreq_data + * ----------------------------------------- + * Some would have prefered functions defined this way : + * static int mydriver_ioctl_setrate(struct net_device *dev, + * long rate, int auto) + * 1) The kernel code doesn't "validate" the content of iwreq_data, and + * can't do it (different hardware may have different notion of what a + * valid frequency is), so we don't pretend that we do it. + * 2) The above form is not extendable. If I want to add a flag (for + * example to distinguish setting max rate and basic rate), I would + * break the prototype. Using iwreq_data is more flexible. + * 3) Also, the above form is not generic (see above). + * 4) I don't expect driver developper using the wrong field of the + * union (Doh !), so static typechecking doesn't add much value. + * 5) Lastly, you can skip the union by doing : + * static int mydriver_ioctl_setrate(struct net_device *dev, + * struct iw_request_info *info, + * struct iw_param *rrq, + * char *extra) + * And then adding the handler in the array like this : + * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE + * + * Using functions and not a registry + * ---------------------------------- + * Another implementation option would have been for every instance to + * define a registry (a struct containing all the Wireless Extensions) + * and only have a function to commit the registry to the hardware. + * 1) This approach can be emulated by the current code, but not + * vice versa. + * 2) Some drivers don't keep any configuration in the driver, for them + * adding such a registry would be a significant bloat. + * 3) The code to translate from Wireless Extension to native format is + * needed anyway, so it would not reduce significantely the amount of code. + * 4) The current approach only selectively translate Wireless Extensions + * to native format and only selectively set, whereas the registry approach + * would require to translate all WE and set all parameters for any single + * change. + * 5) For many Wireless Extensions, the GET operation return the current + * dynamic value, not the value that was set. + * + * This header is <net/iw_handler.h> + * --------------------------------- + * 1) This header is kernel space only and should not be exported to + * user space. Headers in "include/linux/" are exported, headers in + * "include/net/" are not. + * + * Mixed 32/64 bit issues + * ---------------------- + * The Wireless Extensions are designed to be 64 bit clean, by using only + * datatypes with explicit storage size. + * There are some issues related to kernel and user space using different + * memory model, and in particular 64bit kernel with 32bit user space. + * The problem is related to struct iw_point, that contains a pointer + * that *may* need to be translated. + * This is quite messy. The new API doesn't solve this problem (it can't), + * but is a step in the right direction : + * 1) Meta data about each ioctl is easily available, so we know what type + * of translation is needed. + * 2) The move of data between kernel and user space is only done in a single + * place in the kernel, so adding specific hooks in there is possible. + * 3) In the long term, it allows to move away from using ioctl as the + * user space API. + * + * So many comments and so few code + * -------------------------------- + * That's a feature. Comments won't bloat the resulting kernel binary. + */ + +/***************************** INCLUDES *****************************/ + +#include <linux/wireless.h> /* IOCTL user space API */ +#include <linux/if_ether.h> + +/***************************** VERSION *****************************/ +/* + * This constant is used to know which version of the driver API is + * available. Hopefully, this will be pretty stable and no changes + * will be needed... + * I just plan to increment with each new version. + */ +#define IW_HANDLER_VERSION 8 + +/* + * Changes : + * + * V2 to V3 + * -------- + * - Move event definition in <linux/wireless.h> + * - Add Wireless Event support : + * o wireless_send_event() prototype + * o iwe_stream_add_event/point() inline functions + * V3 to V4 + * -------- + * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + * + * V4 to V5 + * -------- + * - Add new spy support : struct iw_spy_data & prototypes + * + * V5 to V6 + * -------- + * - Change the way we get to spy_data method for added safety + * - Remove spy #ifdef, they are always on -> cleaner code + * - Add IW_DESCR_FLAG_NOMAX flag for very large requests + * - Start migrating get_wireless_stats to struct iw_handler_def + * + * V6 to V7 + * -------- + * - Add struct ieee80211_device pointer in struct iw_public_data + * - Remove (struct iw_point *)->pointer from events and streams + * - Remove spy_offset from struct iw_handler_def + * - Add "check" version of event macros for ieee802.11 stack + * + * V7 to V8 + * ---------- + * - Prevent leaking of kernel space in stream on 64 bits. + */ + +/**************************** CONSTANTS ****************************/ + +/* Enhanced spy support available */ +#define IW_WIRELESS_SPY +#define IW_WIRELESS_THRSPY + +/* Special error message for the driver to indicate that we + * should do a commit after return from the iw_handler */ +#define EIWCOMMIT EINPROGRESS + +/* Flags available in struct iw_request_info */ +#define IW_REQUEST_FLAG_COMPAT 0x0001 /* Compat ioctl call */ + +/* Type of headers we know about (basically union iwreq_data) */ +#define IW_HEADER_TYPE_NULL 0 /* Not available */ +#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ +#define IW_HEADER_TYPE_UINT 4 /* __u32 */ +#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ +#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ +#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ +#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ +#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ + +/* Handling flags */ +/* Most are not implemented. I just use them as a reminder of some + * cool features we might need one day ;-) */ +#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */ +/* Wrapper level flags */ +#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ +#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ +#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ + /* SET : Omit payload from generated iwevent */ +#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */ +/* Driver level flags */ +#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ + +/****************************** TYPES ******************************/ + +/* ----------------------- WIRELESS HANDLER ----------------------- */ +/* + * A wireless handler is just a standard function, that looks like the + * ioctl handler. + * We also define there how a handler list look like... As the Wireless + * Extension space is quite dense, we use a simple array, which is faster + * (that's the perfect hash table ;-). + */ + +/* + * Meta data about the request passed to the iw_handler. + * Most handlers can safely ignore what's in there. + * The 'cmd' field might come handy if you want to use the same handler + * for multiple command... + * This struct is also my long term insurance. I can add new fields here + * without breaking the prototype of iw_handler... + */ +struct iw_request_info { + __u16 cmd; /* Wireless Extension command */ + __u16 flags; /* More to come ;-) */ +}; + +struct net_device; + +/* + * This is how a function handling a Wireless Extension should look + * like (both get and set, standard and private). + */ +typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +/* + * This define all the handler that the driver export. + * As you need only one per driver type, please use a static const + * shared by all driver instances... Same for the members... + * This will be linked from net_device in <linux/netdevice.h> + */ +struct iw_handler_def { + + /* Array of handlers for standard ioctls + * We will call dev->wireless_handlers->standard[ioctl - SIOCIWFIRST] + */ + const iw_handler * standard; + /* Number of handlers defined (more precisely, index of the + * last defined handler + 1) */ + __u16 num_standard; + +#ifdef CONFIG_WEXT_PRIV + __u16 num_private; + /* Number of private arg description */ + __u16 num_private_args; + /* Array of handlers for private ioctls + * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] + */ + const iw_handler * private; + + /* Arguments of private handler. This one is just a list, so you + * can put it in any order you want and should not leave holes... + * We will automatically export that to user space... */ + const struct iw_priv_args * private_args; +#endif + + /* New location of get_wireless_stats, to de-bloat struct net_device. + * The old pointer in struct net_device will be gradually phased + * out, and drivers are encouraged to use this one... */ + struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); +}; + +/* ---------------------- IOCTL DESCRIPTION ---------------------- */ +/* + * One of the main goal of the new interface is to deal entirely with + * user space/kernel space memory move. + * For that, we need to know : + * o if iwreq is a pointer or contain the full data + * o what is the size of the data to copy + * + * For private IOCTLs, we use the same rules as used by iwpriv and + * defined in struct iw_priv_args. + * + * For standard IOCTLs, things are quite different and we need to + * use the stuctures below. Actually, this struct is also more + * efficient, but that's another story... + */ + +/* + * Describe how a standard IOCTL looks like. + */ +struct iw_ioctl_description { + __u8 header_type; /* NULL, iw_point or other */ + __u8 token_type; /* Future */ + __u16 token_size; /* Granularity of payload */ + __u16 min_tokens; /* Min acceptable token number */ + __u16 max_tokens; /* Max acceptable token number */ + __u32 flags; /* Special handling of the request */ +}; + +/* Need to think of short header translation table. Later. */ + +/* --------------------- ENHANCED SPY SUPPORT --------------------- */ +/* + * In the old days, the driver was handling spy support all by itself. + * Now, the driver can delegate this task to Wireless Extensions. + * It needs to include this struct in its private part and use the + * standard spy iw_handler. + */ + +/* + * Instance specific spy data, i.e. addresses spied and quality for them. + */ +struct iw_spy_data { + /* --- Standard spy support --- */ + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; + /* --- Enhanced spy support (event) */ + struct iw_quality spy_thr_low; /* Low threshold */ + struct iw_quality spy_thr_high; /* High threshold */ + u_char spy_thr_under[IW_MAX_SPY]; +}; + +/* --------------------- DEVICE WIRELESS DATA --------------------- */ +/* + * This is all the wireless data specific to a device instance that + * is managed by the core of Wireless Extensions or the 802.11 layer. + * We only keep pointer to those structures, so that a driver is free + * to share them between instances. + * This structure should be initialised before registering the device. + * Access to this data follow the same rules as any other struct net_device + * data (i.e. valid as long as struct net_device exist, same locking rules). + */ +/* Forward declaration */ +struct libipw_device; +/* The struct */ +struct iw_public_data { + /* Driver enhanced spy support */ + struct iw_spy_data * spy_data; + /* Legacy structure managed by the ipw2x00-specific IEEE 802.11 layer */ + struct libipw_device * libipw; +}; + +/**************************** PROTOTYPES ****************************/ +/* + * Functions part of the Wireless Extensions (defined in net/core/wireless.c). + * Those may be called only within the kernel. + */ + +/* First : function strictly used inside the kernel */ + +/* Handle /proc/net/wireless, called in net/code/dev.c */ +extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, + int length); + +/* Second : functions that may be called by driver modules */ + +/* Send a single event to user space */ +extern void wireless_send_event(struct net_device * dev, + unsigned int cmd, + union iwreq_data * wrqu, + const char * extra); + +/* We may need a function to send a stream of events to user space. + * More on that later... */ + +/* Standard handler for SIOCSIWSPY */ +extern int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCGIWSPY */ +extern int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCSIWTHRSPY */ +extern int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCGIWTHRSPY */ +extern int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra); +/* Driver call to update spy records */ +extern void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats); + +/************************* INLINE FUNTIONS *************************/ +/* + * Function that are so simple that it's more efficient inlining them + */ + +static inline int iwe_stream_lcp_len(struct iw_request_info *info) +{ +#ifdef CONFIG_COMPAT + if (info->flags & IW_REQUEST_FLAG_COMPAT) + return IW_EV_COMPAT_LCP_LEN; +#endif + return IW_EV_LCP_LEN; +} + +static inline int iwe_stream_point_len(struct iw_request_info *info) +{ +#ifdef CONFIG_COMPAT + if (info->flags & IW_REQUEST_FLAG_COMPAT) + return IW_EV_COMPAT_POINT_LEN; +#endif + return IW_EV_POINT_LEN; +} + +static inline int iwe_stream_event_len_adjust(struct iw_request_info *info, + int event_len) +{ +#ifdef CONFIG_COMPAT + if (info->flags & IW_REQUEST_FLAG_COMPAT) { + event_len -= IW_EV_LCP_LEN; + event_len += IW_EV_COMPAT_LCP_LEN; + } +#endif + + return event_len; +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper to add an Wireless Event to a stream of events. + */ +static inline char * +iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends, + struct iw_event *iwe, int event_len) +{ + int lcp_len = iwe_stream_lcp_len(info); + + event_len = iwe_stream_event_len_adjust(info, event_len); + + /* Check if it's possible */ + if(likely((stream + event_len) < ends)) { + iwe->len = event_len; + /* Beware of alignement issues on 64 bits */ + memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); + memcpy(stream + lcp_len, &iwe->u, + event_len - lcp_len); + stream += event_len; + } + return stream; +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper to add an short Wireless Event containing a pointer to a + * stream of events. + */ +static inline char * +iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends, + struct iw_event *iwe, char *extra) +{ + int event_len = iwe_stream_point_len(info) + iwe->u.data.length; + int point_len = iwe_stream_point_len(info); + int lcp_len = iwe_stream_lcp_len(info); + + /* Check if it's possible */ + if(likely((stream + event_len) < ends)) { + iwe->len = event_len; + memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); + memcpy(stream + lcp_len, + ((char *) &iwe->u) + IW_EV_POINT_OFF, + IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); + memcpy(stream + point_len, extra, iwe->u.data.length); + stream += event_len; + } + return stream; +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper to add a value to a Wireless Event in a stream of events. + * Be careful, this one is tricky to use properly : + * At the first run, you need to have (value = event + IW_EV_LCP_LEN). + */ +static inline char * +iwe_stream_add_value(struct iw_request_info *info, char *event, char *value, + char *ends, struct iw_event *iwe, int event_len) +{ + int lcp_len = iwe_stream_lcp_len(info); + + /* Don't duplicate LCP */ + event_len -= IW_EV_LCP_LEN; + + /* Check if it's possible */ + if(likely((value + event_len) < ends)) { + /* Add new value */ + memcpy(value, &iwe->u, event_len); + value += event_len; + /* Patch LCP */ + iwe->len = value - event; + memcpy(event, (char *) iwe, lcp_len); + } + return value; +} + +#endif /* _IW_HANDLER_H */ diff --git a/include/net/lapb.h b/include/net/lapb.h new file mode 100644 index 00000000..96cb5dda --- /dev/null +++ b/include/net/lapb.h @@ -0,0 +1,152 @@ +#ifndef _LAPB_H +#define _LAPB_H +#include <linux/lapb.h> + +#define LAPB_HEADER_LEN 20 /* LAPB over Ethernet + a bit more */ + +#define LAPB_ACK_PENDING_CONDITION 0x01 +#define LAPB_REJECT_CONDITION 0x02 +#define LAPB_PEER_RX_BUSY_CONDITION 0x04 + +/* Control field templates */ +#define LAPB_I 0x00 /* Information frames */ +#define LAPB_S 0x01 /* Supervisory frames */ +#define LAPB_U 0x03 /* Unnumbered frames */ + +#define LAPB_RR 0x01 /* Receiver ready */ +#define LAPB_RNR 0x05 /* Receiver not ready */ +#define LAPB_REJ 0x09 /* Reject */ + +#define LAPB_SABM 0x2F /* Set Asynchronous Balanced Mode */ +#define LAPB_SABME 0x6F /* Set Asynchronous Balanced Mode Extended */ +#define LAPB_DISC 0x43 /* Disconnect */ +#define LAPB_DM 0x0F /* Disconnected mode */ +#define LAPB_UA 0x63 /* Unnumbered acknowledge */ +#define LAPB_FRMR 0x87 /* Frame reject */ + +#define LAPB_ILLEGAL 0x100 /* Impossible to be a real frame type */ + +#define LAPB_SPF 0x10 /* Poll/final bit for standard LAPB */ +#define LAPB_EPF 0x01 /* Poll/final bit for extended LAPB */ + +#define LAPB_FRMR_W 0x01 /* Control field invalid */ +#define LAPB_FRMR_X 0x02 /* I field invalid */ +#define LAPB_FRMR_Y 0x04 /* I field too long */ +#define LAPB_FRMR_Z 0x08 /* Invalid N(R) */ + +#define LAPB_POLLOFF 0 +#define LAPB_POLLON 1 + +/* LAPB C-bit */ +#define LAPB_COMMAND 1 +#define LAPB_RESPONSE 2 + +#define LAPB_ADDR_A 0x03 +#define LAPB_ADDR_B 0x01 +#define LAPB_ADDR_C 0x0F +#define LAPB_ADDR_D 0x07 + +/* Define Link State constants. */ +enum { + LAPB_STATE_0, /* Disconnected State */ + LAPB_STATE_1, /* Awaiting Connection State */ + LAPB_STATE_2, /* Awaiting Disconnection State */ + LAPB_STATE_3, /* Data Transfer State */ + LAPB_STATE_4 /* Frame Reject State */ +}; + +#define LAPB_DEFAULT_MODE (LAPB_STANDARD | LAPB_SLP | LAPB_DTE) +#define LAPB_DEFAULT_WINDOW 7 /* Window=7 */ +#define LAPB_DEFAULT_T1 (5 * HZ) /* T1=5s */ +#define LAPB_DEFAULT_T2 (1 * HZ) /* T2=1s */ +#define LAPB_DEFAULT_N2 20 /* N2=20 */ + +#define LAPB_SMODULUS 8 +#define LAPB_EMODULUS 128 + +/* + * Information about the current frame. + */ +struct lapb_frame { + unsigned short type; /* Parsed type */ + unsigned short nr, ns; /* N(R), N(S) */ + unsigned char cr; /* Command/Response */ + unsigned char pf; /* Poll/Final */ + unsigned char control[2]; /* Original control data*/ +}; + +/* + * The per LAPB connection control structure. + */ +struct lapb_cb { + struct list_head node; + struct net_device *dev; + + /* Link status fields */ + unsigned int mode; + unsigned char state; + unsigned short vs, vr, va; + unsigned char condition; + unsigned short n2, n2count; + unsigned short t1, t2; + struct timer_list t1timer, t2timer; + + /* Internal control information */ + struct sk_buff_head write_queue; + struct sk_buff_head ack_queue; + unsigned char window; + struct lapb_register_struct callbacks; + + /* FRMR control information */ + struct lapb_frame frmr_data; + unsigned char frmr_type; + + atomic_t refcnt; +}; + +/* lapb_iface.c */ +extern void lapb_connect_confirmation(struct lapb_cb *lapb, int); +extern void lapb_connect_indication(struct lapb_cb *lapb, int); +extern void lapb_disconnect_confirmation(struct lapb_cb *lapb, int); +extern void lapb_disconnect_indication(struct lapb_cb *lapb, int); +extern int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *); +extern int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *); + +/* lapb_in.c */ +extern void lapb_data_input(struct lapb_cb *lapb, struct sk_buff *); + +/* lapb_out.c */ +extern void lapb_kick(struct lapb_cb *lapb); +extern void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *, int); +extern void lapb_establish_data_link(struct lapb_cb *lapb); +extern void lapb_enquiry_response(struct lapb_cb *lapb); +extern void lapb_timeout_response(struct lapb_cb *lapb); +extern void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short); +extern void lapb_check_need_response(struct lapb_cb *lapb, int, int); + +/* lapb_subr.c */ +extern void lapb_clear_queues(struct lapb_cb *lapb); +extern void lapb_frames_acked(struct lapb_cb *lapb, unsigned short); +extern void lapb_requeue_frames(struct lapb_cb *lapb); +extern int lapb_validate_nr(struct lapb_cb *lapb, unsigned short); +extern int lapb_decode(struct lapb_cb *lapb, struct sk_buff *, struct lapb_frame *); +extern void lapb_send_control(struct lapb_cb *lapb, int, int, int); +extern void lapb_transmit_frmr(struct lapb_cb *lapb); + +/* lapb_timer.c */ +extern void lapb_start_t1timer(struct lapb_cb *lapb); +extern void lapb_start_t2timer(struct lapb_cb *lapb); +extern void lapb_stop_t1timer(struct lapb_cb *lapb); +extern void lapb_stop_t2timer(struct lapb_cb *lapb); +extern int lapb_t1timer_running(struct lapb_cb *lapb); + +/* + * Debug levels. + * 0 = Off + * 1 = State Changes + * 2 = Packets I/O and State Changes + * 3 = Hex dumps, Packets I/O and State Changes. + */ +#define LAPB_DEBUG 0 + +#endif diff --git a/include/net/lib80211.h b/include/net/lib80211.h new file mode 100644 index 00000000..848cce1b --- /dev/null +++ b/include/net/lib80211.h @@ -0,0 +1,126 @@ +/* + * lib80211.h -- common bits for IEEE802.11 wireless drivers + * + * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com> + * + * Some bits copied from old ieee80211 component, w/ original copyright + * notices below: + * + * Original code based on Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * <j@w1.fi> + * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * <jketreno@linux.intel.com> + * + * Copyright (c) 2004, Intel Corporation + * + */ + +#ifndef LIB80211_H +#define LIB80211_H + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/module.h> +#include <asm/atomic.h> +#include <linux/if.h> +#include <linux/skbuff.h> +#include <linux/ieee80211.h> +#include <linux/timer.h> +/* print_ssid() is intended to be used in debug (and possibly error) + * messages. It should never be used for passing ssid to user space. */ +const char *print_ssid(char *buf, const char *ssid, u8 ssid_len); +#define DECLARE_SSID_BUF(var) char var[IEEE80211_MAX_SSID_LEN * 4 + 1] __maybe_unused + +#define NUM_WEP_KEYS 4 + +enum { + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0), +}; + +struct lib80211_crypto_ops { + const char *name; + struct list_head list; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void *(*init) (int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit) (void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key) (void *key, int len, u8 * seq, void *priv); + int (*get_key) (void *key, int len, u8 * seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + char *(*print_stats) (char *p, void *priv); + + /* Crypto specific flag get/set for configuration settings */ + unsigned long (*get_flags) (void *priv); + unsigned long (*set_flags) (unsigned long flags, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_mpdu_prefix_len, extra_mpdu_postfix_len; + int extra_msdu_prefix_len, extra_msdu_postfix_len; + + struct module *owner; +}; + +struct lib80211_crypt_data { + struct list_head list; /* delayed deletion list */ + struct lib80211_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +struct lib80211_crypt_info { + char *name; + /* Most clients will already have a lock, + so just point to that. */ + spinlock_t *lock; + + struct lib80211_crypt_data *crypt[NUM_WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct list_head crypt_deinit_list; + struct timer_list crypt_deinit_timer; + int crypt_quiesced; +}; + +int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name, + spinlock_t *lock); +void lib80211_crypt_info_free(struct lib80211_crypt_info *info); +int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops); +int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops); +struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name); +void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *, int); +void lib80211_crypt_deinit_handler(unsigned long); +void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt); +void lib80211_crypt_quiescing(struct lib80211_crypt_info *info); + +#endif /* LIB80211_H */ diff --git a/include/net/llc.h b/include/net/llc.h new file mode 100644 index 00000000..5503b74a --- /dev/null +++ b/include/net/llc.h @@ -0,0 +1,159 @@ +#ifndef LLC_H +#define LLC_H +/* + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/rculist_nulls.h> +#include <linux/hash.h> +#include <linux/jhash.h> + +#include <asm/atomic.h> + +struct net_device; +struct packet_type; +struct sk_buff; + +struct llc_addr { + unsigned char lsap; + unsigned char mac[IFHWADDRLEN]; +}; + +#define LLC_SAP_STATE_INACTIVE 1 +#define LLC_SAP_STATE_ACTIVE 2 + +#define LLC_SK_DEV_HASH_BITS 6 +#define LLC_SK_DEV_HASH_ENTRIES (1<<LLC_SK_DEV_HASH_BITS) + +#define LLC_SK_LADDR_HASH_BITS 6 +#define LLC_SK_LADDR_HASH_ENTRIES (1<<LLC_SK_LADDR_HASH_BITS) + +/** + * struct llc_sap - Defines the SAP component + * + * @station - station this sap belongs to + * @state - sap state + * @p_bit - only lowest-order bit used + * @f_bit - only lowest-order bit used + * @laddr - SAP value in this 'lsap' + * @node - entry in station sap_list + * @sk_list - LLC sockets this one manages + */ +struct llc_sap { + unsigned char state; + unsigned char p_bit; + unsigned char f_bit; + atomic_t refcnt; + int (*rcv_func)(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt, + struct net_device *orig_dev); + struct llc_addr laddr; + struct list_head node; + spinlock_t sk_lock; + int sk_count; + struct hlist_nulls_head sk_laddr_hash[LLC_SK_LADDR_HASH_ENTRIES]; + struct hlist_head sk_dev_hash[LLC_SK_DEV_HASH_ENTRIES]; +}; + +static inline +struct hlist_head *llc_sk_dev_hash(struct llc_sap *sap, int ifindex) +{ + return &sap->sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES]; +} + +static inline +u32 llc_sk_laddr_hashfn(struct llc_sap *sap, const struct llc_addr *laddr) +{ + return hash_32(jhash(laddr->mac, sizeof(laddr->mac), 0), + LLC_SK_LADDR_HASH_BITS); +} + +static inline +struct hlist_nulls_head *llc_sk_laddr_hash(struct llc_sap *sap, + const struct llc_addr *laddr) +{ + return &sap->sk_laddr_hash[llc_sk_laddr_hashfn(sap, laddr)]; +} + +#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ +#define LLC_DEST_SAP 1 /* Type 1 goes here */ +#define LLC_DEST_CONN 2 /* Type 2 goes here */ + +extern struct list_head llc_sap_list; +extern spinlock_t llc_sap_list_lock; + +extern int llc_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev); + +extern int llc_mac_hdr_init(struct sk_buff *skb, + const unsigned char *sa, const unsigned char *da); + +extern void llc_add_pack(int type, void (*handler)(struct llc_sap *sap, + struct sk_buff *skb)); +extern void llc_remove_pack(int type); + +extern void llc_set_station_handler(void (*handler)(struct sk_buff *skb)); + +extern struct llc_sap *llc_sap_open(unsigned char lsap, + int (*rcv)(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt, + struct net_device *orig_dev)); +static inline void llc_sap_hold(struct llc_sap *sap) +{ + atomic_inc(&sap->refcnt); +} + +extern void llc_sap_close(struct llc_sap *sap); + +static inline void llc_sap_put(struct llc_sap *sap) +{ + if (atomic_dec_and_test(&sap->refcnt)) + llc_sap_close(sap); +} + +extern struct llc_sap *llc_sap_find(unsigned char sap_value); + +extern int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb, + unsigned char *dmac, unsigned char dsap); + +extern void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb); +extern void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb); + +extern int llc_station_init(void); +extern void llc_station_exit(void); + +#ifdef CONFIG_PROC_FS +extern int llc_proc_init(void); +extern void llc_proc_exit(void); +#else +#define llc_proc_init() (0) +#define llc_proc_exit() do { } while(0) +#endif /* CONFIG_PROC_FS */ +#ifdef CONFIG_SYSCTL +extern int llc_sysctl_init(void); +extern void llc_sysctl_exit(void); + +extern int sysctl_llc2_ack_timeout; +extern int sysctl_llc2_busy_timeout; +extern int sysctl_llc2_p_timeout; +extern int sysctl_llc2_rej_timeout; +extern int sysctl_llc_station_ack_timeout; +#else +#define llc_sysctl_init() (0) +#define llc_sysctl_exit() do { } while(0) +#endif /* CONFIG_SYSCTL */ +#endif /* LLC_H */ diff --git a/include/net/llc_c_ac.h b/include/net/llc_c_ac.h new file mode 100644 index 00000000..df83f69d --- /dev/null +++ b/include/net/llc_c_ac.h @@ -0,0 +1,202 @@ +#ifndef LLC_C_AC_H +#define LLC_C_AC_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Connection component state transition actions */ +/* + * Connection state transition actions + * (Fb = F bit; Pb = P bit; Xb = X bit) + */ +#define LLC_CONN_AC_CLR_REMOTE_BUSY 1 +#define LLC_CONN_AC_CONN_IND 2 +#define LLC_CONN_AC_CONN_CONFIRM 3 +#define LLC_CONN_AC_DATA_IND 4 +#define LLC_CONN_AC_DISC_IND 5 +#define LLC_CONN_AC_RESET_IND 6 +#define LLC_CONN_AC_RESET_CONFIRM 7 +#define LLC_CONN_AC_REPORT_STATUS 8 +#define LLC_CONN_AC_CLR_REMOTE_BUSY_IF_Fb_EQ_1 9 +#define LLC_CONN_AC_STOP_REJ_TMR_IF_DATA_FLAG_EQ_2 10 +#define LLC_CONN_AC_SEND_DISC_CMD_Pb_SET_X 11 +#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_Pb 12 +#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_1 13 +#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_F_FLAG 14 +#define LLC_CONN_AC_SEND_FRMR_RSP_Fb_SET_X 15 +#define LLC_CONN_AC_RESEND_FRMR_RSP_Fb_SET_0 16 +#define LLC_CONN_AC_RESEND_FRMR_RSP_Fb_SET_Pb 17 +#define LLC_CONN_AC_SEND_I_CMD_Pb_SET_1 18 +#define LLC_CONN_AC_RESEND_I_CMD_Pb_SET_1 19 +#define LLC_CONN_AC_RESEND_I_CMD_Pb_SET_1_OR_SEND_RR 20 +#define LLC_CONN_AC_SEND_I_XXX_Xb_SET_0 21 +#define LLC_CONN_AC_RESEND_I_XXX_Xb_SET_0 22 +#define LLC_CONN_AC_RESEND_I_XXX_Xb_SET_0_OR_SEND_RR 23 +#define LLC_CONN_AC_RESEND_I_RSP_Fb_SET_1 24 +#define LLC_CONN_AC_SEND_REJ_CMD_Pb_SET_1 25 +#define LLC_CONN_AC_SEND_REJ_RSP_Fb_SET_1 26 +#define LLC_CONN_AC_SEND_REJ_XXX_Xb_SET_0 27 +#define LLC_CONN_AC_SEND_RNR_CMD_Pb_SET_1 28 +#define LLC_CONN_AC_SEND_RNR_RSP_Fb_SET_1 29 +#define LLC_CONN_AC_SEND_RNR_XXX_Xb_SET_0 30 +#define LLC_CONN_AC_SET_REMOTE_BUSY 31 +#define LLC_CONN_AC_OPTIONAL_SEND_RNR_XXX_Xb_SET_0 32 +#define LLC_CONN_AC_SEND_RR_CMD_Pb_SET_1 33 +#define LLC_CONN_AC_SEND_ACK_CMD_Pb_SET_1 34 +#define LLC_CONN_AC_SEND_RR_RSP_Fb_SET_1 35 +#define LLC_CONN_AC_SEND_ACK_RSP_Fb_SET_1 36 +#define LLC_CONN_AC_SEND_RR_XXX_Xb_SET_0 37 +#define LLC_CONN_AC_SEND_ACK_XXX_Xb_SET_0 38 +#define LLC_CONN_AC_SEND_SABME_CMD_Pb_SET_X 39 +#define LLC_CONN_AC_SEND_UA_RSP_Fb_SET_Pb 40 +#define LLC_CONN_AC_SEND_UA_RSP_Fb_SET_F_FLAG 41 +#define LLC_CONN_AC_S_FLAG_SET_0 42 +#define LLC_CONN_AC_S_FLAG_SET_1 43 +#define LLC_CONN_AC_START_P_TMR 44 +#define LLC_CONN_AC_START_ACK_TMR 45 +#define LLC_CONN_AC_START_REJ_TMR 46 +#define LLC_CONN_AC_START_ACK_TMR_IF_NOT_RUNNING 47 +#define LLC_CONN_AC_STOP_ACK_TMR 48 +#define LLC_CONN_AC_STOP_P_TMR 49 +#define LLC_CONN_AC_STOP_REJ_TMR 50 +#define LLC_CONN_AC_STOP_ALL_TMRS 51 +#define LLC_CONN_AC_STOP_OTHER_TMRS 52 +#define LLC_CONN_AC_UPDATE_Nr_RECEIVED 53 +#define LLC_CONN_AC_UPDATE_P_FLAG 54 +#define LLC_CONN_AC_DATA_FLAG_SET_2 55 +#define LLC_CONN_AC_DATA_FLAG_SET_0 56 +#define LLC_CONN_AC_DATA_FLAG_SET_1 57 +#define LLC_CONN_AC_DATA_FLAG_SET_1_IF_DATA_FLAG_EQ_0 58 +#define LLC_CONN_AC_P_FLAG_SET_0 59 +#define LLC_CONN_AC_P_FLAG_SET_P 60 +#define LLC_CONN_AC_REMOTE_BUSY_SET_0 61 +#define LLC_CONN_AC_RETRY_CNT_SET_0 62 +#define LLC_CONN_AC_RETRY_CNT_INC_BY_1 63 +#define LLC_CONN_AC_Vr_SET_0 64 +#define LLC_CONN_AC_Vr_INC_BY_1 65 +#define LLC_CONN_AC_Vs_SET_0 66 +#define LLC_CONN_AC_Vs_SET_Nr 67 +#define LLC_CONN_AC_F_FLAG_SET_P 68 +#define LLC_CONN_AC_STOP_SENDACK_TMR 70 +#define LLC_CONN_AC_START_SENDACK_TMR_IF_NOT_RUNNING 71 + +typedef int (*llc_conn_action_t)(struct sock *sk, struct sk_buff *skb); + +extern int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ac_conn_confirm(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_data_ind(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_disc_ind(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_rst_ind(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_rst_confirm(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_disc_cmd_p_set_x(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_dm_rsp_f_set_p(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_dm_rsp_f_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_i_cmd_p_set_1(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_send_i_xxx_x_set_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_resend_i_xxx_x_set_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_resend_i_rsp_f_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rej_cmd_p_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rej_rsp_f_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rej_xxx_x_set_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_set_remote_busy(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rr_cmd_p_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rr_rsp_f_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_ack_rsp_f_set_1(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_rr_xxx_x_set_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_ack_xxx_x_set_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_send_ua_rsp_f_set_p(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_set_s_flag_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_s_flag_1(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_start_p_timer(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_start_ack_timer(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_start_rej_timer(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_start_ack_tmr_if_not_running(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_stop_ack_timer(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_stop_p_timer(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_stop_rej_timer(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_stop_all_timers(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_stop_other_timers(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_upd_nr_received(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_inc_tx_win_size(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_dec_tx_win_size(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_upd_p_flag(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_data_flag_2(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_data_flag_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_data_flag_1(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock* sk, + struct sk_buff *skb); +extern int llc_conn_ac_set_p_flag_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_remote_busy_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_retry_cnt_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_cause_flag_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_cause_flag_1(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_inc_retry_cnt_by_1(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_vr_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_inc_vr_by_1(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_vs_0(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_set_vs_nr(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_rst_vs(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_upd_vs(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_disc(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_reset(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_disc_confirm(struct sock* sk, struct sk_buff *skb); +extern u8 llc_circular_between(u8 a, u8 b, u8 c); +extern int llc_conn_ac_send_ack_if_needed(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_adjust_npta_by_rr(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_adjust_npta_by_rnr(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_rst_sendack_flag(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk, struct sk_buff *skb); +extern int llc_conn_ac_send_i_as_ack(struct sock* sk, struct sk_buff *skb); + +extern void llc_conn_busy_tmr_cb(unsigned long timeout_data); +extern void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data); +extern void llc_conn_ack_tmr_cb(unsigned long timeout_data); +extern void llc_conn_rej_tmr_cb(unsigned long timeout_data); + +extern void llc_conn_set_p_flag(struct sock *sk, u8 value); +#endif /* LLC_C_AC_H */ diff --git a/include/net/llc_c_ev.h b/include/net/llc_c_ev.h new file mode 100644 index 00000000..23a40938 --- /dev/null +++ b/include/net/llc_c_ev.h @@ -0,0 +1,269 @@ +#ifndef LLC_C_EV_H +#define LLC_C_EV_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <net/sock.h> + +/* Connection component state transition event qualifiers */ +/* Types of events (possible values in 'ev->type') */ +#define LLC_CONN_EV_TYPE_SIMPLE 1 +#define LLC_CONN_EV_TYPE_CONDITION 2 +#define LLC_CONN_EV_TYPE_PRIM 3 +#define LLC_CONN_EV_TYPE_PDU 4 /* command/response PDU */ +#define LLC_CONN_EV_TYPE_ACK_TMR 5 +#define LLC_CONN_EV_TYPE_P_TMR 6 +#define LLC_CONN_EV_TYPE_REJ_TMR 7 +#define LLC_CONN_EV_TYPE_BUSY_TMR 8 +#define LLC_CONN_EV_TYPE_RPT_STATUS 9 +#define LLC_CONN_EV_TYPE_SENDACK_TMR 10 + +#define NBR_CONN_EV 5 +/* Connection events which cause state transitions when fully qualified */ + +#define LLC_CONN_EV_CONN_REQ 1 +#define LLC_CONN_EV_CONN_RESP 2 +#define LLC_CONN_EV_DATA_REQ 3 +#define LLC_CONN_EV_DISC_REQ 4 +#define LLC_CONN_EV_RESET_REQ 5 +#define LLC_CONN_EV_RESET_RESP 6 +#define LLC_CONN_EV_LOCAL_BUSY_DETECTED 7 +#define LLC_CONN_EV_LOCAL_BUSY_CLEARED 8 +#define LLC_CONN_EV_RX_BAD_PDU 9 +#define LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X 10 +#define LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X 11 +#define LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X 12 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X 13 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_UNEXPD_Ns 14 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_INVAL_Ns 15 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X 16 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_UNEXPD_Ns 17 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_INVAL_Ns 18 +#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_X 19 +#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X 20 +#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_X 21 +#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_X 22 +#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_X 23 +#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_X 24 +#define LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X 25 +#define LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X 26 +#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_X 27 +#define LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_X 28 +#define LLC_CONN_EV_RX_XXX_YYY 29 +#define LLC_CONN_EV_RX_ZZZ_CMD_Pbit_SET_X_INVAL_Nr 30 +#define LLC_CONN_EV_RX_ZZZ_RSP_Fbit_SET_X_INVAL_Nr 31 +#define LLC_CONN_EV_P_TMR_EXP 32 +#define LLC_CONN_EV_ACK_TMR_EXP 33 +#define LLC_CONN_EV_REJ_TMR_EXP 34 +#define LLC_CONN_EV_BUSY_TMR_EXP 35 +#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_1 36 +#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_0 37 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns 38 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns 39 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns 40 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns 41 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 42 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 43 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 44 +#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 45 +#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 46 +#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 47 +#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 48 +#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 49 +#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 50 +#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 51 +#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 52 +#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 53 +#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 54 +#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 55 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 56 +#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 57 +#define LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_1 58 +#define LLC_CONN_EV_TX_BUFF_FULL 59 + +#define LLC_CONN_EV_INIT_P_F_CYCLE 100 +/* + * Connection event qualifiers; for some events a certain combination of + * these qualifiers must be TRUE before event recognized valid for state; + * these constants act as indexes into the Event Qualifier function + * table + */ +#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_1 1 +#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_0 2 +#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_2 3 +#define LLC_CONN_EV_QFY_P_FLAG_EQ_1 4 +#define LLC_CONN_EV_QFY_P_FLAG_EQ_0 5 +#define LLC_CONN_EV_QFY_P_FLAG_EQ_Fbit 6 +#define LLC_CONN_EV_QFY_REMOTE_BUSY_EQ_0 7 +#define LLC_CONN_EV_QFY_RETRY_CNT_LT_N2 8 +#define LLC_CONN_EV_QFY_RETRY_CNT_GTE_N2 9 +#define LLC_CONN_EV_QFY_S_FLAG_EQ_1 10 +#define LLC_CONN_EV_QFY_S_FLAG_EQ_0 11 +#define LLC_CONN_EV_QFY_INIT_P_F_CYCLE 12 + +struct llc_conn_state_ev { + u8 type; + u8 prim; + u8 prim_type; + u8 reason; + u8 status; + u8 ind_prim; + u8 cfm_prim; +}; + +static __inline__ struct llc_conn_state_ev *llc_conn_ev(struct sk_buff *skb) +{ + return (struct llc_conn_state_ev *)skb->cb; +} + +typedef int (*llc_conn_ev_t)(struct sock *sk, struct sk_buff *skb); +typedef int (*llc_conn_ev_qfyr_t)(struct sock *sk, struct sk_buff *skb); + +extern int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_local_busy_detected(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_p_tmr_exp(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_ack_tmr_exp(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_rej_tmr_exp(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_busy_tmr_exp(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_sendack_tmr_exp(struct sock *sk, struct sk_buff *skb); +/* NOT_USED functions and their variations */ +extern int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_rx_any_frame(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct sk_buff *skb); + +/* Available connection action qualifiers */ +extern int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_set_status_conn(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_set_status_disc(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_set_status_failed(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk, + struct sk_buff *skb); +extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, + struct sk_buff *skb); + +static __inline__ int llc_conn_space(struct sock *sk, struct sk_buff *skb) +{ + return atomic_read(&sk->sk_rmem_alloc) + skb->truesize < + (unsigned)sk->sk_rcvbuf; +} +#endif /* LLC_C_EV_H */ diff --git a/include/net/llc_c_st.h b/include/net/llc_c_st.h new file mode 100644 index 00000000..0e79cfba --- /dev/null +++ b/include/net/llc_c_st.h @@ -0,0 +1,48 @@ +#ifndef LLC_C_ST_H +#define LLC_C_ST_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Connection component state management */ +/* connection states */ +#define LLC_CONN_OUT_OF_SVC 0 /* prior to allocation */ + +#define LLC_CONN_STATE_ADM 1 /* disc, initial state */ +#define LLC_CONN_STATE_SETUP 2 /* disconnected state */ +#define LLC_CONN_STATE_NORMAL 3 /* connected state */ +#define LLC_CONN_STATE_BUSY 4 /* connected state */ +#define LLC_CONN_STATE_REJ 5 /* connected state */ +#define LLC_CONN_STATE_AWAIT 6 /* connected state */ +#define LLC_CONN_STATE_AWAIT_BUSY 7 /* connected state */ +#define LLC_CONN_STATE_AWAIT_REJ 8 /* connected state */ +#define LLC_CONN_STATE_D_CONN 9 /* disconnected state */ +#define LLC_CONN_STATE_RESET 10 /* disconnected state */ +#define LLC_CONN_STATE_ERROR 11 /* disconnected state */ +#define LLC_CONN_STATE_TEMP 12 /* disconnected state */ + +#define NBR_CONN_STATES 12 /* size of state table */ +#define NO_STATE_CHANGE 100 + +/* Connection state table structure */ +struct llc_conn_state_trans { + llc_conn_ev_t ev; + u8 next_state; + llc_conn_ev_qfyr_t *ev_qualifiers; + llc_conn_action_t *ev_actions; +}; + +struct llc_conn_state { + u8 current_state; + struct llc_conn_state_trans **transitions; +}; + +extern struct llc_conn_state llc_conn_state_table[]; +#endif /* LLC_C_ST_H */ diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h new file mode 100644 index 00000000..2f97d8dd --- /dev/null +++ b/include/net/llc_conn.h @@ -0,0 +1,122 @@ +#ifndef LLC_CONN_H +#define LLC_CONN_H +/* + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001, 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include <linux/timer.h> +#include <net/llc_if.h> +#include <net/sock.h> +#include <linux/llc.h> + +#define LLC_EVENT 1 +#define LLC_PACKET 2 + +#define LLC2_P_TIME 2 +#define LLC2_ACK_TIME 1 +#define LLC2_REJ_TIME 3 +#define LLC2_BUSY_TIME 3 + +struct llc_timer { + struct timer_list timer; + unsigned long expire; /* timer expire time */ +}; + +struct llc_sock { + /* struct sock must be the first member of llc_sock */ + struct sock sk; + struct sockaddr_llc addr; /* address sock is bound to */ + u8 state; /* state of connection */ + struct llc_sap *sap; /* pointer to parent SAP */ + struct llc_addr laddr; /* lsap/mac pair */ + struct llc_addr daddr; /* dsap/mac pair */ + struct net_device *dev; /* device to send to remote */ + u32 copied_seq; /* head of yet unread data */ + u8 retry_count; /* number of retries */ + u8 ack_must_be_send; + u8 first_pdu_Ns; + u8 npta; + struct llc_timer ack_timer; + struct llc_timer pf_cycle_timer; + struct llc_timer rej_sent_timer; + struct llc_timer busy_state_timer; /* ind busy clr at remote LLC */ + u8 vS; /* seq# next in-seq I-PDU tx'd*/ + u8 vR; /* seq# next in-seq I-PDU rx'd*/ + u32 n2; /* max nbr re-tx's for timeout*/ + u32 n1; /* max nbr octets in I PDU */ + u8 k; /* tx window size; max = 127 */ + u8 rw; /* rx window size; max = 127 */ + u8 p_flag; /* state flags */ + u8 f_flag; + u8 s_flag; + u8 data_flag; + u8 remote_busy_flag; + u8 cause_flag; + struct sk_buff_head pdu_unack_q; /* PUDs sent/waiting ack */ + u16 link; /* network layer link number */ + u8 X; /* a temporary variable */ + u8 ack_pf; /* this flag indicates what is + the P-bit of acknowledge */ + u8 failed_data_req; /* recognize that already exist a + failed llc_data_req_handler + (tx_buffer_full or unacceptable + state */ + u8 dec_step; + u8 inc_cntr; + u8 dec_cntr; + u8 connect_step; + u8 last_nr; /* NR of last pdu received */ + u32 rx_pdu_hdr; /* used for saving header of last pdu + received and caused sending FRMR. + Used for resending FRMR */ + u32 cmsg_flags; + struct hlist_node dev_hash_node; +}; + +static inline struct llc_sock *llc_sk(const struct sock *sk) +{ + return (struct llc_sock *)sk; +} + +static __inline__ void llc_set_backlog_type(struct sk_buff *skb, char type) +{ + skb->cb[sizeof(skb->cb) - 1] = type; +} + +static __inline__ char llc_backlog_type(struct sk_buff *skb) +{ + return skb->cb[sizeof(skb->cb) - 1]; +} + +extern struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, + struct proto *prot); +extern void llc_sk_free(struct sock *sk); + +extern void llc_sk_reset(struct sock *sk); + +/* Access to a connection */ +extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb); +extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); +extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb); +extern void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, + u8 first_p_bit); +extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, + u8 first_f_bit); +extern int llc_conn_remove_acked_pdus(struct sock *conn, u8 nr, + u16 *how_many_unacked); +extern struct sock *llc_lookup_established(struct llc_sap *sap, + struct llc_addr *daddr, + struct llc_addr *laddr); +extern void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk); +extern void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk); + +extern u8 llc_data_accept_state(u8 state); +extern void llc_build_offset_table(void); +#endif /* LLC_CONN_H */ diff --git a/include/net/llc_if.h b/include/net/llc_if.h new file mode 100644 index 00000000..b595a004 --- /dev/null +++ b/include/net/llc_if.h @@ -0,0 +1,99 @@ +#ifndef LLC_IF_H +#define LLC_IF_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Defines LLC interface to network layer */ +/* Available primitives */ +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/llc.h> +#include <linux/etherdevice.h> +#include <net/llc.h> + +#define LLC_DATAUNIT_PRIM 1 +#define LLC_CONN_PRIM 2 +#define LLC_DATA_PRIM 3 +#define LLC_DISC_PRIM 4 +#define LLC_RESET_PRIM 5 +#define LLC_FLOWCONTROL_PRIM 6 /* Not supported at this time */ +#define LLC_DISABLE_PRIM 7 +#define LLC_XID_PRIM 8 +#define LLC_TEST_PRIM 9 +#define LLC_SAP_ACTIVATION 10 +#define LLC_SAP_DEACTIVATION 11 + +#define LLC_NBR_PRIMITIVES 11 + +#define LLC_IND 1 +#define LLC_CONFIRM 2 + +/* Primitive type */ +#define LLC_PRIM_TYPE_REQ 1 +#define LLC_PRIM_TYPE_IND 2 +#define LLC_PRIM_TYPE_RESP 3 +#define LLC_PRIM_TYPE_CONFIRM 4 + +/* Reset reasons, remote entity or local LLC */ +#define LLC_RESET_REASON_REMOTE 1 +#define LLC_RESET_REASON_LOCAL 2 + +/* Disconnect reasons */ +#define LLC_DISC_REASON_RX_DM_RSP_PDU 0 +#define LLC_DISC_REASON_RX_DISC_CMD_PDU 1 +#define LLC_DISC_REASON_ACK_TMR_EXP 2 + +/* Confirm reasons */ +#define LLC_STATUS_CONN 0 /* connect confirm & reset confirm */ +#define LLC_STATUS_DISC 1 /* connect confirm & reset confirm */ +#define LLC_STATUS_FAILED 2 /* connect confirm & reset confirm */ +#define LLC_STATUS_IMPOSSIBLE 3 /* connect confirm */ +#define LLC_STATUS_RECEIVED 4 /* data conn */ +#define LLC_STATUS_REMOTE_BUSY 5 /* data conn */ +#define LLC_STATUS_REFUSE 6 /* data conn */ +#define LLC_STATUS_CONFLICT 7 /* disconnect conn */ +#define LLC_STATUS_RESET_DONE 8 /* */ + +/** + * llc_mac_null - determines if a address is a null mac address + * @mac: Mac address to test if null. + * + * Determines if a given address is a null mac address. Returns 0 if the + * address is not a null mac, 1 if the address is a null mac. + */ +static inline int llc_mac_null(const u8 *mac) +{ + return is_zero_ether_addr(mac); +} + +static inline int llc_mac_multicast(const u8 *mac) +{ + return is_multicast_ether_addr(mac); +} +/** + * llc_mac_match - determines if two mac addresses are the same + * @mac1: First mac address to compare. + * @mac2: Second mac address to compare. + * + * Determines if two given mac address are the same. Returns 0 if there + * is not a complete match up to len, 1 if a complete match up to len is + * found. + */ +static inline int llc_mac_match(const u8 *mac1, const u8 *mac2) +{ + return !compare_ether_addr(mac1, mac2); +} + +extern int llc_establish_connection(struct sock *sk, u8 *lmac, + u8 *dmac, u8 dsap); +extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb); +extern int llc_send_disc(struct sock *sk); +#endif /* LLC_IF_H */ diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h new file mode 100644 index 00000000..75b8e296 --- /dev/null +++ b/include/net/llc_pdu.h @@ -0,0 +1,437 @@ +#ifndef LLC_PDU_H +#define LLC_PDU_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/if_ether.h> +#include <linux/if_tr.h> + +/* Lengths of frame formats */ +#define LLC_PDU_LEN_I 4 /* header and 2 control bytes */ +#define LLC_PDU_LEN_S 4 +#define LLC_PDU_LEN_U 3 /* header and 1 control byte */ +/* Known SAP addresses */ +#define LLC_GLOBAL_SAP 0xFF +#define LLC_NULL_SAP 0x00 /* not network-layer visible */ +#define LLC_MGMT_INDIV 0x02 /* station LLC mgmt indiv addr */ +#define LLC_MGMT_GRP 0x03 /* station LLC mgmt group addr */ +#define LLC_RDE_SAP 0xA6 /* route ... */ + +/* SAP field bit masks */ +#define LLC_ISO_RESERVED_SAP 0x02 +#define LLC_SAP_GROUP_DSAP 0x01 +#define LLC_SAP_RESP_SSAP 0x01 + +/* Group/individual DSAP indicator is DSAP field */ +#define LLC_PDU_GROUP_DSAP_MASK 0x01 +#define LLC_PDU_IS_GROUP_DSAP(pdu) \ + ((pdu->dsap & LLC_PDU_GROUP_DSAP_MASK) ? 0 : 1) +#define LLC_PDU_IS_INDIV_DSAP(pdu) \ + (!(pdu->dsap & LLC_PDU_GROUP_DSAP_MASK) ? 0 : 1) + +/* Command/response PDU indicator in SSAP field */ +#define LLC_PDU_CMD_RSP_MASK 0x01 +#define LLC_PDU_CMD 0 +#define LLC_PDU_RSP 1 +#define LLC_PDU_IS_CMD(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 0 : 1) +#define LLC_PDU_IS_RSP(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 1 : 0) + +/* Get PDU type from 2 lowest-order bits of control field first byte */ +#define LLC_PDU_TYPE_I_MASK 0x01 /* 16-bit control field */ +#define LLC_PDU_TYPE_S_MASK 0x03 +#define LLC_PDU_TYPE_U_MASK 0x03 /* 8-bit control field */ +#define LLC_PDU_TYPE_MASK 0x03 + +#define LLC_PDU_TYPE_I 0 /* first bit */ +#define LLC_PDU_TYPE_S 1 /* first two bits */ +#define LLC_PDU_TYPE_U 3 /* first two bits */ + +#define LLC_PDU_TYPE_IS_I(pdu) \ + ((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 1 : 0) + +#define LLC_PDU_TYPE_IS_U(pdu) \ + (((pdu->ctrl_1 & LLC_PDU_TYPE_U_MASK) == LLC_PDU_TYPE_U) ? 1 : 0) + +#define LLC_PDU_TYPE_IS_S(pdu) \ + (((pdu->ctrl_1 & LLC_PDU_TYPE_S_MASK) == LLC_PDU_TYPE_S) ? 1 : 0) + +/* U-format PDU control field masks */ +#define LLC_U_PF_BIT_MASK 0x10 /* P/F bit mask */ +#define LLC_U_PF_IS_1(pdu) ((pdu->ctrl_1 & LLC_U_PF_BIT_MASK) ? 1 : 0) +#define LLC_U_PF_IS_0(pdu) ((!(pdu->ctrl_1 & LLC_U_PF_BIT_MASK)) ? 1 : 0) + +#define LLC_U_PDU_CMD_MASK 0xEC /* cmd/rsp mask */ +#define LLC_U_PDU_CMD(pdu) (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK) +#define LLC_U_PDU_RSP(pdu) (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK) + +#define LLC_1_PDU_CMD_UI 0x00 /* Type 1 cmds/rsps */ +#define LLC_1_PDU_CMD_XID 0xAC +#define LLC_1_PDU_CMD_TEST 0xE0 + +#define LLC_2_PDU_CMD_SABME 0x6C /* Type 2 cmds/rsps */ +#define LLC_2_PDU_CMD_DISC 0x40 +#define LLC_2_PDU_RSP_UA 0x60 +#define LLC_2_PDU_RSP_DM 0x0C +#define LLC_2_PDU_RSP_FRMR 0x84 + +/* Type 1 operations */ + +/* XID information field bit masks */ + +/* LLC format identifier (byte 1) */ +#define LLC_XID_FMT_ID 0x81 /* first byte must be this */ + +/* LLC types/classes identifier (byte 2) */ +#define LLC_XID_CLASS_ZEROS_MASK 0xE0 /* these must be zeros */ +#define LLC_XID_CLASS_MASK 0x1F /* AND with byte to get below */ + +#define LLC_XID_NULL_CLASS_1 0x01 /* if NULL LSAP...use these */ +#define LLC_XID_NULL_CLASS_2 0x03 +#define LLC_XID_NULL_CLASS_3 0x05 +#define LLC_XID_NULL_CLASS_4 0x07 + +#define LLC_XID_NNULL_TYPE_1 0x01 /* if non-NULL LSAP...use these */ +#define LLC_XID_NNULL_TYPE_2 0x02 +#define LLC_XID_NNULL_TYPE_3 0x04 +#define LLC_XID_NNULL_TYPE_1_2 0x03 +#define LLC_XID_NNULL_TYPE_1_3 0x05 +#define LLC_XID_NNULL_TYPE_2_3 0x06 +#define LLC_XID_NNULL_ALL 0x07 + +/* Sender Receive Window (byte 3) */ +#define LLC_XID_RW_MASK 0xFE /* AND with value to get below */ + +#define LLC_XID_MIN_RW 0x02 /* lowest-order bit always zero */ + +/* Type 2 operations */ + +#define LLC_2_SEQ_NBR_MODULO ((u8) 128) + +/* I-PDU masks ('ctrl' is I-PDU control word) */ +#define LLC_I_GET_NS(pdu) (u8)((pdu->ctrl_1 & 0xFE) >> 1) +#define LLC_I_GET_NR(pdu) (u8)((pdu->ctrl_2 & 0xFE) >> 1) + +#define LLC_I_PF_BIT_MASK 0x01 + +#define LLC_I_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_I_PF_BIT_MASK)) ? 1 : 0) +#define LLC_I_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_I_PF_BIT_MASK) ? 1 : 0) + +/* S-PDU supervisory commands and responses */ + +#define LLC_S_PDU_CMD_MASK 0x0C +#define LLC_S_PDU_CMD(pdu) (pdu->ctrl_1 & LLC_S_PDU_CMD_MASK) +#define LLC_S_PDU_RSP(pdu) (pdu->ctrl_1 & LLC_S_PDU_CMD_MASK) + +#define LLC_2_PDU_CMD_RR 0x00 /* rx ready cmd */ +#define LLC_2_PDU_RSP_RR 0x00 /* rx ready rsp */ +#define LLC_2_PDU_CMD_REJ 0x08 /* reject PDU cmd */ +#define LLC_2_PDU_RSP_REJ 0x08 /* reject PDU rsp */ +#define LLC_2_PDU_CMD_RNR 0x04 /* rx not ready cmd */ +#define LLC_2_PDU_RSP_RNR 0x04 /* rx not ready rsp */ + +#define LLC_S_PF_BIT_MASK 0x01 +#define LLC_S_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_S_PF_BIT_MASK)) ? 1 : 0) +#define LLC_S_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_S_PF_BIT_MASK) ? 1 : 0) + +#define PDU_SUPV_GET_Nr(pdu) ((pdu->ctrl_2 & 0xFE) >> 1) +#define PDU_GET_NEXT_Vr(sn) (++sn & ~LLC_2_SEQ_NBR_MODULO) + +/* FRMR information field macros */ + +#define FRMR_INFO_LENGTH 5 /* 5 bytes of information */ + +/* + * info is pointer to FRMR info field structure; 'rej_ctrl' is byte pointer + * (if U-PDU) or word pointer to rejected PDU control field + */ +#define FRMR_INFO_SET_REJ_CNTRL(info,rej_ctrl) \ + info->rej_pdu_ctrl = ((*((u8 *) rej_ctrl) & \ + LLC_PDU_TYPE_U) != LLC_PDU_TYPE_U ? \ + (u16)*((u16 *) rej_ctrl) : \ + (((u16) *((u8 *) rej_ctrl)) & 0x00FF)) + +/* + * Info is pointer to FRMR info field structure; 'vs' is a byte containing + * send state variable value in low-order 7 bits (insure the lowest-order + * bit remains zero (0)) + */ +#define FRMR_INFO_SET_Vs(info,vs) (info->curr_ssv = (((u8) vs) << 1)) +#define FRMR_INFO_SET_Vr(info,vr) (info->curr_rsv = (((u8) vr) << 1)) + +/* + * Info is pointer to FRMR info field structure; 'cr' is a byte containing + * the C/R bit value in the low-order bit + */ +#define FRMR_INFO_SET_C_R_BIT(info, cr) (info->curr_rsv |= (((u8) cr) & 0x01)) + +/* + * In the remaining five macros, 'info' is pointer to FRMR info field + * structure; 'ind' is a byte containing the bit value to set in the + * lowest-order bit) + */ +#define FRMR_INFO_SET_INVALID_PDU_CTRL_IND(info, ind) \ + (info->ind_bits = ((info->ind_bits & 0xFE) | (((u8) ind) & 0x01))) + +#define FRMR_INFO_SET_INVALID_PDU_INFO_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xFD) | (((u8) ind) & 0x02))) + +#define FRMR_INFO_SET_PDU_INFO_2LONG_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xFB) | (((u8) ind) & 0x04))) + +#define FRMR_INFO_SET_PDU_INVALID_Nr_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xF7) | (((u8) ind) & 0x08))) + +#define FRMR_INFO_SET_PDU_INVALID_Ns_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xEF) | (((u8) ind) & 0x10))) + +/* Sequence-numbered PDU format (4 bytes in length) */ +struct llc_pdu_sn { + u8 dsap; + u8 ssap; + u8 ctrl_1; + u8 ctrl_2; +}; + +static inline struct llc_pdu_sn *llc_pdu_sn_hdr(struct sk_buff *skb) +{ + return (struct llc_pdu_sn *)skb_network_header(skb); +} + +/* Un-numbered PDU format (3 bytes in length) */ +struct llc_pdu_un { + u8 dsap; + u8 ssap; + u8 ctrl_1; +}; + +static inline struct llc_pdu_un *llc_pdu_un_hdr(struct sk_buff *skb) +{ + return (struct llc_pdu_un *)skb_network_header(skb); +} + +/** + * llc_pdu_header_init - initializes pdu header + * @skb: input skb that header must be set into it. + * @type: type of PDU (U, I or S). + * @ssap: source sap. + * @dsap: destination sap. + * @cr: command/response bit (0 or 1). + * + * This function sets DSAP, SSAP and command/Response bit in LLC header. + */ +static inline void llc_pdu_header_init(struct sk_buff *skb, u8 type, + u8 ssap, u8 dsap, u8 cr) +{ + const int hlen = type == LLC_PDU_TYPE_U ? 3 : 4; + struct llc_pdu_un *pdu; + + skb_push(skb, hlen); + skb_reset_network_header(skb); + pdu = llc_pdu_un_hdr(skb); + pdu->dsap = dsap; + pdu->ssap = ssap; + pdu->ssap |= cr; +} + +/** + * llc_pdu_decode_sa - extracs source address (MAC) of input frame + * @skb: input skb that source address must be extracted from it. + * @sa: pointer to source address (6 byte array). + * + * This function extracts source address(MAC) of input frame. + */ +static inline void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) +{ + if (skb->protocol == htons(ETH_P_802_2)) + memcpy(sa, eth_hdr(skb)->h_source, ETH_ALEN); + else if (skb->protocol == htons(ETH_P_TR_802_2)) { + memcpy(sa, tr_hdr(skb)->saddr, ETH_ALEN); + *sa &= 0x7F; + } +} + +/** + * llc_pdu_decode_da - extracts dest address of input frame + * @skb: input skb that destination address must be extracted from it + * @sa: pointer to destination address (6 byte array). + * + * This function extracts destination address(MAC) of input frame. + */ +static inline void llc_pdu_decode_da(struct sk_buff *skb, u8 *da) +{ + if (skb->protocol == htons(ETH_P_802_2)) + memcpy(da, eth_hdr(skb)->h_dest, ETH_ALEN); + else if (skb->protocol == htons(ETH_P_TR_802_2)) + memcpy(da, tr_hdr(skb)->daddr, ETH_ALEN); +} + +/** + * llc_pdu_decode_ssap - extracts source SAP of input frame + * @skb: input skb that source SAP must be extracted from it. + * @ssap: source SAP (output argument). + * + * This function extracts source SAP of input frame. Right bit of SSAP is + * command/response bit. + */ +static inline void llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap) +{ + *ssap = llc_pdu_un_hdr(skb)->ssap & 0xFE; +} + +/** + * llc_pdu_decode_dsap - extracts dest SAP of input frame + * @skb: input skb that destination SAP must be extracted from it. + * @dsap: destination SAP (output argument). + * + * This function extracts destination SAP of input frame. right bit of + * DSAP designates individual/group SAP. + */ +static inline void llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap) +{ + *dsap = llc_pdu_un_hdr(skb)->dsap & 0xFE; +} + +/** + * llc_pdu_init_as_ui_cmd - sets LLC header as UI PDU + * @skb: input skb that header must be set into it. + * + * This function sets third byte of LLC header as a UI PDU. + */ +static inline void llc_pdu_init_as_ui_cmd(struct sk_buff *skb) +{ + struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_UI; +} + +/** + * llc_pdu_init_as_test_cmd - sets PDU as TEST + * @skb - Address of the skb to build + * + * Sets a PDU as TEST + */ +static inline void llc_pdu_init_as_test_cmd(struct sk_buff *skb) +{ + struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; +} + +/** + * llc_pdu_init_as_test_rsp - build TEST response PDU + * @skb: Address of the skb to build + * @ev_skb: The received TEST command PDU frame + * + * Builds a pdu frame as a TEST response. + */ +static inline void llc_pdu_init_as_test_rsp(struct sk_buff *skb, + struct sk_buff *ev_skb) +{ + struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; + if (ev_skb->protocol == htons(ETH_P_802_2)) { + struct llc_pdu_un *ev_pdu = llc_pdu_un_hdr(ev_skb); + int dsize; + + dsize = ntohs(eth_hdr(ev_skb)->h_proto) - 3; + memcpy(((u8 *)pdu) + 3, ((u8 *)ev_pdu) + 3, dsize); + skb_put(skb, dsize); + } +} + +/* LLC Type 1 XID command/response information fields format */ +struct llc_xid_info { + u8 fmt_id; /* always 0x81 for LLC */ + u8 type; /* different if NULL/non-NULL LSAP */ + u8 rw; /* sender receive window */ +}; + +/** + * llc_pdu_init_as_xid_cmd - sets bytes 3, 4 & 5 of LLC header as XID + * @skb: input skb that header must be set into it. + * + * This function sets third,fourth,fifth and sixth bytes of LLC header as + * a XID PDU. + */ +static inline void llc_pdu_init_as_xid_cmd(struct sk_buff *skb, + u8 svcs_supported, u8 rx_window) +{ + struct llc_xid_info *xid_info; + struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_XID; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; + xid_info = (struct llc_xid_info *)(((u8 *)&pdu->ctrl_1) + 1); + xid_info->fmt_id = LLC_XID_FMT_ID; /* 0x81 */ + xid_info->type = svcs_supported; + xid_info->rw = rx_window << 1; /* size of receive window */ + skb_put(skb, sizeof(struct llc_xid_info)); +} + +/** + * llc_pdu_init_as_xid_rsp - builds XID response PDU + * @skb: Address of the skb to build + * @svcs_supported: The class of the LLC (I or II) + * @rx_window: The size of the receive window of the LLC + * + * Builds a pdu frame as an XID response. + */ +static inline void llc_pdu_init_as_xid_rsp(struct sk_buff *skb, + u8 svcs_supported, u8 rx_window) +{ + struct llc_xid_info *xid_info; + struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_XID; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; + + xid_info = (struct llc_xid_info *)(((u8 *)&pdu->ctrl_1) + 1); + xid_info->fmt_id = LLC_XID_FMT_ID; + xid_info->type = svcs_supported; + xid_info->rw = rx_window << 1; + skb_put(skb, sizeof(struct llc_xid_info)); +} + +/* LLC Type 2 FRMR response information field format */ +struct llc_frmr_info { + u16 rej_pdu_ctrl; /* bits 1-8 if U-PDU */ + u8 curr_ssv; /* current send state variable val */ + u8 curr_rsv; /* current receive state variable */ + u8 ind_bits; /* indicator bits set with macro */ +}; + +extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type); +extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value); +extern void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit); +extern void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit); +extern void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr); +extern void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit); +extern void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit); +extern void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, + struct llc_pdu_sn *prev_pdu, + u8 f_bit, u8 vs, u8 vr, u8 vzyxw); +extern void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit); +#endif /* LLC_PDU_H */ diff --git a/include/net/llc_s_ac.h b/include/net/llc_s_ac.h new file mode 100644 index 00000000..37a3bbd0 --- /dev/null +++ b/include/net/llc_s_ac.h @@ -0,0 +1,39 @@ +#ifndef LLC_S_AC_H +#define LLC_S_AC_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* SAP component actions */ +#define SAP_ACT_UNITDATA_IND 1 +#define SAP_ACT_SEND_UI 2 +#define SAP_ACT_SEND_XID_C 3 +#define SAP_ACT_SEND_XID_R 4 +#define SAP_ACT_SEND_TEST_C 5 +#define SAP_ACT_SEND_TEST_R 6 +#define SAP_ACT_REPORT_STATUS 7 +#define SAP_ACT_XID_IND 8 +#define SAP_ACT_TEST_IND 9 + +/* All action functions must look like this */ +typedef int (*llc_sap_action_t)(struct llc_sap *sap, struct sk_buff *skb); + +extern int llc_sap_action_unitdata_ind(struct llc_sap *sap, + struct sk_buff *skb); +extern int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_action_report_status(struct llc_sap *sap, + struct sk_buff *skb); +extern int llc_sap_action_xid_ind(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_action_test_ind(struct llc_sap *sap, struct sk_buff *skb); +#endif /* LLC_S_AC_H */ diff --git a/include/net/llc_s_ev.h b/include/net/llc_s_ev.h new file mode 100644 index 00000000..e3acb932 --- /dev/null +++ b/include/net/llc_s_ev.h @@ -0,0 +1,67 @@ +#ifndef LLC_S_EV_H +#define LLC_S_EV_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#include <linux/skbuff.h> + +/* Defines SAP component events */ +/* Types of events (possible values in 'ev->type') */ +#define LLC_SAP_EV_TYPE_SIMPLE 1 +#define LLC_SAP_EV_TYPE_CONDITION 2 +#define LLC_SAP_EV_TYPE_PRIM 3 +#define LLC_SAP_EV_TYPE_PDU 4 /* command/response PDU */ +#define LLC_SAP_EV_TYPE_ACK_TMR 5 +#define LLC_SAP_EV_TYPE_RPT_STATUS 6 + +#define LLC_SAP_EV_ACTIVATION_REQ 1 +#define LLC_SAP_EV_RX_UI 2 +#define LLC_SAP_EV_UNITDATA_REQ 3 +#define LLC_SAP_EV_XID_REQ 4 +#define LLC_SAP_EV_RX_XID_C 5 +#define LLC_SAP_EV_RX_XID_R 6 +#define LLC_SAP_EV_TEST_REQ 7 +#define LLC_SAP_EV_RX_TEST_C 8 +#define LLC_SAP_EV_RX_TEST_R 9 +#define LLC_SAP_EV_DEACTIVATION_REQ 10 + +struct llc_sap_state_ev { + u8 prim; + u8 prim_type; + u8 type; + u8 reason; + u8 ind_cfm_flag; + struct llc_addr saddr; + struct llc_addr daddr; +}; + +static __inline__ struct llc_sap_state_ev *llc_sap_ev(struct sk_buff *skb) +{ + return (struct llc_sap_state_ev *)skb->cb; +} + +struct llc_sap; + +typedef int (*llc_sap_ev_t)(struct llc_sap *sap, struct sk_buff *skb); + +extern int llc_sap_ev_activation_req(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_rx_ui(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_xid_req(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_test_req(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct sk_buff *skb); +extern int llc_sap_ev_deactivation_req(struct llc_sap *sap, + struct sk_buff *skb); +#endif /* LLC_S_EV_H */ diff --git a/include/net/llc_s_st.h b/include/net/llc_s_st.h new file mode 100644 index 00000000..567c681f --- /dev/null +++ b/include/net/llc_s_st.h @@ -0,0 +1,32 @@ +#ifndef LLC_S_ST_H +#define LLC_S_ST_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +#define LLC_NR_SAP_STATES 2 /* size of state table */ + +/* structures and types */ +/* SAP state table structure */ +struct llc_sap_state_trans { + llc_sap_ev_t ev; + u8 next_state; + llc_sap_action_t *ev_actions; +}; + +struct llc_sap_state { + u8 curr_state; + struct llc_sap_state_trans **transitions; +}; + +/* only access to SAP state table */ +extern struct llc_sap_state llc_sap_state_table[LLC_NR_SAP_STATES]; +#endif /* LLC_S_ST_H */ diff --git a/include/net/llc_sap.h b/include/net/llc_sap.h new file mode 100644 index 00000000..ed25bec2 --- /dev/null +++ b/include/net/llc_sap.h @@ -0,0 +1,36 @@ +#ifndef LLC_SAP_H +#define LLC_SAP_H + +#include <asm/types.h> + +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +struct llc_sap; +struct net_device; +struct sk_buff; +struct sock; + +extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb); +extern void llc_save_primitive(struct sock *sk, struct sk_buff* skb, + unsigned char prim); +extern struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev, + u8 type, u32 data_size); + +extern void llc_build_and_send_test_pkt(struct llc_sap *sap, + struct sk_buff *skb, + unsigned char *dmac, + unsigned char dsap); +extern void llc_build_and_send_xid_pkt(struct llc_sap *sap, + struct sk_buff *skb, + unsigned char *dmac, + unsigned char dsap); +#endif /* LLC_SAP_H */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h new file mode 100644 index 00000000..05aaa878 --- /dev/null +++ b/include/net/mac80211.h @@ -0,0 +1,2700 @@ +/* + * mac80211 <-> driver interface + * + * Copyright 2002-2005, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> + * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef MAC80211_H +#define MAC80211_H + +#include <linux/kernel.h> +#include <linux/if_ether.h> +#include <linux/skbuff.h> +#include <linux/wireless.h> +#include <linux/device.h> +#include <linux/ieee80211.h> +#include <net/cfg80211.h> + +/** + * DOC: Introduction + * + * mac80211 is the Linux stack for 802.11 hardware that implements + * only partial functionality in hard- or firmware. This document + * defines the interface between mac80211 and low-level hardware + * drivers. + */ + +/** + * DOC: Calling mac80211 from interrupts + * + * Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be + * called in hardware interrupt context. The low-level driver must not call any + * other functions in hardware interrupt context. If there is a need for such + * call, the low-level driver should first ACK the interrupt and perform the + * IEEE 802.11 code call after this, e.g. from a scheduled workqueue or even + * tasklet function. + * + * NOTE: If the driver opts to use the _irqsafe() functions, it may not also + * use the non-IRQ-safe functions! + */ + +/** + * DOC: Warning + * + * If you're reading this document and not the header file itself, it will + * be incomplete because not all documentation has been converted yet. + */ + +/** + * DOC: Frame format + * + * As a general rule, when frames are passed between mac80211 and the driver, + * they start with the IEEE 802.11 header and include the same octets that are + * sent over the air except for the FCS which should be calculated by the + * hardware. + * + * There are, however, various exceptions to this rule for advanced features: + * + * The first exception is for hardware encryption and decryption offload + * where the IV/ICV may or may not be generated in hardware. + * + * Secondly, when the hardware handles fragmentation, the frame handed to + * the driver from mac80211 is the MSDU, not the MPDU. + * + * Finally, for received frames, the driver is able to indicate that it has + * filled a radiotap header and put that in front of the frame; if it does + * not do so then mac80211 may add this under certain circumstances. + */ + +/** + * DOC: mac80211 workqueue + * + * mac80211 provides its own workqueue for drivers and internal mac80211 use. + * The workqueue is a single threaded workqueue and can only be accessed by + * helpers for sanity checking. Drivers must ensure all work added onto the + * mac80211 workqueue should be cancelled on the driver stop() callback. + * + * mac80211 will flushed the workqueue upon interface removal and during + * suspend. + * + * All work performed on the mac80211 workqueue must not acquire the RTNL lock. + * + */ + +/** + * enum ieee80211_max_queues - maximum number of queues + * + * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. + */ +enum ieee80211_max_queues { + IEEE80211_MAX_QUEUES = 4, +}; + +/** + * struct ieee80211_tx_queue_params - transmit queue configuration + * + * The information provided in this structure is required for QoS + * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29. + * + * @aifs: arbitration interframe space [0..255] + * @cw_min: minimum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @cw_max: maximum contention window [like @cw_min] + * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled + * @uapsd: is U-APSD mode enabled for the queue + */ +struct ieee80211_tx_queue_params { + u16 txop; + u16 cw_min; + u16 cw_max; + u8 aifs; + bool uapsd; +}; + +struct ieee80211_low_level_stats { + unsigned int dot11ACKFailureCount; + unsigned int dot11RTSFailureCount; + unsigned int dot11FCSErrorCount; + unsigned int dot11RTSSuccessCount; +}; + +/** + * enum ieee80211_bss_change - BSS change notification flags + * + * These flags are used with the bss_info_changed() callback + * to indicate which BSS parameter changed. + * + * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated), + * also implies a change in the AID. + * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed + * @BSS_CHANGED_ERP_PREAMBLE: preamble changed + * @BSS_CHANGED_ERP_SLOT: slot timing changed + * @BSS_CHANGED_HT: 802.11n parameters changed + * @BSS_CHANGED_BASIC_RATES: Basic rateset changed + * @BSS_CHANGED_BEACON_INT: Beacon interval changed + * @BSS_CHANGED_BSSID: BSSID changed, for whatever + * reason (IBSS and managed mode) + * @BSS_CHANGED_BEACON: Beacon data changed, retrieve + * new beacon (beaconing modes) + * @BSS_CHANGED_BEACON_ENABLED: Beaconing should be + * enabled/disabled (beaconing modes) + * @BSS_CHANGED_CQM: Connection quality monitor config changed + * @BSS_CHANGED_IBSS: IBSS join status changed + * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed. + * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note + * that it is only ever disabled for station mode. + */ +enum ieee80211_bss_change { + BSS_CHANGED_ASSOC = 1<<0, + BSS_CHANGED_ERP_CTS_PROT = 1<<1, + BSS_CHANGED_ERP_PREAMBLE = 1<<2, + BSS_CHANGED_ERP_SLOT = 1<<3, + BSS_CHANGED_HT = 1<<4, + BSS_CHANGED_BASIC_RATES = 1<<5, + BSS_CHANGED_BEACON_INT = 1<<6, + BSS_CHANGED_BSSID = 1<<7, + BSS_CHANGED_BEACON = 1<<8, + BSS_CHANGED_BEACON_ENABLED = 1<<9, + BSS_CHANGED_CQM = 1<<10, + BSS_CHANGED_IBSS = 1<<11, + BSS_CHANGED_ARP_FILTER = 1<<12, + BSS_CHANGED_QOS = 1<<13, + + /* when adding here, make sure to change ieee80211_reconfig */ +}; + +/* + * The maximum number of IPv4 addresses listed for ARP filtering. If the number + * of addresses for an interface increase beyond this value, hardware ARP + * filtering will be disabled. + */ +#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4 + +/** + * struct ieee80211_bss_conf - holds the BSS's changing parameters + * + * This structure keeps information about a BSS (and an association + * to that BSS) that can change during the lifetime of the BSS. + * + * @assoc: association status + * @ibss_joined: indicates whether this station is part of an IBSS + * or not + * @aid: association ID number, valid only when @assoc is true + * @use_cts_prot: use CTS protection + * @use_short_preamble: use 802.11b short preamble; + * if the hardware cannot handle this it must set the + * IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE hardware flag + * @use_short_slot: use short slot time (only relevant for ERP); + * if the hardware cannot handle this it must set the + * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag + * @dtim_period: num of beacons before the next DTIM, for beaconing, + * valid in station mode only while @assoc is true and if also + * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf + * @ps_dtim_period) + * @timestamp: beacon timestamp + * @beacon_int: beacon interval + * @assoc_capability: capabilities taken from assoc resp + * @basic_rates: bitmap of basic rates, each bit stands for an + * index into the rate table configured by the driver in + * the current band. + * @bssid: The BSSID for this BSS + * @enable_beacon: whether beaconing should be enabled or not + * @channel_type: Channel type for this BSS -- the hardware might be + * configured for HT40+ while this BSS only uses no-HT, for + * example. + * @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info). + * This field is only valid when the channel type is one of the HT types. + * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value + * implies disabled + * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis + * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The + * may filter ARP queries targeted for other addresses than listed here. + * The driver must allow ARP queries targeted for all address listed here + * to pass through. An empty list implies no ARP queries need to pass. + * @arp_addr_cnt: Number of addresses currently on the list. + * @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may + * filter ARP queries based on the @arp_addr_list, if disabled, the + * hardware must not perform any ARP filtering. Note, that the filter will + * be enabled also in promiscuous mode. + * @qos: This is a QoS-enabled BSS. + */ +struct ieee80211_bss_conf { + const u8 *bssid; + /* association related data */ + bool assoc, ibss_joined; + u16 aid; + /* erp related data */ + bool use_cts_prot; + bool use_short_preamble; + bool use_short_slot; + bool enable_beacon; + u8 dtim_period; + u16 beacon_int; + u16 assoc_capability; + u64 timestamp; + u32 basic_rates; + u16 ht_operation_mode; + s32 cqm_rssi_thold; + u32 cqm_rssi_hyst; + enum nl80211_channel_type channel_type; + __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; + u8 arp_addr_cnt; + bool arp_filter_enabled; + bool qos; +}; + +/** + * enum mac80211_tx_control_flags - flags to describe transmission information/status + * + * These flags are used with the @flags member of &ieee80211_tx_info. + * + * @IEEE80211_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. + * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence + * number to this frame, taking care of not overwriting the fragment + * number and increasing the sequence number only when the + * IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly + * assign sequence numbers to QoS-data frames but cannot do so correctly + * for non-QoS-data and management frames because beacons need them from + * that counter as well and mac80211 cannot guarantee proper sequencing. + * If this flag is set, the driver should instruct the hardware to + * assign a sequence number to the frame or assign one itself. Cf. IEEE + * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for + * beacons and always be clear for frames without a sequence number field. + * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack + * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination + * station + * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame + * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon + * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU + * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. + * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted + * because the destination STA was in powersave mode. Note that to + * avoid race conditions, the filter must be set by the hardware or + * firmware upon receiving a frame that indicates that the station + * went to sleep (must be done on device to filter frames already on + * the queue) and may only be unset after mac80211 gives the OK for + * that by setting the IEEE80211_TX_CTL_CLEAR_PS_FILT (see above), + * since only then is it guaranteed that no more frames are in the + * hardware queue. + * @IEEE80211_TX_STAT_ACK: Frame was acknowledged + * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status + * is for the whole aggregation. + * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, + * so consider using block ack request (BAR). + * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be + * set by rate control algorithms to indicate probe rate, will + * be cleared for fragmented frames (except on the last fragment) + * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, + * used to indicate that a pending frame requires TX processing before + * it can be sent out. + * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, + * used to indicate that a frame was already retried due to PS + * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, + * used to indicate frame should not be encrypted + * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) + * This frame is a response to a PS-poll frame and should be sent + * although the station is in powersave mode. + * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the + * transmit function after the current frame, this can be used + * by drivers to kick the DMA queue only if unset or when the + * queue gets full. + * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted + * after TX status because the destination was asleep, it must not + * be modified again (no seqno assignment, crypto, etc.) + * @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still + * has a radiotap header at skb->data. + * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 + * MLME command (internal to mac80211 to figure out whether to send TX + * status to user space) + * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame + * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this + * frame and selects the maximum number of streams that it can use. + * + * Note: If you have to add new flags to the enumeration, then don't + * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. + */ +enum mac80211_tx_control_flags { + IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), + IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), + IEEE80211_TX_CTL_NO_ACK = BIT(2), + IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3), + IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4), + IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5), + IEEE80211_TX_CTL_AMPDU = BIT(6), + IEEE80211_TX_CTL_INJECTED = BIT(7), + IEEE80211_TX_STAT_TX_FILTERED = BIT(8), + IEEE80211_TX_STAT_ACK = BIT(9), + IEEE80211_TX_STAT_AMPDU = BIT(10), + IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), + IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), + IEEE80211_TX_INTFL_RETRIED = BIT(15), + IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), + IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), + IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), + IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), + IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20), + IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), + IEEE80211_TX_CTL_LDPC = BIT(22), + IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24), +}; + +#define IEEE80211_TX_CTL_STBC_SHIFT 23 + +/* + * This definition is used as a mask to clear all temporary flags, which are + * set by the tx handlers for each transmission attempt by the mac80211 stack. + */ +#define IEEE80211_TX_TEMPORARY_FLAGS (IEEE80211_TX_CTL_NO_ACK | \ + IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT | \ + IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ + IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ + IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ + IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \ + IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ + IEEE80211_TX_CTL_STBC) + +/** + * enum mac80211_rate_control_flags - per-rate flags set by the + * Rate Control algorithm. + * + * These flags are set by the Rate control algorithm for each rate during tx, + * in the @flags member of struct ieee80211_tx_rate. + * + * @IEEE80211_TX_RC_USE_RTS_CTS: Use RTS/CTS exchange for this rate. + * @IEEE80211_TX_RC_USE_CTS_PROTECT: CTS-to-self protection is required. + * This is set if the current BSS requires ERP protection. + * @IEEE80211_TX_RC_USE_SHORT_PREAMBLE: Use short preamble. + * @IEEE80211_TX_RC_MCS: HT rate. + * @IEEE80211_TX_RC_GREEN_FIELD: Indicates whether this rate should be used in + * Greenfield mode. + * @IEEE80211_TX_RC_40_MHZ_WIDTH: Indicates if the Channel Width should be 40 MHz. + * @IEEE80211_TX_RC_DUP_DATA: The frame should be transmitted on both of the + * adjacent 20 MHz channels, if the current channel type is + * NL80211_CHAN_HT40MINUS or NL80211_CHAN_HT40PLUS. + * @IEEE80211_TX_RC_SHORT_GI: Short Guard interval should be used for this rate. + */ +enum mac80211_rate_control_flags { + IEEE80211_TX_RC_USE_RTS_CTS = BIT(0), + IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), + IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), + + /* rate index is an MCS rate number instead of an index */ + IEEE80211_TX_RC_MCS = BIT(3), + IEEE80211_TX_RC_GREEN_FIELD = BIT(4), + IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), + IEEE80211_TX_RC_DUP_DATA = BIT(6), + IEEE80211_TX_RC_SHORT_GI = BIT(7), +}; + + +/* there are 40 bytes if you don't need the rateset to be kept */ +#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40 + +/* if you do need the rateset, then you have less space */ +#define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 + +/* maximum number of rate stages */ +#define IEEE80211_TX_MAX_RATES 5 + +/** + * struct ieee80211_tx_rate - rate selection/status + * + * @idx: rate index to attempt to send with + * @flags: rate control flags (&enum mac80211_rate_control_flags) + * @count: number of tries in this rate before going to the next rate + * + * A value of -1 for @idx indicates an invalid rate and, if used + * in an array of retry rates, that no more rates should be tried. + * + * When used for transmit status reporting, the driver should + * always report the rate along with the flags it used. + * + * &struct ieee80211_tx_info contains an array of these structs + * in the control information, and it will be filled by the rate + * control algorithm according to what should be sent. For example, + * if this array contains, in the format { <idx>, <count> } the + * information + * { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 } + * then this means that the frame should be transmitted + * up to twice at rate 3, up to twice at rate 2, and up to four + * times at rate 1 if it doesn't get acknowledged. Say it gets + * acknowledged by the peer after the fifth attempt, the status + * information should then contain + * { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ... + * since it was transmitted twice at rate 3, twice at rate 2 + * and once at rate 1 after which we received an acknowledgement. + */ +struct ieee80211_tx_rate { + s8 idx; + u8 count; + u8 flags; +} __packed; + +/** + * struct ieee80211_tx_info - skb transmit information + * + * This structure is placed in skb->cb for three uses: + * (1) mac80211 TX control - mac80211 tells the driver what to do + * (2) driver internal use (if applicable) + * (3) TX status information - driver tells mac80211 what happened + * + * The TX control's sta pointer is only valid during the ->tx call, + * it may be NULL. + * + * @flags: transmit info flags, defined above + * @band: the band to transmit on (use for checking for races) + * @antenna_sel_tx: antenna to use, 0 for automatic diversity + * @pad: padding, ignore + * @control: union for control data + * @status: union for status data + * @driver_data: array of driver_data pointers + * @ampdu_ack_len: number of acked aggregated frames. + * relevant only if IEEE80211_TX_STAT_AMPDU was set. + * @ampdu_len: number of aggregated frames. + * relevant only if IEEE80211_TX_STAT_AMPDU was set. + * @ack_signal: signal strength of the ACK frame + */ +struct ieee80211_tx_info { + /* common information */ + u32 flags; + u8 band; + + u8 antenna_sel_tx; + + /* 2 byte hole */ + u8 pad[2]; + + union { + struct { + union { + /* rate control */ + struct { + struct ieee80211_tx_rate rates[ + IEEE80211_TX_MAX_RATES]; + s8 rts_cts_rate_idx; + }; + /* only needed before rate control */ + unsigned long jiffies; + }; + /* NB: vif can be NULL for injected frames */ + struct ieee80211_vif *vif; + struct ieee80211_key_conf *hw_key; + struct ieee80211_sta *sta; + } control; + struct { + struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; + u8 ampdu_ack_len; + int ack_signal; + u8 ampdu_len; + /* 15 bytes free */ + } status; + struct { + struct ieee80211_tx_rate driver_rates[ + IEEE80211_TX_MAX_RATES]; + void *rate_driver_data[ + IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; + }; + void *driver_data[ + IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)]; + }; +}; + +static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) +{ + return (struct ieee80211_tx_info *)skb->cb; +} + +static inline struct ieee80211_rx_status *IEEE80211_SKB_RXCB(struct sk_buff *skb) +{ + return (struct ieee80211_rx_status *)skb->cb; +} + +/** + * ieee80211_tx_info_clear_status - clear TX status + * + * @info: The &struct ieee80211_tx_info to be cleared. + * + * When the driver passes an skb back to mac80211, it must report + * a number of things in TX status. This function clears everything + * in the TX status but the rate control information (it does clear + * the count since you need to fill that in anyway). + * + * NOTE: You can only use this function if you do NOT use + * info->driver_data! Use info->rate_driver_data + * instead if you need only the less space that allows. + */ +static inline void +ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) +{ + int i; + + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, control.rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, driver_rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8); + /* clear the rate counts */ + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) + info->status.rates[i].count = 0; + + BUILD_BUG_ON( + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); +} + + +/** + * enum mac80211_rx_flags - receive flags + * + * These flags are used with the @flag member of &struct ieee80211_rx_status. + * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame. + * Use together with %RX_FLAG_MMIC_STRIPPED. + * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. + * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, + * verification has been done by the hardware. + * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. + * If this flag is set, the stack cannot do any replay detection + * hence the driver or hardware will have to do that. + * @RX_FLAG_FAILED_FCS_CRC: Set this flag if the FCS check failed on + * the frame. + * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on + * the frame. + * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field) + * is valid. This is useful in monitor mode and necessary for beacon frames + * to enable IBSS merging. + * @RX_FLAG_SHORTPRE: Short preamble was used for this frame + * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index + * @RX_FLAG_40MHZ: HT40 (40 MHz) was used + * @RX_FLAG_SHORT_GI: Short guard interval was used + * @RX_FLAG_INTERNAL_CMTR: set internally after frame was reported + * on cooked monitor to avoid double-reporting it for multiple + * virtual interfaces + */ +enum mac80211_rx_flags { + RX_FLAG_MMIC_ERROR = 1<<0, + RX_FLAG_DECRYPTED = 1<<1, + RX_FLAG_MMIC_STRIPPED = 1<<3, + RX_FLAG_IV_STRIPPED = 1<<4, + RX_FLAG_FAILED_FCS_CRC = 1<<5, + RX_FLAG_FAILED_PLCP_CRC = 1<<6, + RX_FLAG_TSFT = 1<<7, + RX_FLAG_SHORTPRE = 1<<8, + RX_FLAG_HT = 1<<9, + RX_FLAG_40MHZ = 1<<10, + RX_FLAG_SHORT_GI = 1<<11, + RX_FLAG_INTERNAL_CMTR = 1<<12, +}; + +/** + * struct ieee80211_rx_status - receive status + * + * The low-level driver should provide this information (the subset + * supported by hardware) to the 802.11 code with each received + * frame, in the skb's control buffer (cb). + * + * @mactime: value in microseconds of the 64-bit Time Synchronization Function + * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. + * @band: the active band when this frame was received + * @freq: frequency the radio was tuned to when receiving this frame, in MHz + * @signal: signal strength when receiving this frame, either in dBm, in dB or + * unspecified depending on the hardware capabilities flags + * @IEEE80211_HW_SIGNAL_* + * @antenna: antenna used + * @rate_idx: index of data rate into band's supported rates or MCS index if + * HT rates are use (RX_FLAG_HT) + * @flag: %RX_FLAG_* + */ +struct ieee80211_rx_status { + u64 mactime; + enum ieee80211_band band; + int freq; + int signal; + int antenna; + int rate_idx; + int flag; +}; + +/** + * enum ieee80211_conf_flags - configuration flags + * + * Flags to define PHY configuration options + * + * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this + * to determine for example whether to calculate timestamps for packets + * or not, do not use instead of filter flags! + * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only). + * This is the power save mode defined by IEEE 802.11-2007 section 11.2, + * meaning that the hardware still wakes up for beacons, is able to + * transmit frames and receive the possible acknowledgment frames. + * Not to be confused with hardware specific wakeup/sleep states, + * driver is responsible for that. See the section "Powersave support" + * for more. + * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set + * the driver should be prepared to handle configuration requests but + * may turn the device off as much as possible. Typically, this flag will + * be set when an interface is set UP but not associated or scanning, but + * it can also be unset in that case when monitor interfaces are active. + * @IEEE80211_CONF_OFFCHANNEL: The device is currently not on its main + * operating channel. + */ +enum ieee80211_conf_flags { + IEEE80211_CONF_MONITOR = (1<<0), + IEEE80211_CONF_PS = (1<<1), + IEEE80211_CONF_IDLE = (1<<2), + IEEE80211_CONF_OFFCHANNEL = (1<<3), +}; + + +/** + * enum ieee80211_conf_changed - denotes which configuration changed + * + * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed + * @IEEE80211_CONF_CHANGE_MONITOR: the monitor flag changed + * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed + * @IEEE80211_CONF_CHANGE_POWER: the TX power changed + * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed + * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed + * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed + * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed + */ +enum ieee80211_conf_changed { + IEEE80211_CONF_CHANGE_SMPS = BIT(1), + IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), + IEEE80211_CONF_CHANGE_MONITOR = BIT(3), + IEEE80211_CONF_CHANGE_PS = BIT(4), + IEEE80211_CONF_CHANGE_POWER = BIT(5), + IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), + IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), + IEEE80211_CONF_CHANGE_IDLE = BIT(8), +}; + +/** + * enum ieee80211_smps_mode - spatial multiplexing power save mode + * + * @IEEE80211_SMPS_AUTOMATIC: automatic + * @IEEE80211_SMPS_OFF: off + * @IEEE80211_SMPS_STATIC: static + * @IEEE80211_SMPS_DYNAMIC: dynamic + * @IEEE80211_SMPS_NUM_MODES: internal, don't use + */ +enum ieee80211_smps_mode { + IEEE80211_SMPS_AUTOMATIC, + IEEE80211_SMPS_OFF, + IEEE80211_SMPS_STATIC, + IEEE80211_SMPS_DYNAMIC, + + /* keep last */ + IEEE80211_SMPS_NUM_MODES, +}; + +/** + * struct ieee80211_conf - configuration of the device + * + * This struct indicates how the driver shall configure the hardware. + * + * @flags: configuration flags defined above + * + * @listen_interval: listen interval in units of beacon interval + * @max_sleep_period: the maximum number of beacon intervals to sleep for + * before checking the beacon for a TIM bit (managed mode only); this + * value will be only achievable between DTIM frames, the hardware + * needs to check for the multicast traffic bit in DTIM beacons. + * This variable is valid only when the CONF_PS flag is set. + * @ps_dtim_period: The DTIM period of the AP we're connected to, for use + * in power saving. Power saving will not be enabled until a beacon + * has been received and the DTIM period is known. + * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the + * powersave documentation below. This variable is valid only when + * the CONF_PS flag is set. + * + * @power_level: requested transmit power (in dBm) + * + * @channel: the channel to tune to + * @channel_type: the channel (HT) type + * + * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame + * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, + * but actually means the number of transmissions not the number of retries + * @short_frame_max_tx_count: Maximum number of transmissions for a "short" + * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the + * number of transmissions not the number of retries + * + * @smps_mode: spatial multiplexing powersave mode; note that + * %IEEE80211_SMPS_STATIC is used when the device is not + * configured for an HT channel + */ +struct ieee80211_conf { + u32 flags; + int power_level, dynamic_ps_timeout; + int max_sleep_period; + + u16 listen_interval; + u8 ps_dtim_period; + + u8 long_frame_max_tx_count, short_frame_max_tx_count; + + struct ieee80211_channel *channel; + enum nl80211_channel_type channel_type; + enum ieee80211_smps_mode smps_mode; +}; + +/** + * struct ieee80211_channel_switch - holds the channel switch data + * + * The information provided in this structure is required for channel switch + * operation. + * + * @timestamp: value in microseconds of the 64-bit Time Synchronization + * Function (TSF) timer when the frame containing the channel switch + * announcement was received. This is simply the rx.mactime parameter + * the driver passed into mac80211. + * @block_tx: Indicates whether transmission must be blocked before the + * scheduled channel switch, as indicated by the AP. + * @channel: the new channel to switch to + * @count: the number of TBTT's until the channel switch event + */ +struct ieee80211_channel_switch { + u64 timestamp; + bool block_tx; + struct ieee80211_channel *channel; + u8 count; +}; + +/** + * struct ieee80211_vif - per-interface data + * + * Data in this structure is continually present for driver + * use during the life of a virtual interface. + * + * @type: type of this virtual interface + * @bss_conf: BSS configuration for this interface, either our own + * or the BSS we're associated to + * @addr: address of this interface + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *). + */ +struct ieee80211_vif { + enum nl80211_iftype type; + struct ieee80211_bss_conf bss_conf; + u8 addr[ETH_ALEN]; + /* must be last */ + u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + +static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) +{ +#ifdef CONFIG_MAC80211_MESH + return vif->type == NL80211_IFTYPE_MESH_POINT; +#endif + return false; +} + +/** + * enum ieee80211_key_alg - key algorithm + * @ALG_WEP: WEP40 or WEP104 + * @ALG_TKIP: TKIP + * @ALG_CCMP: CCMP (AES) + * @ALG_AES_CMAC: AES-128-CMAC + */ +enum ieee80211_key_alg { + ALG_WEP, + ALG_TKIP, + ALG_CCMP, + ALG_AES_CMAC, +}; + +/** + * enum ieee80211_key_flags - key flags + * + * These flags are used for communication about keys between the driver + * and mac80211, with the @flags parameter of &struct ieee80211_key_conf. + * + * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates + * that the STA this key will be used with could be using QoS. + * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the + * driver to indicate that it requires IV generation for this + * particular key. + * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by + * the driver for a TKIP key if it requires Michael MIC + * generation in software. + * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates + * that the key is pairwise rather then a shared key. + * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a + * CCMP key if it requires CCMP encryption of management frames (MFP) to + * be done in software. + */ +enum ieee80211_key_flags { + IEEE80211_KEY_FLAG_WMM_STA = 1<<0, + IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, + IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, + IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, + IEEE80211_KEY_FLAG_SW_MGMT = 1<<4, +}; + +/** + * struct ieee80211_key_conf - key information + * + * This key information is given by mac80211 to the driver by + * the set_key() callback in &struct ieee80211_ops. + * + * @hw_key_idx: To be set by the driver, this is the key index the driver + * wants to be given when a frame is transmitted and needs to be + * encrypted in hardware. + * @alg: The key algorithm. + * @flags: key flags, see &enum ieee80211_key_flags. + * @keyidx: the key index (0-3) + * @keylen: key material length + * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte) + * data block: + * - Temporal Encryption Key (128 bits) + * - Temporal Authenticator Tx MIC Key (64 bits) + * - Temporal Authenticator Rx MIC Key (64 bits) + * @icv_len: The ICV length for this key type + * @iv_len: The IV length for this key type + */ +struct ieee80211_key_conf { + enum ieee80211_key_alg alg; + u8 icv_len; + u8 iv_len; + u8 hw_key_idx; + u8 flags; + s8 keyidx; + u8 keylen; + u8 key[0]; +}; + +/** + * enum set_key_cmd - key command + * + * Used with the set_key() callback in &struct ieee80211_ops, this + * indicates whether a key is being removed or added. + * + * @SET_KEY: a key is set + * @DISABLE_KEY: a key must be disabled + */ +enum set_key_cmd { + SET_KEY, DISABLE_KEY, +}; + +/** + * struct ieee80211_sta - station table entry + * + * A station table entry represents a station we are possibly + * communicating with. Since stations are RCU-managed in + * mac80211, any ieee80211_sta pointer you get access to must + * either be protected by rcu_read_lock() explicitly or implicitly, + * or you must take good care to not use such a pointer after a + * call to your sta_remove callback that removed it. + * + * @addr: MAC address + * @aid: AID we assigned to the station if we're an AP + * @supp_rates: Bitmap of supported rates (per band) + * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *), size is determined in hw information. + */ +struct ieee80211_sta { + u32 supp_rates[IEEE80211_NUM_BANDS]; + u8 addr[ETH_ALEN]; + u16 aid; + struct ieee80211_sta_ht_cap ht_cap; + + /* must be last */ + u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); +}; + +/** + * enum sta_notify_cmd - sta notify command + * + * Used with the sta_notify() callback in &struct ieee80211_ops, this + * indicates if an associated station made a power state transition. + * + * @STA_NOTIFY_SLEEP: a station is now sleeping + * @STA_NOTIFY_AWAKE: a sleeping station woke up + */ +enum sta_notify_cmd { + STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, +}; + +/** + * enum ieee80211_tkip_key_type - get tkip key + * + * Used by drivers which need to get a tkip key for skb. Some drivers need a + * phase 1 key, others need a phase 2 key. A single function allows the driver + * to get the key, this enum indicates what type of key is required. + * + * @IEEE80211_TKIP_P1_KEY: the driver needs a phase 1 key + * @IEEE80211_TKIP_P2_KEY: the driver needs a phase 2 key + */ +enum ieee80211_tkip_key_type { + IEEE80211_TKIP_P1_KEY, + IEEE80211_TKIP_P2_KEY, +}; + +/** + * enum ieee80211_hw_flags - hardware flags + * + * These flags are used to indicate hardware capabilities to + * the stack. Generally, flags here should have their meaning + * done in a way that the simplest hardware doesn't need setting + * any particular flags. There are some exceptions to this rule, + * however, so you are advised to review these flags carefully. + * + * @IEEE80211_HW_HAS_RATE_CONTROL: + * The hardware or firmware includes rate control, and cannot be + * controlled by the stack. As such, no rate control algorithm + * should be instantiated, and the TX rate reported to userspace + * will be taken from the TX status instead of the rate control + * algorithm. + * Note that this requires that the driver implement a number of + * callbacks so it has the correct information, it needs to have + * the @set_rts_threshold callback and must look at the BSS config + * @use_cts_prot for G/N protection, @use_short_slot for slot + * timing in 2.4 GHz and @use_short_preamble for preambles for + * CCK frames. + * + * @IEEE80211_HW_RX_INCLUDES_FCS: + * Indicates that received frames passed to the stack include + * the FCS at the end. + * + * @IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING: + * Some wireless LAN chipsets buffer broadcast/multicast frames + * for power saving stations in the hardware/firmware and others + * rely on the host system for such buffering. This option is used + * to configure the IEEE 802.11 upper layer to buffer broadcast and + * multicast frames when there are power saving stations so that + * the driver can fetch them with ieee80211_get_buffered_bc(). + * + * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE: + * Hardware is not capable of short slot operation on the 2.4 GHz band. + * + * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: + * Hardware is not capable of receiving frames with short preamble on + * the 2.4 GHz band. + * + * @IEEE80211_HW_SIGNAL_UNSPEC: + * Hardware can provide signal values but we don't know its units. We + * expect values between 0 and @max_signal. + * If possible please provide dB or dBm instead. + * + * @IEEE80211_HW_SIGNAL_DBM: + * Hardware gives signal values in dBm, decibel difference from + * one milliwatt. This is the preferred method since it is standardized + * between different devices. @max_signal does not need to be set. + * + * @IEEE80211_HW_SPECTRUM_MGMT: + * Hardware supports spectrum management defined in 802.11h + * Measurement, Channel Switch, Quieting, TPC + * + * @IEEE80211_HW_AMPDU_AGGREGATION: + * Hardware supports 11n A-MPDU aggregation. + * + * @IEEE80211_HW_SUPPORTS_PS: + * Hardware has power save support (i.e. can go to sleep). + * + * @IEEE80211_HW_PS_NULLFUNC_STACK: + * Hardware requires nullfunc frame handling in stack, implies + * stack support for dynamic PS. + * + * @IEEE80211_HW_SUPPORTS_DYNAMIC_PS: + * Hardware has support for dynamic PS. + * + * @IEEE80211_HW_MFP_CAPABLE: + * Hardware supports management frame protection (MFP, IEEE 802.11w). + * + * @IEEE80211_HW_BEACON_FILTER: + * Hardware supports dropping of irrelevant beacon frames to + * avoid waking up cpu. + * + * @IEEE80211_HW_SUPPORTS_STATIC_SMPS: + * Hardware supports static spatial multiplexing powersave, + * ie. can turn off all but one chain even on HT connections + * that should be using more chains. + * + * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS: + * Hardware supports dynamic spatial multiplexing powersave, + * ie. can turn off all but one chain and then wake the rest + * up as required after, for example, rts/cts handshake. + * + * @IEEE80211_HW_SUPPORTS_UAPSD: + * Hardware supports Unscheduled Automatic Power Save Delivery + * (U-APSD) in managed mode. The mode is configured with + * conf_tx() operation. + * + * @IEEE80211_HW_REPORTS_TX_ACK_STATUS: + * Hardware can provide ack status reports of Tx frames to + * the stack. + * + * @IEEE80211_HW_CONNECTION_MONITOR: + * The hardware performs its own connection monitoring, including + * periodic keep-alives to the AP and probing the AP on beacon loss. + * When this flag is set, signaling beacon-loss will cause an immediate + * change to disassociated state. + * + * @IEEE80211_HW_SUPPORTS_CQM_RSSI: + * Hardware can do connection quality monitoring - i.e. it can monitor + * connection quality related parameters, such as the RSSI level and + * provide notifications if configured trigger levels are reached. + * + * @IEEE80211_HW_NEED_DTIM_PERIOD: + * This device needs to know the DTIM period for the BSS before + * associating. + */ +enum ieee80211_hw_flags { + IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, + IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, + IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, + IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, + IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, + IEEE80211_HW_SIGNAL_DBM = 1<<6, + IEEE80211_HW_NEED_DTIM_PERIOD = 1<<7, + IEEE80211_HW_SPECTRUM_MGMT = 1<<8, + IEEE80211_HW_AMPDU_AGGREGATION = 1<<9, + IEEE80211_HW_SUPPORTS_PS = 1<<10, + IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11, + IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, + IEEE80211_HW_MFP_CAPABLE = 1<<13, + IEEE80211_HW_BEACON_FILTER = 1<<14, + IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, + IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, + IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, + IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, + IEEE80211_HW_CONNECTION_MONITOR = 1<<19, + IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20, +}; + +/** + * struct ieee80211_hw - hardware information and state + * + * This structure contains the configuration and hardware + * information for an 802.11 PHY. + * + * @wiphy: This points to the &struct wiphy allocated for this + * 802.11 PHY. You must fill in the @perm_addr and @dev + * members of this structure using SET_IEEE80211_DEV() + * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported + * bands (with channels, bitrates) are registered here. + * + * @conf: &struct ieee80211_conf, device configuration, don't use. + * + * @priv: pointer to private area that was allocated for driver use + * along with this structure. + * + * @flags: hardware flags, see &enum ieee80211_hw_flags. + * + * @extra_tx_headroom: headroom to reserve in each transmit skb + * for use by the driver (e.g. for transmit headers.) + * + * @channel_change_time: time (in microseconds) it takes to change channels. + * + * @max_signal: Maximum value for signal (rssi) in RX information, used + * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB + * + * @max_listen_interval: max listen interval in units of beacon interval + * that HW supports + * + * @queues: number of available hardware transmit queues for + * data packets. WMM/QoS requires at least four, these + * queues need to have configurable access parameters. + * + * @rate_control_algorithm: rate control algorithm for this hardware. + * If unset (NULL), the default algorithm will be used. Must be + * set before calling ieee80211_register_hw(). + * + * @vif_data_size: size (in bytes) of the drv_priv data area + * within &struct ieee80211_vif. + * @sta_data_size: size (in bytes) of the drv_priv data area + * within &struct ieee80211_sta. + * + * @max_rates: maximum number of alternate rate retry stages + * @max_rate_tries: maximum number of tries for each stage + */ +struct ieee80211_hw { + struct ieee80211_conf conf; + struct wiphy *wiphy; + const char *rate_control_algorithm; + void *priv; + u32 flags; + unsigned int extra_tx_headroom; + int channel_change_time; + int vif_data_size; + int sta_data_size; + u16 queues; + u16 max_listen_interval; + s8 max_signal; + u8 max_rates; + u8 max_rate_tries; +}; + +/** + * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy + * + * @wiphy: the &struct wiphy which we want to query + * + * mac80211 drivers can use this to get to their respective + * &struct ieee80211_hw. Drivers wishing to get to their own private + * structure can then access it via hw->priv. Note that mac802111 drivers should + * not use wiphy_priv() to try to get their private driver structure as this + * is already used internally by mac80211. + */ +struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy); + +/** + * SET_IEEE80211_DEV - set device for 802.11 hardware + * + * @hw: the &struct ieee80211_hw to set the device for + * @dev: the &struct device of this 802.11 device + */ +static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev) +{ + set_wiphy_dev(hw->wiphy, dev); +} + +/** + * SET_IEEE80211_PERM_ADDR - set the permanent MAC address for 802.11 hardware + * + * @hw: the &struct ieee80211_hw to set the MAC address for + * @addr: the address to set + */ +static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) +{ + memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); +} + +static inline struct ieee80211_rate * +ieee80211_get_tx_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c) +{ + if (WARN_ON(c->control.rates[0].idx < 0)) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c) +{ + if (c->control.rts_cts_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_info *c, int idx) +{ + if (c->control.rates[idx + 1].idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx]; +} + +/** + * DOC: Hardware crypto acceleration + * + * mac80211 is capable of taking advantage of many hardware + * acceleration designs for encryption and decryption operations. + * + * The set_key() callback in the &struct ieee80211_ops for a given + * device is called to enable hardware acceleration of encryption and + * decryption. The callback takes a @sta parameter that will be NULL + * for default keys or keys used for transmission only, or point to + * the station information for the peer for individual keys. + * Multiple transmission keys with the same key index may be used when + * VLANs are configured for an access point. + * + * When transmitting, the TX control data will use the @hw_key_idx + * selected by the driver by modifying the &struct ieee80211_key_conf + * pointed to by the @key parameter to the set_key() function. + * + * The set_key() call for the %SET_KEY command should return 0 if + * the key is now in use, -%EOPNOTSUPP or -%ENOSPC if it couldn't be + * added; if you return 0 then hw_key_idx must be assigned to the + * hardware key index, you are free to use the full u8 range. + * + * When the cmd is %DISABLE_KEY then it must succeed. + * + * Note that it is permissible to not decrypt a frame even if a key + * for it has been uploaded to hardware, the stack will not make any + * decision based on whether a key has been uploaded or not but rather + * based on the receive flags. + * + * The &struct ieee80211_key_conf structure pointed to by the @key + * parameter is guaranteed to be valid until another call to set_key() + * removes it, but it can only be used as a cookie to differentiate + * keys. + * + * In TKIP some HW need to be provided a phase 1 key, for RX decryption + * acceleration (i.e. iwlwifi). Those drivers should provide update_tkip_key + * handler. + * The update_tkip_key() call updates the driver with the new phase 1 key. + * This happens everytime the iv16 wraps around (every 65536 packets). The + * set_key() call will happen only once for each key (unless the AP did + * rekeying), it will not include a valid phase 1 key. The valid phase 1 key is + * provided by update_tkip_key only. The trigger that makes mac80211 call this + * handler is software decryption with wrap around of iv16. + */ + +/** + * DOC: Powersave support + * + * mac80211 has support for various powersave implementations. + * + * First, it can support hardware that handles all powersaving by itself, + * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware + * flag. In that case, it will be told about the desired powersave mode + * with the %IEEE80211_CONF_PS flag depending on the association status. + * The hardware must take care of sending nullfunc frames when necessary, + * i.e. when entering and leaving powersave mode. The hardware is required + * to look at the AID in beacons and signal to the AP that it woke up when + * it finds traffic directed to it. + * + * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in + * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused + * with hardware wakeup and sleep states. Driver is responsible for waking + * up the hardware before issueing commands to the hardware and putting it + * back to sleep at approriate times. + * + * When PS is enabled, hardware needs to wakeup for beacons and receive the + * buffered multicast/broadcast frames after the beacon. Also it must be + * possible to send frames and receive the acknowledment frame. + * + * Other hardware designs cannot send nullfunc frames by themselves and also + * need software support for parsing the TIM bitmap. This is also supported + * by mac80211 by combining the %IEEE80211_HW_SUPPORTS_PS and + * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still + * required to pass up beacons. The hardware is still required to handle + * waking up for multicast traffic; if it cannot the driver must handle that + * as best as it can, mac80211 is too slow to do that. + * + * Dynamic powersave is an extension to normal powersave in which the + * hardware stays awake for a user-specified period of time after sending a + * frame so that reply frames need not be buffered and therefore delayed to + * the next wakeup. It's compromise of getting good enough latency when + * there's data traffic and still saving significantly power in idle + * periods. + * + * Dynamic powersave is supported by simply mac80211 enabling and disabling + * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS + * flag and mac80211 will handle everything automatically. Additionally, + * hardware having support for the dynamic PS feature may set the + * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support + * dynamic PS mode itself. The driver needs to look at the + * @dynamic_ps_timeout hardware configuration value and use it that value + * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable + * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS + * enabled whenever user has enabled powersave. + * + * Some hardware need to toggle a single shared antenna between WLAN and + * Bluetooth to facilitate co-existence. These types of hardware set + * limitations on the use of host controlled dynamic powersave whenever there + * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the + * driver may request temporarily going into full power save, in order to + * enable toggling the antenna between BT and WLAN. If the driver requests + * disabling dynamic powersave, the @dynamic_ps_timeout value will be + * temporarily set to zero until the driver re-enables dynamic powersave. + * + * Driver informs U-APSD client support by enabling + * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the + * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS + * Nullfunc frames and stay awake until the service period has ended. To + * utilize U-APSD, dynamic powersave is disabled for voip AC and all frames + * from that AC are transmitted with powersave enabled. + * + * Note: U-APSD client mode is not yet supported with + * %IEEE80211_HW_PS_NULLFUNC_STACK. + */ + +/** + * DOC: Beacon filter support + * + * Some hardware have beacon filter support to reduce host cpu wakeups + * which will reduce system power consumption. It usuallly works so that + * the firmware creates a checksum of the beacon but omits all constantly + * changing elements (TSF, TIM etc). Whenever the checksum changes the + * beacon is forwarded to the host, otherwise it will be just dropped. That + * way the host will only receive beacons where some relevant information + * (for example ERP protection or WMM settings) have changed. + * + * Beacon filter support is advertised with the %IEEE80211_HW_BEACON_FILTER + * hardware capability. The driver needs to enable beacon filter support + * whenever power save is enabled, that is %IEEE80211_CONF_PS is set. When + * power save is enabled, the stack will not check for beacon loss and the + * driver needs to notify about loss of beacons with ieee80211_beacon_loss(). + * + * The time (or number of beacons missed) until the firmware notifies the + * driver of a beacon loss event (which in turn causes the driver to call + * ieee80211_beacon_loss()) should be configurable and will be controlled + * by mac80211 and the roaming algorithm in the future. + * + * Since there may be constantly changing information elements that nothing + * in the software stack cares about, we will, in the future, have mac80211 + * tell the driver which information elements are interesting in the sense + * that we want to see changes in them. This will include + * - a list of information element IDs + * - a list of OUIs for the vendor information element + * + * Ideally, the hardware would filter out any beacons without changes in the + * requested elements, but if it cannot support that it may, at the expense + * of some efficiency, filter out only a subset. For example, if the device + * doesn't support checking for OUIs it should pass up all changes in all + * vendor information elements. + * + * Note that change, for the sake of simplification, also includes information + * elements appearing or disappearing from the beacon. + * + * Some hardware supports an "ignore list" instead, just make sure nothing + * that was requested is on the ignore list, and include commonly changing + * information element IDs in the ignore list, for example 11 (BSS load) and + * the various vendor-assigned IEs with unknown contents (128, 129, 133-136, + * 149, 150, 155, 156, 173, 176, 178, 179, 219); for forward compatibility + * it could also include some currently unused IDs. + * + * + * In addition to these capabilities, hardware should support notifying the + * host of changes in the beacon RSSI. This is relevant to implement roaming + * when no traffic is flowing (when traffic is flowing we see the RSSI of + * the received data packets). This can consist in notifying the host when + * the RSSI changes significantly or when it drops below or rises above + * configurable thresholds. In the future these thresholds will also be + * configured by mac80211 (which gets them from userspace) to implement + * them as the roaming algorithm requires. + * + * If the hardware cannot implement this, the driver should ask it to + * periodically pass beacon frames to the host so that software can do the + * signal strength threshold checking. + */ + +/** + * DOC: Spatial multiplexing power save + * + * SMPS (Spatial multiplexing power save) is a mechanism to conserve + * power in an 802.11n implementation. For details on the mechanism + * and rationale, please refer to 802.11 (as amended by 802.11n-2009) + * "11.2.3 SM power save". + * + * The mac80211 implementation is capable of sending action frames + * to update the AP about the station's SMPS mode, and will instruct + * the driver to enter the specific mode. It will also announce the + * requested SMPS mode during the association handshake. Hardware + * support for this feature is required, and can be indicated by + * hardware flags. + * + * The default mode will be "automatic", which nl80211/cfg80211 + * defines to be dynamic SMPS in (regular) powersave, and SMPS + * turned off otherwise. + * + * To support this feature, the driver must set the appropriate + * hardware support flags, and handle the SMPS flag to the config() + * operation. It will then with this mechanism be instructed to + * enter the requested SMPS mode while associated to an HT AP. + */ + +/** + * DOC: Frame filtering + * + * mac80211 requires to see many management frames for proper + * operation, and users may want to see many more frames when + * in monitor mode. However, for best CPU usage and power consumption, + * having as few frames as possible percolate through the stack is + * desirable. Hence, the hardware should filter as much as possible. + * + * To achieve this, mac80211 uses filter flags (see below) to tell + * the driver's configure_filter() function which frames should be + * passed to mac80211 and which should be filtered out. + * + * Before configure_filter() is invoked, the prepare_multicast() + * callback is invoked with the parameters @mc_count and @mc_list + * for the combined multicast address list of all virtual interfaces. + * It's use is optional, and it returns a u64 that is passed to + * configure_filter(). Additionally, configure_filter() has the + * arguments @changed_flags telling which flags were changed and + * @total_flags with the new flag states. + * + * If your device has no multicast address filters your driver will + * need to check both the %FIF_ALLMULTI flag and the @mc_count + * parameter to see whether multicast frames should be accepted + * or dropped. + * + * All unsupported flags in @total_flags must be cleared. + * Hardware does not support a flag if it is incapable of _passing_ + * the frame to the stack. Otherwise the driver must ignore + * the flag, but not clear it. + * You must _only_ clear the flag (announce no support for the + * flag to mac80211) if you are not able to pass the packet type + * to the stack (so the hardware always filters it). + * So for example, you should clear @FIF_CONTROL, if your hardware + * always filters control frames. If your hardware always passes + * control frames to the kernel and is incapable of filtering them, + * you do _not_ clear the @FIF_CONTROL flag. + * This rule applies to all other FIF flags as well. + */ + +/** + * enum ieee80211_filter_flags - hardware filter flags + * + * These flags determine what the filter in hardware should be + * programmed to let through and what should not be passed to the + * stack. It is always safe to pass more frames than requested, + * but this has negative impact on power consumption. + * + * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS, + * think of the BSS as your network segment and then this corresponds + * to the regular ethernet device promiscuous mode. + * + * @FIF_ALLMULTI: pass all multicast frames, this is used if requested + * by the user or if the hardware is not capable of filtering by + * multicast address. + * + * @FIF_FCSFAIL: pass frames with failed FCS (but you need to set the + * %RX_FLAG_FAILED_FCS_CRC for them) + * + * @FIF_PLCPFAIL: pass frames with failed PLCP CRC (but you need to set + * the %RX_FLAG_FAILED_PLCP_CRC for them + * + * @FIF_BCN_PRBRESP_PROMISC: This flag is set during scanning to indicate + * to the hardware that it should not filter beacons or probe responses + * by BSSID. Filtering them can greatly reduce the amount of processing + * mac80211 needs to do and the amount of CPU wakeups, so you should + * honour this flag if possible. + * + * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS + * is not set then only those addressed to this station. + * + * @FIF_OTHER_BSS: pass frames destined to other BSSes + * + * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only + * those addressed to this station. + */ +enum ieee80211_filter_flags { + FIF_PROMISC_IN_BSS = 1<<0, + FIF_ALLMULTI = 1<<1, + FIF_FCSFAIL = 1<<2, + FIF_PLCPFAIL = 1<<3, + FIF_BCN_PRBRESP_PROMISC = 1<<4, + FIF_CONTROL = 1<<5, + FIF_OTHER_BSS = 1<<6, + FIF_PSPOLL = 1<<7, +}; + +/** + * enum ieee80211_ampdu_mlme_action - A-MPDU actions + * + * These flags are used with the ampdu_action() callback in + * &struct ieee80211_ops to indicate which action is needed. + * + * Note that drivers MUST be able to deal with a TX aggregation + * session being stopped even before they OK'ed starting it by + * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer + * might receive the addBA frame and send a delBA right away! + * + * @IEEE80211_AMPDU_RX_START: start Rx aggregation + * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation + * @IEEE80211_AMPDU_TX_START: start Tx aggregation + * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation + * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational + */ +enum ieee80211_ampdu_mlme_action { + IEEE80211_AMPDU_RX_START, + IEEE80211_AMPDU_RX_STOP, + IEEE80211_AMPDU_TX_START, + IEEE80211_AMPDU_TX_STOP, + IEEE80211_AMPDU_TX_OPERATIONAL, +}; + +/** + * struct ieee80211_ops - callbacks from mac80211 to the driver + * + * This structure contains various callbacks that the driver may + * handle or, in some cases, must handle, for example to configure + * the hardware to a new channel or to transmit a frame. + * + * @tx: Handler that 802.11 module calls for each transmitted frame. + * skb contains the buffer starting from the IEEE 802.11 header. + * The low-level driver should send the frame out based on + * configuration in the TX control data. This handler should, + * preferably, never fail and stop queues appropriately, more + * importantly, however, it must never fail for A-MPDU-queues. + * This function should return NETDEV_TX_OK except in very + * limited cases. + * Must be implemented and atomic. + * + * @start: Called before the first netdevice attached to the hardware + * is enabled. This should turn on the hardware and must turn on + * frame reception (for possibly enabled monitor interfaces.) + * Returns negative error codes, these may be seen in userspace, + * or zero. + * When the device is started it should not have a MAC address + * to avoid acknowledging frames before a non-monitor device + * is added. + * Must be implemented and can sleep. + * + * @stop: Called after last netdevice attached to the hardware + * is disabled. This should turn off the hardware (at least + * it must turn off frame reception.) + * May be called right after add_interface if that rejects + * an interface. If you added any work onto the mac80211 workqueue + * you should ensure to cancel it on this callback. + * Must be implemented and can sleep. + * + * @add_interface: Called when a netdevice attached to the hardware is + * enabled. Because it is not called for monitor mode devices, @start + * and @stop must be implemented. + * The driver should perform any initialization it needs before + * the device can be enabled. The initial configuration for the + * interface is given in the conf parameter. + * The callback may refuse to add an interface by returning a + * negative error code (which will be seen in userspace.) + * Must be implemented and can sleep. + * + * @remove_interface: Notifies a driver that an interface is going down. + * The @stop callback is called after this if it is the last interface + * and no monitor interfaces are present. + * When all interfaces are removed, the MAC address in the hardware + * must be cleared so the device no longer acknowledges packets, + * the mac_addr member of the conf structure is, however, set to the + * MAC address of the device going away. + * Hence, this callback must be implemented. It can sleep. + * + * @config: Handler for configuration requests. IEEE 802.11 code calls this + * function to change hardware configuration, e.g., channel. + * This function should never fail but returns a negative error code + * if it does. The callback can sleep. + * + * @bss_info_changed: Handler for configuration requests related to BSS + * parameters that may vary during BSS's lifespan, and may affect low + * level driver (e.g. assoc/disassoc status, erp parameters). + * This function should not be used if no BSS has been set, unless + * for association indication. The @changed parameter indicates which + * of the bss parameters has changed when a call is made. The callback + * can sleep. + * + * @prepare_multicast: Prepare for multicast filter configuration. + * This callback is optional, and its return value is passed + * to configure_filter(). This callback must be atomic. + * + * @configure_filter: Configure the device's RX filter. + * See the section "Frame filtering" for more information. + * This callback must be implemented and can sleep. + * + * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit + * must be set or cleared for a given STA. Must be atomic. + * + * @set_key: See the section "Hardware crypto acceleration" + * This callback is only called between add_interface and + * remove_interface calls, i.e. while the given virtual interface + * is enabled. + * Returns a negative error code if the key can't be added. + * The callback can sleep. + * + * @update_tkip_key: See the section "Hardware crypto acceleration" + * This callback will be called in the context of Rx. Called for drivers + * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. + * The callback must be atomic. + * + * @hw_scan: Ask the hardware to service the scan request, no need to start + * the scan state machine in stack. The scan must honour the channel + * configuration done by the regulatory agent in the wiphy's + * registered bands. The hardware (or the driver) needs to make sure + * that power save is disabled. + * The @req ie/ie_len members are rewritten by mac80211 to contain the + * entire IEs after the SSID, so that drivers need not look at these + * at all but just send them after the SSID -- mac80211 includes the + * (extended) supported rates and HT information (where applicable). + * When the scan finishes, ieee80211_scan_completed() must be called; + * note that it also must be called when the scan cannot finish due to + * any error unless this callback returned a negative error code. + * The callback can sleep. + * + * @sw_scan_start: Notifier function that is called just before a software scan + * is started. Can be NULL, if the driver doesn't need this notification. + * The callback can sleep. + * + * @sw_scan_complete: Notifier function that is called just after a + * software scan finished. Can be NULL, if the driver doesn't need + * this notification. + * The callback can sleep. + * + * @get_stats: Return low-level statistics. + * Returns zero if statistics are available. + * The callback can sleep. + * + * @get_tkip_seq: If your device implements TKIP encryption in hardware this + * callback should be provided to read the TKIP transmit IVs (both IV32 + * and IV16) for the given key from hardware. + * The callback must be atomic. + * + * @set_rts_threshold: Configuration of RTS threshold (if device needs it) + * The callback can sleep. + * + * @sta_add: Notifies low level driver about addition of an associated station, + * AP, IBSS/WDS/mesh peer etc. This callback can sleep. + * + * @sta_remove: Notifies low level driver about removal of an associated + * station, AP, IBSS/WDS/mesh peer etc. This callback can sleep. + * + * @sta_notify: Notifies low level driver about power state transition of an + * associated station, AP, IBSS/WDS/mesh peer etc. Must be atomic. + * + * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), + * bursting) for a hardware TX queue. + * Returns a negative error code on failure. + * The callback can sleep. + * + * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, + * this is only used for IBSS mode BSSID merging and debugging. Is not a + * required function. + * The callback can sleep. + * + * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware. + * Currently, this is only used for IBSS mode debugging. Is not a + * required function. + * The callback can sleep. + * + * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize + * with other STAs in the IBSS. This is only used in IBSS mode. This + * function is optional if the firmware/hardware takes full care of + * TSF synchronization. + * The callback can sleep. + * + * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. + * This is needed only for IBSS mode and the result of this function is + * used to determine whether to reply to Probe Requests. + * Returns non-zero if this device sent the last beacon. + * The callback can sleep. + * + * @ampdu_action: Perform a certain A-MPDU action + * The RA/TID combination determines the destination and TID we want + * the ampdu action to be performed for. The action is defined through + * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) + * is the first frame we expect to perform the action on. Notice + * that TX/RX_STOP can pass NULL for this parameter. + * Returns a negative error code on failure. + * The callback can sleep. + * + * @get_survey: Return per-channel survey information + * + * @rfkill_poll: Poll rfkill hardware state. If you need this, you also + * need to set wiphy->rfkill_poll to %true before registration, + * and need to call wiphy_rfkill_set_hw_state() in the callback. + * The callback can sleep. + * + * @set_coverage_class: Set slot time for given coverage class as specified + * in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout + * accordingly. This callback is not required and may sleep. + * + * @testmode_cmd: Implement a cfg80211 test mode command. + * The callback can sleep. + * + * @flush: Flush all pending frames from the hardware queue, making sure + * that the hardware queues are empty. If the parameter @drop is set + * to %true, pending frames may be dropped. The callback can sleep. + * + * @channel_switch: Drivers that need (or want) to offload the channel + * switch operation for CSAs received from the AP may implement this + * callback. They must then call ieee80211_chswitch_done() to indicate + * completion of the channel switch. + */ +struct ieee80211_ops { + int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); + int (*start)(struct ieee80211_hw *hw); + void (*stop)(struct ieee80211_hw *hw); + int (*add_interface)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + void (*remove_interface)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + int (*config)(struct ieee80211_hw *hw, u32 changed); + void (*bss_info_changed)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed); + u64 (*prepare_multicast)(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list); + void (*configure_filter)(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast); + int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set); + int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); + void (*update_tkip_key)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *conf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key); + int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_scan_request *req); + void (*sw_scan_start)(struct ieee80211_hw *hw); + void (*sw_scan_complete)(struct ieee80211_hw *hw); + int (*get_stats)(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats); + void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, + u32 *iv32, u16 *iv16); + int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); + int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd, struct ieee80211_sta *sta); + int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params); + u64 (*get_tsf)(struct ieee80211_hw *hw); + void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf); + void (*reset_tsf)(struct ieee80211_hw *hw); + int (*tx_last_beacon)(struct ieee80211_hw *hw); + int (*ampdu_action)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn); + int (*get_survey)(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); + void (*rfkill_poll)(struct ieee80211_hw *hw); + void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); +#ifdef CONFIG_NL80211_TESTMODE + int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); +#endif + void (*flush)(struct ieee80211_hw *hw, bool drop); + void (*channel_switch)(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch); +}; + +/** + * ieee80211_alloc_hw - Allocate a new hardware device + * + * This must be called once for each hardware device. The returned pointer + * must be used to refer to this device when calling other functions. + * mac80211 allocates a private data area for the driver pointed to by + * @priv in &struct ieee80211_hw, the size of this area is given as + * @priv_data_len. + * + * @priv_data_len: length of private data + * @ops: callbacks for this device + */ +struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, + const struct ieee80211_ops *ops); + +/** + * ieee80211_register_hw - Register hardware device + * + * You must call this function before any other functions in + * mac80211. Note that before a hardware can be registered, you + * need to fill the contained wiphy's information. + * + * @hw: the device to register as returned by ieee80211_alloc_hw() + */ +int ieee80211_register_hw(struct ieee80211_hw *hw); + +#ifdef CONFIG_MAC80211_LEDS +extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); +extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); +#endif +/** + * ieee80211_get_tx_led_name - get name of TX LED + * + * mac80211 creates a transmit LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_tx_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_get_rx_led_name - get name of RX LED + * + * mac80211 creates a receive LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_rx_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_get_assoc_led_name - get name of association LED + * + * mac80211 creates a association LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_assoc_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_get_radio_led_name - get name of radio LED + * + * mac80211 creates a radio change LED trigger for each wireless hardware + * that can be used to drive LEDs if your driver registers a LED device. + * This function returns the name (or %NULL if not configured for LEDs) + * of the trigger so you can automatically link the LED device. + * + * @hw: the hardware to get the LED trigger name for + */ +static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) +{ +#ifdef CONFIG_MAC80211_LEDS + return __ieee80211_get_radio_led_name(hw); +#else + return NULL; +#endif +} + +/** + * ieee80211_unregister_hw - Unregister a hardware device + * + * This function instructs mac80211 to free allocated resources + * and unregister netdevices from the networking subsystem. + * + * @hw: the hardware to unregister + */ +void ieee80211_unregister_hw(struct ieee80211_hw *hw); + +/** + * ieee80211_free_hw - free hardware descriptor + * + * This function frees everything that was allocated, including the + * private data for the driver. You must call ieee80211_unregister_hw() + * before calling this function. + * + * @hw: the hardware to free + */ +void ieee80211_free_hw(struct ieee80211_hw *hw); + +/** + * ieee80211_restart_hw - restart hardware completely + * + * Call this function when the hardware was restarted for some reason + * (hardware error, ...) and the driver is unable to restore its state + * by itself. mac80211 assumes that at this point the driver/hardware + * is completely uninitialised and stopped, it starts the process by + * calling the ->start() operation. The driver will need to reset all + * internal state that it has prior to calling this function. + * + * @hw: the hardware to restart + */ +void ieee80211_restart_hw(struct ieee80211_hw *hw); + +/** + * ieee80211_rx - receive frame + * + * Use this function to hand received frames to mac80211. The receive + * buffer in @skb must start with an IEEE 802.11 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee80211 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls to + * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be + * mixed for a single hardware. + * + * In process context use instead ieee80211_rx_ni(). + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + */ +void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); + +/** + * ieee80211_rx_irqsafe - receive frame + * + * Like ieee80211_rx() but can be called in IRQ context + * (internally defers to a tasklet.) + * + * Calls to this function, ieee80211_rx() or ieee80211_rx_ni() may not + * be mixed for a single hardware. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + */ +void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); + +/** + * ieee80211_rx_ni - receive frame (in process context) + * + * Like ieee80211_rx() but can be called in process context + * (internally disables bottom halves). + * + * Calls to this function, ieee80211_rx() and ieee80211_rx_irqsafe() may + * not be mixed for a single hardware. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + */ +static inline void ieee80211_rx_ni(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + local_bh_disable(); + ieee80211_rx(hw, skb); + local_bh_enable(); +} + +/* + * The TX headroom reserved by mac80211 for its own tx_status functions. + * This is enough for the radiotap header. + */ +#define IEEE80211_TX_STATUS_HEADROOM 13 + +/** + * ieee80211_tx_status - transmit status callback + * + * Call this function for all transmitted frames after they have been + * transmitted. It is permissible to not call this function for + * multicast frames but this can affect statistics. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls + * to this function and ieee80211_tx_status_irqsafe() may not be mixed + * for a single hardware. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + */ +void ieee80211_tx_status(struct ieee80211_hw *hw, + struct sk_buff *skb); + +/** + * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback + * + * Like ieee80211_tx_status() but can be called in IRQ context + * (internally defers to a tasklet.) + * + * Calls to this function and ieee80211_tx_status() may not be mixed for a + * single hardware. + * + * @hw: the hardware the frame was transmitted by + * @skb: the frame that was transmitted, owned by mac80211 after this call + */ +void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, + struct sk_buff *skb); + +/** + * ieee80211_beacon_get_tim - beacon generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @tim_offset: pointer to variable that will receive the TIM IE offset. + * Set to 0 if invalid (in non-AP modes). + * @tim_length: pointer to variable that will receive the TIM IE length, + * (including the ID and length bytes!). + * Set to 0 if invalid (in non-AP modes). + * + * If the driver implements beaconing modes, it must use this function to + * obtain the beacon frame/template. + * + * If the beacon frames are generated by the host system (i.e., not in + * hardware/firmware), the driver uses this function to get each beacon + * frame from mac80211 -- it is responsible for calling this function + * before the beacon is needed (e.g. based on hardware interrupt). + * + * If the beacon frames are generated by the device, then the driver + * must use the returned beacon as the template and change the TIM IE + * according to the current DTIM parameters/TIM bitmap. + * + * The driver is responsible for freeing the returned skb. + */ +struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 *tim_offset, u16 *tim_length); + +/** + * ieee80211_beacon_get - beacon generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * See ieee80211_beacon_get_tim(). + */ +static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); +} + +/** + * ieee80211_pspoll_get - retrieve a PS Poll template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a PS Poll a template which can, for example, uploaded to + * hardware. The template must be updated after association so that correct + * AID, BSSID and MAC address is used. + * + * Note: Caller (or hardware) is responsible for setting the + * &IEEE80211_FCTL_PM bit. + */ +struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** + * ieee80211_nullfunc_get - retrieve a nullfunc template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Creates a Nullfunc template which can, for example, uploaded to + * hardware. The template must be updated after association so that correct + * BSSID and address is used. + * + * Note: Caller (or hardware) is responsible for setting the + * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields. + */ +struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + +/** + * ieee80211_probereq_get - retrieve a Probe Request template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @ssid: SSID buffer + * @ssid_len: length of SSID + * @ie: buffer containing all IEs except SSID for the template + * @ie_len: length of the IE buffer + * + * Creates a Probe Request template which can, for example, be uploaded to + * hardware. + */ +struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len); + +/** + * ieee80211_rts_get - RTS frame generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame: pointer to the frame that is going to be protected by the RTS. + * @frame_len: the frame length (in octets). + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * @rts: The buffer where to store the RTS frame. + * + * If the RTS frames are generated by the host system (i.e., not in + * hardware/firmware), the low-level driver uses this function to receive + * the next RTS frame from the 802.11 code. The low-level is responsible + * for calling this function before and RTS frame is needed. + */ +void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const void *frame, size_t frame_len, + const struct ieee80211_tx_info *frame_txctl, + struct ieee80211_rts *rts); + +/** + * ieee80211_rts_duration - Get the duration field for an RTS frame + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame_len: the length of the frame that is going to be protected by the RTS. + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * + * If the RTS is generated in firmware, but the host system must provide + * the duration field, the low-level driver uses this function to receive + * the duration field value in little-endian byteorder. + */ +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, size_t frame_len, + const struct ieee80211_tx_info *frame_txctl); + +/** + * ieee80211_ctstoself_get - CTS-to-self frame generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame: pointer to the frame that is going to be protected by the CTS-to-self. + * @frame_len: the frame length (in octets). + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * @cts: The buffer where to store the CTS-to-self frame. + * + * If the CTS-to-self frames are generated by the host system (i.e., not in + * hardware/firmware), the low-level driver uses this function to receive + * the next CTS-to-self frame from the 802.11 code. The low-level is responsible + * for calling this function before and CTS-to-self frame is needed. + */ +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const void *frame, size_t frame_len, + const struct ieee80211_tx_info *frame_txctl, + struct ieee80211_cts *cts); + +/** + * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. + * @frame_txctl: &struct ieee80211_tx_info of the frame. + * + * If the CTS-to-self is generated in firmware, but the host system must provide + * the duration field, the low-level driver uses this function to receive + * the duration field value in little-endian byteorder. + */ +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + size_t frame_len, + const struct ieee80211_tx_info *frame_txctl); + +/** + * ieee80211_generic_frame_duration - Calculate the duration field for a frame + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @frame_len: the length of the frame. + * @rate: the rate at which the frame is going to be transmitted. + * + * Calculate the duration field of some generic frame, given its + * length and transmission rate (in 100kbps). + */ +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + size_t frame_len, + struct ieee80211_rate *rate); + +/** + * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Function for accessing buffered broadcast and multicast frames. If + * hardware/firmware does not implement buffering of broadcast/multicast + * frames when power saving is used, 802.11 code buffers them in the host + * memory. The low-level driver uses this function to fetch next buffered + * frame. In most cases, this is used when generating beacon frame. This + * function returns a pointer to the next buffered skb or NULL if no more + * buffered frames are available. + * + * Note: buffered frames are returned only after DTIM beacon frame was + * generated with ieee80211_beacon_get() and the low-level driver must thus + * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns + * NULL if the previous generated beacon was not DTIM, so the low-level driver + * does not need to check for DTIM beacons separately and should be able to + * use common code for all beacons. + */ +struct sk_buff * +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + +/** + * ieee80211_get_tkip_key - get a TKIP rc4 for skb + * + * This function computes a TKIP rc4 key for an skb. It computes + * a phase 1 key if needed (iv16 wraps around). This function is to + * be used by drivers which can do HW encryption but need to compute + * to phase 1/2 key in SW. + * + * @keyconf: the parameter passed with the set key + * @skb: the skb for which the key is needed + * @type: TBD + * @key: a buffer to which the key will be written + */ +void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, + enum ieee80211_tkip_key_type type, u8 *key); +/** + * ieee80211_wake_queue - wake specific queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_wake_queue. + */ +void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); + +/** + * ieee80211_stop_queue - stop specific queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_stop_queue. + */ +void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); + +/** + * ieee80211_queue_stopped - test status of the queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_stop_queue. + */ + +int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue); + +/** + * ieee80211_stop_queues - stop all queues + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * + * Drivers should use this function instead of netif_stop_queue. + */ +void ieee80211_stop_queues(struct ieee80211_hw *hw); + +/** + * ieee80211_wake_queues - wake all queues + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * + * Drivers should use this function instead of netif_wake_queue. + */ +void ieee80211_wake_queues(struct ieee80211_hw *hw); + +/** + * ieee80211_scan_completed - completed hardware scan + * + * When hardware scan offload is used (i.e. the hw_scan() callback is + * assigned) this function needs to be called by the driver to notify + * mac80211 that the scan finished. + * + * @hw: the hardware that finished the scan + * @aborted: set to true if scan was aborted + */ +void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted); + +/** + * ieee80211_iterate_active_interfaces - iterate active interfaces + * + * This function iterates over the interfaces associated with a given + * hardware that are currently active and calls the callback for them. + * This function allows the iterator function to sleep, when the iterator + * function is atomic @ieee80211_iterate_active_interfaces_atomic can + * be used. + * + * @hw: the hardware struct of which the interfaces should be iterated over + * @iterator: the iterator function to call + * @data: first argument of the iterator function + */ +void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data); + +/** + * ieee80211_iterate_active_interfaces_atomic - iterate active interfaces + * + * This function iterates over the interfaces associated with a given + * hardware that are currently active and calls the callback for them. + * This function requires the iterator callback function to be atomic, + * if that is not desired, use @ieee80211_iterate_active_interfaces instead. + * + * @hw: the hardware struct of which the interfaces should be iterated over + * @iterator: the iterator function to call, cannot sleep + * @data: first argument of the iterator function + */ +void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, + void (*iterator)(void *data, + u8 *mac, + struct ieee80211_vif *vif), + void *data); + +/** + * ieee80211_queue_work - add work onto the mac80211 workqueue + * + * Drivers and mac80211 use this to add work onto the mac80211 workqueue. + * This helper ensures drivers are not queueing work when they should not be. + * + * @hw: the hardware struct for the interface we are adding work for + * @work: the work we want to add onto the mac80211 workqueue + */ +void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work); + +/** + * ieee80211_queue_delayed_work - add work onto the mac80211 workqueue + * + * Drivers and mac80211 use this to queue delayed work onto the mac80211 + * workqueue. + * + * @hw: the hardware struct for the interface we are adding work for + * @dwork: delayable work to queue onto the mac80211 workqueue + * @delay: number of jiffies to wait before queueing + */ +void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, + struct delayed_work *dwork, + unsigned long delay); + +/** + * ieee80211_start_tx_ba_session - Start a tx Block Ack session. + * @sta: the station for which to start a BA session + * @tid: the TID to BA on. + * + * Return: success if addBA request was sent, failure otherwise + * + * Although mac80211/low level driver/user space application can estimate + * the need to start aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid); + +/** + * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. + * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @ra: receiver address of the BA session recipient. + * @tid: the TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session. It can be called + * from any context. + */ +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, + u16 tid); + +/** + * ieee80211_stop_tx_ba_session - Stop a Block Ack session. + * @sta: the station whose BA session to stop + * @tid: the TID to stop BA. + * + * Return: negative error if the TID is invalid, or no aggregation active + * + * Although mac80211/low level driver/user space application can estimate + * the need to stop aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid); + +/** + * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. + * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @ra: receiver address of the BA session recipient. + * @tid: the desired TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session tear down. It + * can be called from any context. + */ +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, + u16 tid); + +/** + * ieee80211_find_sta - find a station + * + * @vif: virtual interface to look for station on + * @addr: station's address + * + * This function must be called under RCU lock and the + * resulting pointer is only valid under RCU lock as well. + */ +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, + const u8 *addr); + +/** + * ieee80211_find_sta_by_hw - find a station on hardware + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @addr: station's address + * + * This function must be called under RCU lock and the + * resulting pointer is only valid under RCU lock as well. + * + * NOTE: This function should not be used! When mac80211 is converted + * internally to properly keep track of stations on multiple + * virtual interfaces, it will not always know which station to + * return here since a single address might be used by multiple + * logical stations (e.g. consider a station connecting to another + * BSSID on the same AP hardware without disconnecting first). + * + * DO NOT USE THIS FUNCTION. + */ +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr); + +/** + * ieee80211_sta_block_awake - block station from waking up + * @hw: the hardware + * @pubsta: the station + * @block: whether to block or unblock + * + * Some devices require that all frames that are on the queues + * for a specific station that went to sleep are flushed before + * a poll response or frames after the station woke up can be + * delivered to that it. Note that such frames must be rejected + * by the driver as filtered, with the appropriate status flag. + * + * This function allows implementing this mode in a race-free + * manner. + * + * To do this, a driver must keep track of the number of frames + * still enqueued for a specific station. If this number is not + * zero when the station goes to sleep, the driver must call + * this function to force mac80211 to consider the station to + * be asleep regardless of the station's actual state. Once the + * number of outstanding frames reaches zero, the driver must + * call this function again to unblock the station. That will + * cause mac80211 to be able to send ps-poll responses, and if + * the station queried in the meantime then frames will also + * be sent out as a result of this. Additionally, the driver + * will be notified that the station woke up some time after + * it is unblocked, regardless of whether the station actually + * woke up while blocked or not. + */ +void ieee80211_sta_block_awake(struct ieee80211_hw *hw, + struct ieee80211_sta *pubsta, bool block); + +/** + * ieee80211_beacon_loss - inform hardware does not receive beacons + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING and + * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the + * hardware is not receiving beacons with this function. + */ +void ieee80211_beacon_loss(struct ieee80211_vif *vif); + +/** + * ieee80211_connection_loss - inform hardware has lost connection to the AP + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING, and + * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver + * needs to inform if the connection to the AP has been lost. + * + * This function will cause immediate change to disassociated state, + * without connection recovery attempts. + */ +void ieee80211_connection_loss(struct ieee80211_vif *vif); + +/** + * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * Some hardware require full power save to manage simultaneous BT traffic + * on the WLAN frequency. Full PSM is required periodically, whenever there are + * burst of BT traffic. The hardware gets information of BT traffic via + * hardware co-existence lines, and consequentially requests mac80211 to + * (temporarily) enter full psm. + * This function will only temporarily disable dynamic PS, not enable PSM if + * it was not already enabled. + * The driver must make sure to re-enable dynamic PS using + * ieee80211_enable_dyn_ps() if the driver has disabled it. + * + */ +void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif); + +/** + * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * This function restores dynamic PS after being temporarily disabled via + * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must + * be coupled with an eventual call to this function. + * + */ +void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif); + +/** + * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring + * rssi threshold triggered + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @rssi_event: the RSSI trigger event type + * @gfp: context flags + * + * When the %IEEE80211_HW_SUPPORTS_CQM_RSSI is set, and a connection quality + * monitoring is configured with an rssi threshold, the driver will inform + * whenever the rssi level reaches the threshold. + */ +void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, + enum nl80211_cqm_rssi_threshold_event rssi_event, + gfp_t gfp); + +/** + * ieee80211_chswitch_done - Complete channel switch process + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @success: make the channel switch successful or not + * + * Complete the channel switch post-process: set the new operational channel + * and wake up the suspended queues. + */ +void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success); + +/* Rate control API */ + +/** + * enum rate_control_changed - flags to indicate which parameter changed + * + * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have + * changed, rate control algorithm can update its internal state if needed. + */ +enum rate_control_changed { + IEEE80211_RC_HT_CHANGED = BIT(0) +}; + +/** + * struct ieee80211_tx_rate_control - rate control information for/from RC algo + * + * @hw: The hardware the algorithm is invoked for. + * @sband: The band this frame is being transmitted on. + * @bss_conf: the current BSS configuration + * @reported_rate: The rate control algorithm can fill this in to indicate + * which rate should be reported to userspace as the current rate and + * used for rate calculations in the mesh network. + * @rts: whether RTS will be used for this frame because it is longer than the + * RTS threshold + * @short_preamble: whether mac80211 will request short-preamble transmission + * if the selected rate supports it + * @max_rate_idx: user-requested maximum rate (not MCS for now) + * (deprecated; this will be removed once drivers get updated to use + * rate_idx_mask) + * @rate_idx_mask: user-requested rate mask (not MCS for now) + * @skb: the skb that will be transmitted, the control information in it needs + * to be filled in + * @ap: whether this frame is sent out in AP mode + */ +struct ieee80211_tx_rate_control { + struct ieee80211_hw *hw; + struct ieee80211_supported_band *sband; + struct ieee80211_bss_conf *bss_conf; + struct sk_buff *skb; + struct ieee80211_tx_rate reported_rate; + bool rts, short_preamble; + u8 max_rate_idx; + u32 rate_idx_mask; + bool ap; +}; + +struct rate_control_ops { + struct module *module; + const char *name; + void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); + void (*free)(void *priv); + + void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); + void (*rate_init)(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta); + void (*rate_update)(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, + void *priv_sta, u32 changed, + enum nl80211_channel_type oper_chan_type); + void (*free_sta)(void *priv, struct ieee80211_sta *sta, + void *priv_sta); + + void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, + struct sk_buff *skb); + void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc); + + void (*add_sta_debugfs)(void *priv, void *priv_sta, + struct dentry *dir); + void (*remove_sta_debugfs)(void *priv, void *priv_sta); +}; + +static inline int rate_supported(struct ieee80211_sta *sta, + enum ieee80211_band band, + int index) +{ + return (sta == NULL || sta->supp_rates[band] & BIT(index)); +} + +/** + * rate_control_send_low - helper for drivers for management/no-ack frames + * + * Rate control algorithms that agree to use the lowest rate to + * send management frames and NO_ACK data with the respective hw + * retries should use this in the beginning of their mac80211 get_rate + * callback. If true is returned the rate control can simply return. + * If false is returned we guarantee that sta and sta and priv_sta is + * not null. + * + * Rate control algorithms wishing to do more intelligent selection of + * rate for multicast/broadcast frames may choose to not use this. + * + * @sta: &struct ieee80211_sta pointer to the target destination. Note + * that this may be null. + * @priv_sta: private rate control structure. This may be null. + * @txrc: rate control information we sholud populate for mac80211. + */ +bool rate_control_send_low(struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc); + + +static inline s8 +rate_lowest_index(struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) +{ + int i; + + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) + return i; + + /* warn when we cannot find a rate. */ + WARN_ON(1); + + return 0; +} + +static inline +bool rate_usable_index_exists(struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) +{ + unsigned int i; + + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) + return true; + return false; +} + +int ieee80211_rate_control_register(struct rate_control_ops *ops); +void ieee80211_rate_control_unregister(struct rate_control_ops *ops); + +static inline bool +conf_is_ht20(struct ieee80211_conf *conf) +{ + return conf->channel_type == NL80211_CHAN_HT20; +} + +static inline bool +conf_is_ht40_minus(struct ieee80211_conf *conf) +{ + return conf->channel_type == NL80211_CHAN_HT40MINUS; +} + +static inline bool +conf_is_ht40_plus(struct ieee80211_conf *conf) +{ + return conf->channel_type == NL80211_CHAN_HT40PLUS; +} + +static inline bool +conf_is_ht40(struct ieee80211_conf *conf) +{ + return conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf); +} + +static inline bool +conf_is_ht(struct ieee80211_conf *conf) +{ + return conf->channel_type != NL80211_CHAN_NO_HT; +} + +#endif /* MAC80211_H */ diff --git a/include/net/mip6.h b/include/net/mip6.h new file mode 100644 index 00000000..26ba99b5 --- /dev/null +++ b/include/net/mip6.h @@ -0,0 +1,54 @@ +/* + * Copyright (C)2003-2006 Helsinki University of Technology + * Copyright (C)2003-2006 USAGI/WIDE Project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Authors: + * Noriaki TAKAMIYA @USAGI + * Masahide NAKAMURA @USAGI + * YOSHIFUJI Hideaki @USAGI + */ +#ifndef _NET_MIP6_H +#define _NET_MIP6_H + +#include <linux/skbuff.h> +#include <net/sock.h> + +/* + * Mobility Header + */ +struct ip6_mh { + __u8 ip6mh_proto; + __u8 ip6mh_hdrlen; + __u8 ip6mh_type; + __u8 ip6mh_reserved; + __u16 ip6mh_cksum; + /* Followed by type specific messages */ + __u8 data[0]; +} __packed; + +#define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */ +#define IP6_MH_TYPE_HOTI 1 /* HOTI Message */ +#define IP6_MH_TYPE_COTI 2 /* COTI Message */ +#define IP6_MH_TYPE_HOT 3 /* HOT Message */ +#define IP6_MH_TYPE_COT 4 /* COT Message */ +#define IP6_MH_TYPE_BU 5 /* Binding Update */ +#define IP6_MH_TYPE_BACK 6 /* Binding ACK */ +#define IP6_MH_TYPE_BERROR 7 /* Binding Error */ +#define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR + +#endif diff --git a/include/net/mld.h b/include/net/mld.h new file mode 100644 index 00000000..467143cd --- /dev/null +++ b/include/net/mld.h @@ -0,0 +1,75 @@ +#ifndef LINUX_MLD_H +#define LINUX_MLD_H + +#include <linux/in6.h> +#include <linux/icmpv6.h> + +/* MLDv1 Query/Report/Done */ +struct mld_msg { + struct icmp6hdr mld_hdr; + struct in6_addr mld_mca; +}; + +#define mld_type mld_hdr.icmp6_type +#define mld_code mld_hdr.icmp6_code +#define mld_cksum mld_hdr.icmp6_cksum +#define mld_maxdelay mld_hdr.icmp6_maxdelay +#define mld_reserved mld_hdr.icmp6_dataun.un_data16[1] + +/* Multicast Listener Discovery version 2 headers */ +/* MLDv2 Report */ +struct mld2_grec { + __u8 grec_type; + __u8 grec_auxwords; + __be16 grec_nsrcs; + struct in6_addr grec_mca; + struct in6_addr grec_src[0]; +}; + +struct mld2_report { + struct icmp6hdr mld2r_hdr; + struct mld2_grec mld2r_grec[0]; +}; + +#define mld2r_type mld2r_hdr.icmp6_type +#define mld2r_resv1 mld2r_hdr.icmp6_code +#define mld2r_cksum mld2r_hdr.icmp6_cksum +#define mld2r_resv2 mld2r_hdr.icmp6_dataun.un_data16[0] +#define mld2r_ngrec mld2r_hdr.icmp6_dataun.un_data16[1] + +/* MLDv2 Query */ +struct mld2_query { + struct icmp6hdr mld2q_hdr; + struct in6_addr mld2q_mca; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 mld2q_qrv:3, + mld2q_suppress:1, + mld2q_resv2:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 mld2q_resv2:4, + mld2q_suppress:1, + mld2q_qrv:3; +#else +#error "Please fix <asm/byteorder.h>" +#endif + __u8 mld2q_qqic; + __be16 mld2q_nsrcs; + struct in6_addr mld2q_srcs[0]; +}; + +#define mld2q_type mld2q_hdr.icmp6_type +#define mld2q_code mld2q_hdr.icmp6_code +#define mld2q_cksum mld2q_hdr.icmp6_cksum +#define mld2q_mrc mld2q_hdr.icmp6_maxdelay +#define mld2q_resv1 mld2q_hdr.icmp6_dataun.un_data16[1] + +/* Max Response Code */ +#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) +#define MLDV2_EXP(thresh, nbmant, nbexp, value) \ + ((value) < (thresh) ? (value) : \ + ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \ + (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) + +#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value) + +#endif diff --git a/include/net/ndisc.h b/include/net/ndisc.h new file mode 100644 index 00000000..895997bc --- /dev/null +++ b/include/net/ndisc.h @@ -0,0 +1,165 @@ +#ifndef _NDISC_H +#define _NDISC_H + +/* + * ICMP codes for neighbour discovery messages + */ + +#define NDISC_ROUTER_SOLICITATION 133 +#define NDISC_ROUTER_ADVERTISEMENT 134 +#define NDISC_NEIGHBOUR_SOLICITATION 135 +#define NDISC_NEIGHBOUR_ADVERTISEMENT 136 +#define NDISC_REDIRECT 137 + +/* + * Router type: cross-layer information from link-layer to + * IPv6 layer reported by certain link types (e.g., RFC4214). + */ +#define NDISC_NODETYPE_UNSPEC 0 /* unspecified (default) */ +#define NDISC_NODETYPE_HOST 1 /* host or unauthorized router */ +#define NDISC_NODETYPE_NODEFAULT 2 /* non-default router */ +#define NDISC_NODETYPE_DEFAULT 3 /* default router */ + +/* + * ndisc options + */ + +enum { + __ND_OPT_PREFIX_INFO_END = 0, + ND_OPT_SOURCE_LL_ADDR = 1, /* RFC2461 */ + ND_OPT_TARGET_LL_ADDR = 2, /* RFC2461 */ + ND_OPT_PREFIX_INFO = 3, /* RFC2461 */ + ND_OPT_REDIRECT_HDR = 4, /* RFC2461 */ + ND_OPT_MTU = 5, /* RFC2461 */ + __ND_OPT_ARRAY_MAX, + ND_OPT_ROUTE_INFO = 24, /* RFC4191 */ + ND_OPT_RDNSS = 25, /* RFC5006 */ + __ND_OPT_MAX +}; + +#define MAX_RTR_SOLICITATION_DELAY HZ + +#define ND_REACHABLE_TIME (30*HZ) +#define ND_RETRANS_TIMER HZ + +#define ND_MIN_RANDOM_FACTOR (1/2) +#define ND_MAX_RANDOM_FACTOR (3/2) + +#ifdef __KERNEL__ + +#include <linux/compiler.h> +#include <linux/icmpv6.h> +#include <linux/in6.h> +#include <linux/types.h> + +#include <net/neighbour.h> + +struct ctl_table; +struct inet6_dev; +struct net_device; +struct net_proto_family; +struct sk_buff; + +extern struct neigh_table nd_tbl; + +struct nd_msg { + struct icmp6hdr icmph; + struct in6_addr target; + __u8 opt[0]; +}; + +struct rs_msg { + struct icmp6hdr icmph; + __u8 opt[0]; +}; + +struct ra_msg { + struct icmp6hdr icmph; + __be32 reachable_time; + __be32 retrans_timer; +}; + +struct nd_opt_hdr { + __u8 nd_opt_type; + __u8 nd_opt_len; +} __packed; + + +extern int ndisc_init(void); + +extern void ndisc_cleanup(void); + +extern int ndisc_rcv(struct sk_buff *skb); + +extern void ndisc_send_ns(struct net_device *dev, + struct neighbour *neigh, + const struct in6_addr *solicit, + const struct in6_addr *daddr, + const struct in6_addr *saddr); + +extern void ndisc_send_rs(struct net_device *dev, + const struct in6_addr *saddr, + const struct in6_addr *daddr); + +extern void ndisc_send_redirect(struct sk_buff *skb, + struct neighbour *neigh, + const struct in6_addr *target); + +extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir); + +extern struct sk_buff *ndisc_build_skb(struct net_device *dev, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h, + const struct in6_addr *target, + int llinfo); + +extern void ndisc_send_skb(struct sk_buff *skb, + struct net_device *dev, + struct neighbour *neigh, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h); + + + +/* + * IGMP + */ +extern int igmp6_init(void); + +extern void igmp6_cleanup(void); + +extern int igmp6_event_query(struct sk_buff *skb); + +extern int igmp6_event_report(struct sk_buff *skb); + + +#ifdef CONFIG_SYSCTL +extern int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, + int write, + void __user *buffer, + size_t *lenp, + loff_t *ppos); +int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen); +#endif + +extern void inet6_ifinfo_notify(int event, + struct inet6_dev *idev); + +static inline struct neighbour * ndisc_get_neigh(struct net_device *dev, const struct in6_addr *addr) +{ + + if (dev) + return __neigh_lookup_errno(&nd_tbl, addr, dev); + + return ERR_PTR(-ENODEV); +} + + +#endif /* __KERNEL__ */ + + +#endif diff --git a/include/net/neighbour.h b/include/net/neighbour.h new file mode 100644 index 00000000..242879b6 --- /dev/null +++ b/include/net/neighbour.h @@ -0,0 +1,367 @@ +#ifndef _NET_NEIGHBOUR_H +#define _NET_NEIGHBOUR_H + +#include <linux/neighbour.h> + +/* + * Generic neighbour manipulation + * + * Authors: + * Pedro Roque <roque@di.fc.ul.pt> + * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> + * + * Changes: + * + * Harald Welte: <laforge@gnumonks.org> + * - Add neighbour cache statistics like rtstat + */ + +#include <asm/atomic.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/rcupdate.h> +#include <linux/seq_file.h> + +#include <linux/err.h> +#include <linux/sysctl.h> +#include <linux/workqueue.h> +#include <net/rtnetlink.h> + +/* + * NUD stands for "neighbor unreachability detection" + */ + +#define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE) +#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY) +#define NUD_CONNECTED (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE) + +struct neighbour; + +struct neigh_parms { +#ifdef CONFIG_NET_NS + struct net *net; +#endif + struct net_device *dev; + struct neigh_parms *next; + int (*neigh_setup)(struct neighbour *); + void (*neigh_cleanup)(struct neighbour *); + struct neigh_table *tbl; + + void *sysctl_table; + + int dead; + atomic_t refcnt; + struct rcu_head rcu_head; + + int base_reachable_time; + int retrans_time; + int gc_staletime; + int reachable_time; + int delay_probe_time; + + int queue_len; + int ucast_probes; + int app_probes; + int mcast_probes; + int anycast_delay; + int proxy_delay; + int proxy_qlen; + int locktime; +}; + +struct neigh_statistics { + unsigned long allocs; /* number of allocated neighs */ + unsigned long destroys; /* number of destroyed neighs */ + unsigned long hash_grows; /* number of hash resizes */ + + unsigned long res_failed; /* number of failed resolutions */ + + unsigned long lookups; /* number of lookups */ + unsigned long hits; /* number of hits (among lookups) */ + + unsigned long rcv_probes_mcast; /* number of received mcast ipv6 */ + unsigned long rcv_probes_ucast; /* number of received ucast ipv6 */ + + unsigned long periodic_gc_runs; /* number of periodic GC runs */ + unsigned long forced_gc_runs; /* number of forced GC runs */ + + unsigned long unres_discards; /* number of unresolved drops */ +}; + +#define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field) + +struct neighbour { + struct neighbour *next; + struct neigh_table *tbl; + struct neigh_parms *parms; + struct net_device *dev; + unsigned long used; + unsigned long confirmed; + unsigned long updated; + __u8 flags; + __u8 nud_state; + __u8 type; + __u8 dead; + atomic_t probes; + rwlock_t lock; + unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; + struct hh_cache *hh; + atomic_t refcnt; + int (*output)(struct sk_buff *skb); + struct sk_buff_head arp_queue; + struct timer_list timer; + const struct neigh_ops *ops; + u8 primary_key[0]; +}; + +struct neigh_ops { + int family; + void (*solicit)(struct neighbour *, struct sk_buff*); + void (*error_report)(struct neighbour *, struct sk_buff*); + int (*output)(struct sk_buff*); + int (*connected_output)(struct sk_buff*); + int (*hh_output)(struct sk_buff*); + int (*queue_xmit)(struct sk_buff*); +}; + +struct pneigh_entry { + struct pneigh_entry *next; +#ifdef CONFIG_NET_NS + struct net *net; +#endif + struct net_device *dev; + u8 flags; + u8 key[0]; +}; + +/* + * neighbour table manipulation + */ + + +struct neigh_table { + struct neigh_table *next; + int family; + int entry_size; + int key_len; + __u32 (*hash)(const void *pkey, const struct net_device *); + int (*constructor)(struct neighbour *); + int (*pconstructor)(struct pneigh_entry *); + void (*pdestructor)(struct pneigh_entry *); + void (*proxy_redo)(struct sk_buff *skb); + char *id; + struct neigh_parms parms; + /* HACK. gc_* should follow parms without a gap! */ + int gc_interval; + int gc_thresh1; + int gc_thresh2; + int gc_thresh3; + unsigned long last_flush; + struct delayed_work gc_work; + struct timer_list proxy_timer; + struct sk_buff_head proxy_queue; + atomic_t entries; + rwlock_t lock; + unsigned long last_rand; + struct kmem_cache *kmem_cachep; + struct neigh_statistics __percpu *stats; + struct neighbour **hash_buckets; + unsigned int hash_mask; + __u32 hash_rnd; + struct pneigh_entry **phash_buckets; +}; + +/* flags for neigh_update() */ +#define NEIGH_UPDATE_F_OVERRIDE 0x00000001 +#define NEIGH_UPDATE_F_WEAK_OVERRIDE 0x00000002 +#define NEIGH_UPDATE_F_OVERRIDE_ISROUTER 0x00000004 +#define NEIGH_UPDATE_F_ISROUTER 0x40000000 +#define NEIGH_UPDATE_F_ADMIN 0x80000000 + +extern void neigh_table_init(struct neigh_table *tbl); +extern void neigh_table_init_no_netlink(struct neigh_table *tbl); +extern int neigh_table_clear(struct neigh_table *tbl); +extern struct neighbour * neigh_lookup(struct neigh_table *tbl, + const void *pkey, + struct net_device *dev); +extern struct neighbour * neigh_lookup_nodev(struct neigh_table *tbl, + struct net *net, + const void *pkey); +extern struct neighbour * neigh_create(struct neigh_table *tbl, + const void *pkey, + struct net_device *dev); +extern void neigh_destroy(struct neighbour *neigh); +extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); +extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, + u32 flags); +extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); +extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); +extern int neigh_resolve_output(struct sk_buff *skb); +extern int neigh_connected_output(struct sk_buff *skb); +extern int neigh_compat_output(struct sk_buff *skb); +extern struct neighbour *neigh_event_ns(struct neigh_table *tbl, + u8 *lladdr, void *saddr, + struct net_device *dev); + +extern struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_table *tbl); +extern void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms); + +static inline +struct net *neigh_parms_net(const struct neigh_parms *parms) +{ + return read_pnet(&parms->net); +} + +extern unsigned long neigh_rand_reach_time(unsigned long base); + +extern void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, + struct sk_buff *skb); +extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev, int creat); +extern struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, + struct net *net, + const void *key, + struct net_device *dev); +extern int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev); + +static inline +struct net *pneigh_net(const struct pneigh_entry *pneigh) +{ + return read_pnet(&pneigh->net); +} + +extern void neigh_app_ns(struct neighbour *n); +extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie); +extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *)); +extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *)); + +struct neigh_seq_state { + struct seq_net_private p; + struct neigh_table *tbl; + void *(*neigh_sub_iter)(struct neigh_seq_state *state, + struct neighbour *n, loff_t *pos); + unsigned int bucket; + unsigned int flags; +#define NEIGH_SEQ_NEIGH_ONLY 0x00000001 +#define NEIGH_SEQ_IS_PNEIGH 0x00000002 +#define NEIGH_SEQ_SKIP_NOARP 0x00000004 +}; +extern void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table *, unsigned int); +extern void *neigh_seq_next(struct seq_file *, void *, loff_t *); +extern void neigh_seq_stop(struct seq_file *, void *); + +extern int neigh_sysctl_register(struct net_device *dev, + struct neigh_parms *p, + char *p_name, + proc_handler *proc_handler); +extern void neigh_sysctl_unregister(struct neigh_parms *p); + +static inline void __neigh_parms_put(struct neigh_parms *parms) +{ + atomic_dec(&parms->refcnt); +} + +static inline struct neigh_parms *neigh_parms_clone(struct neigh_parms *parms) +{ + atomic_inc(&parms->refcnt); + return parms; +} + +/* + * Neighbour references + */ + +static inline void neigh_release(struct neighbour *neigh) +{ + if (atomic_dec_and_test(&neigh->refcnt)) + neigh_destroy(neigh); +} + +static inline struct neighbour * neigh_clone(struct neighbour *neigh) +{ + if (neigh) + atomic_inc(&neigh->refcnt); + return neigh; +} + +#define neigh_hold(n) atomic_inc(&(n)->refcnt) + +static inline void neigh_confirm(struct neighbour *neigh) +{ + if (neigh) + neigh->confirmed = jiffies; +} + +static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) +{ + neigh->used = jiffies; + if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) + return __neigh_event_send(neigh, skb); + return 0; +} + +#ifdef CONFIG_BRIDGE_NETFILTER +static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) +{ + unsigned seq, hh_alen; + + do { + seq = read_seqbegin(&hh->hh_lock); + hh_alen = HH_DATA_ALIGN(ETH_HLEN); + memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); + } while (read_seqretry(&hh->hh_lock, seq)); + return 0; +} +#endif + +static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) +{ + unsigned seq; + int hh_len; + + do { + int hh_alen; + + seq = read_seqbegin(&hh->hh_lock); + hh_len = hh->hh_len; + hh_alen = HH_DATA_ALIGN(hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); + } while (read_seqretry(&hh->hh_lock, seq)); + + skb_push(skb, hh_len); + return hh->hh_output(skb); +} + +static inline struct neighbour * +__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) +{ + struct neighbour *n = neigh_lookup(tbl, pkey, dev); + + if (n || !creat) + return n; + + n = neigh_create(tbl, pkey, dev); + return IS_ERR(n) ? NULL : n; +} + +static inline struct neighbour * +__neigh_lookup_errno(struct neigh_table *tbl, const void *pkey, + struct net_device *dev) +{ + struct neighbour *n = neigh_lookup(tbl, pkey, dev); + + if (n) + return n; + + return neigh_create(tbl, pkey, dev); +} + +struct neighbour_cb { + unsigned long sched_next; + unsigned int flags; +}; + +#define LOCALLY_ENQUEUED 0x1 + +#define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb) + +#endif diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h new file mode 100644 index 00000000..bd10a790 --- /dev/null +++ b/include/net/net_namespace.h @@ -0,0 +1,276 @@ +/* + * Operations on the network namespace + */ +#ifndef __NET_NET_NAMESPACE_H +#define __NET_NET_NAMESPACE_H + +#include <asm/atomic.h> +#include <linux/workqueue.h> +#include <linux/list.h> + +#include <net/netns/core.h> +#include <net/netns/mib.h> +#include <net/netns/unix.h> +#include <net/netns/packet.h> +#include <net/netns/ipv4.h> +#include <net/netns/ipv6.h> +#include <net/netns/dccp.h> +#include <net/netns/x_tables.h> +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +#include <net/netns/conntrack.h> +#endif +#include <net/netns/xfrm.h> + +struct proc_dir_entry; +struct net_device; +struct sock; +struct ctl_table_header; +struct net_generic; +struct sock; + + +#define NETDEV_HASHBITS 8 +#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) + +struct net { + atomic_t count; /* To decided when the network + * namespace should be freed. + */ +#ifdef NETNS_REFCNT_DEBUG + atomic_t use_count; /* To track references we + * destroy on demand + */ +#endif + struct list_head list; /* list of network namespaces */ + struct list_head cleanup_list; /* namespaces on death row */ + struct list_head exit_list; /* Use only net_mutex */ + + struct proc_dir_entry *proc_net; + struct proc_dir_entry *proc_net_stat; + +#ifdef CONFIG_SYSCTL + struct ctl_table_set sysctls; +#endif + + struct net_device *loopback_dev; /* The loopback */ + + struct list_head dev_base_head; + struct hlist_head *dev_name_head; + struct hlist_head *dev_index_head; + + /* core fib_rules */ + struct list_head rules_ops; + spinlock_t rules_mod_lock; + + struct sock *rtnl; /* rtnetlink socket */ + struct sock *genl_sock; + + struct netns_core core; + struct netns_mib mib; + struct netns_packet packet; + struct netns_unix unx; + struct netns_ipv4 ipv4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct netns_ipv6 ipv6; +#endif +#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) + struct netns_dccp dccp; +#endif +#ifdef CONFIG_NETFILTER + struct netns_xt xt; +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + struct netns_ct ct; +#endif + struct sock *nfnl; + struct sock *nfnl_stash; +#endif +#ifdef CONFIG_XFRM + struct netns_xfrm xfrm; +#endif +#ifdef CONFIG_WEXT_CORE + struct sk_buff_head wext_nlevents; +#endif + struct net_generic *gen; +}; + + +#include <linux/seq_file_net.h> + +/* Init's network namespace */ +extern struct net init_net; + +#ifdef CONFIG_NET +extern struct net *copy_net_ns(unsigned long flags, struct net *net_ns); + +#else /* CONFIG_NET */ +static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns) +{ + /* There is nothing to copy so this is a noop */ + return net_ns; +} +#endif /* CONFIG_NET */ + + +extern struct list_head net_namespace_list; + +extern struct net *get_net_ns_by_pid(pid_t pid); + +#ifdef CONFIG_NET_NS +extern void __put_net(struct net *net); + +static inline struct net *get_net(struct net *net) +{ + atomic_inc(&net->count); + return net; +} + +static inline struct net *maybe_get_net(struct net *net) +{ + /* Used when we know struct net exists but we + * aren't guaranteed a previous reference count + * exists. If the reference count is zero this + * function fails and returns NULL. + */ + if (!atomic_inc_not_zero(&net->count)) + net = NULL; + return net; +} + +static inline void put_net(struct net *net) +{ + if (atomic_dec_and_test(&net->count)) + __put_net(net); +} + +static inline +int net_eq(const struct net *net1, const struct net *net2) +{ + return net1 == net2; +} +#else + +static inline struct net *get_net(struct net *net) +{ + return net; +} + +static inline void put_net(struct net *net) +{ +} + +static inline struct net *maybe_get_net(struct net *net) +{ + return net; +} + +static inline +int net_eq(const struct net *net1, const struct net *net2) +{ + return 1; +} +#endif + + +#ifdef NETNS_REFCNT_DEBUG +static inline struct net *hold_net(struct net *net) +{ + if (net) + atomic_inc(&net->use_count); + return net; +} + +static inline void release_net(struct net *net) +{ + if (net) + atomic_dec(&net->use_count); +} +#else +static inline struct net *hold_net(struct net *net) +{ + return net; +} + +static inline void release_net(struct net *net) +{ +} +#endif + +#ifdef CONFIG_NET_NS + +static inline void write_pnet(struct net **pnet, struct net *net) +{ + *pnet = net; +} + +static inline struct net *read_pnet(struct net * const *pnet) +{ + return *pnet; +} + +#else + +#define write_pnet(pnet, net) do { (void)(net);} while (0) +#define read_pnet(pnet) (&init_net) + +#endif + +#define for_each_net(VAR) \ + list_for_each_entry(VAR, &net_namespace_list, list) + +#define for_each_net_rcu(VAR) \ + list_for_each_entry_rcu(VAR, &net_namespace_list, list) + +#ifdef CONFIG_NET_NS +#define __net_init +#define __net_exit +#define __net_initdata +#else +#define __net_init __init +#define __net_exit __exit_refok +#define __net_initdata __initdata +#endif + +struct pernet_operations { + struct list_head list; + int (*init)(struct net *net); + void (*exit)(struct net *net); + void (*exit_batch)(struct list_head *net_exit_list); + int *id; + size_t size; +}; + +/* + * Use these carefully. If you implement a network device and it + * needs per network namespace operations use device pernet operations, + * otherwise use pernet subsys operations. + * + * Network interfaces need to be removed from a dying netns _before_ + * subsys notifiers can be called, as most of the network code cleanup + * (which is done from subsys notifiers) runs with the assumption that + * dev_remove_pack has been called so no new packets will arrive during + * and after the cleanup functions have been called. dev_remove_pack + * is not per namespace so instead the guarantee of no more packets + * arriving in a network namespace is provided by ensuring that all + * network devices and all sockets have left the network namespace + * before the cleanup methods are called. + * + * For the longest time the ipv4 icmp code was registered as a pernet + * device which caused kernel oops, and panics during network + * namespace cleanup. So please don't get this wrong. + */ +extern int register_pernet_subsys(struct pernet_operations *); +extern void unregister_pernet_subsys(struct pernet_operations *); +extern int register_pernet_device(struct pernet_operations *); +extern void unregister_pernet_device(struct pernet_operations *); + +struct ctl_path; +struct ctl_table; +struct ctl_table_header; + +extern struct ctl_table_header *register_net_sysctl_table(struct net *net, + const struct ctl_path *path, struct ctl_table *table); +extern struct ctl_table_header *register_net_sysctl_rotable( + const struct ctl_path *path, struct ctl_table *table); +extern void unregister_net_sysctl_table(struct ctl_table_header *header); + +#endif /* __NET_NET_NAMESPACE_H */ diff --git a/include/net/netdma.h b/include/net/netdma.h new file mode 100644 index 00000000..8ba8ce28 --- /dev/null +++ b/include/net/netdma.h @@ -0,0 +1,32 @@ +/* + * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ +#ifndef NETDMA_H +#define NETDMA_H +#ifdef CONFIG_NET_DMA +#include <linux/dmaengine.h> +#include <linux/skbuff.h> + +int dma_skb_copy_datagram_iovec(struct dma_chan* chan, + struct sk_buff *skb, int offset, struct iovec *to, + size_t len, struct dma_pinned_list *pinned_list); + +#endif /* CONFIG_NET_DMA */ +#endif /* NETDMA_H */ diff --git a/include/net/netevent.h b/include/net/netevent.h new file mode 100644 index 00000000..e82b7bab --- /dev/null +++ b/include/net/netevent.h @@ -0,0 +1,33 @@ +#ifndef _NET_EVENT_H +#define _NET_EVENT_H + +/* + * Generic netevent notifiers + * + * Authors: + * Tom Tucker <tom@opengridcomputing.com> + * Steve Wise <swise@opengridcomputing.com> + * + * Changes: + */ +#ifdef __KERNEL__ + +struct dst_entry; + +struct netevent_redirect { + struct dst_entry *old; + struct dst_entry *new; +}; + +enum netevent_notif_type { + NETEVENT_NEIGH_UPDATE = 1, /* arg is struct neighbour ptr */ + NETEVENT_PMTU_UPDATE, /* arg is struct dst_entry ptr */ + NETEVENT_REDIRECT, /* arg is struct netevent_redirect ptr */ +}; + +extern int register_netevent_notifier(struct notifier_block *nb); +extern int unregister_netevent_notifier(struct notifier_block *nb); +extern int call_netevent_notifiers(unsigned long val, void *v); + +#endif +#endif diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h new file mode 100644 index 00000000..7573d52a --- /dev/null +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -0,0 +1,24 @@ +/* + * IPv4 support for nf_conntrack. + * + * 23 Mar 2004: Yasuyuki Kozakai @ USAGI <yasuyuki.kozakai@toshiba.co.jp> + * - move L3 protocol dependent part from include/linux/netfilter_ipv4/ + * ip_conntarck.h + */ + +#ifndef _NF_CONNTRACK_IPV4_H +#define _NF_CONNTRACK_IPV4_H + + +extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; + +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp; + +extern int nf_conntrack_ipv4_compat_init(void); +extern void nf_conntrack_ipv4_compat_fini(void); + +extern void need_ipv4_conntrack(void); + +#endif /*_NF_CONNTRACK_IPV4_H*/ diff --git a/include/net/netfilter/ipv4/nf_defrag_ipv4.h b/include/net/netfilter/ipv4/nf_defrag_ipv4.h new file mode 100644 index 00000000..6b00ea38 --- /dev/null +++ b/include/net/netfilter/ipv4/nf_defrag_ipv4.h @@ -0,0 +1,6 @@ +#ifndef _NF_DEFRAG_IPV4_H +#define _NF_DEFRAG_IPV4_H + +extern void nf_defrag_ipv4_enable(void); + +#endif /* _NF_DEFRAG_IPV4_H */ diff --git a/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h new file mode 100644 index 00000000..67edd50a --- /dev/null +++ b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h @@ -0,0 +1,20 @@ +/* + * ICMPv6 tracking. + * + * 21 Apl 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> + * - separated from nf_conntrack_icmp.h + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_icmp.h + */ + +#ifndef _NF_CONNTRACK_ICMPV6_H +#define _NF_CONNTRACK_ICMPV6_H + +#ifndef ICMPV6_NI_QUERY +#define ICMPV6_NI_QUERY 139 +#endif +#ifndef ICMPV6_NI_REPLY +#define ICMPV6_NI_REPLY 140 +#endif + +#endif /* _NF_CONNTRACK_ICMPV6_H */ diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h new file mode 100644 index 00000000..1ee717eb --- /dev/null +++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h @@ -0,0 +1,23 @@ +#ifndef _NF_CONNTRACK_IPV6_H +#define _NF_CONNTRACK_IPV6_H + +extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; + +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6; + +extern int nf_ct_frag6_init(void); +extern void nf_ct_frag6_cleanup(void); +extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); +extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, + struct net_device *in, + struct net_device *out, + int (*okfn)(struct sk_buff *)); + +struct inet_frags_ctl; + +#include <linux/sysctl.h> +extern struct ctl_table nf_ct_ipv6_sysctl_table[]; + +#endif /* _NF_CONNTRACK_IPV6_H*/ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h new file mode 100644 index 00000000..e624dae5 --- /dev/null +++ b/include/net/netfilter/nf_conntrack.h @@ -0,0 +1,315 @@ +/* + * Connection state tracking for netfilter. This is separated from, + * but required by, the (future) NAT layer; it can also be used by an iptables + * extension. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack.h + */ + +#ifndef _NF_CONNTRACK_H +#define _NF_CONNTRACK_H + +#include <linux/netfilter/nf_conntrack_common.h> + +#ifdef __KERNEL__ +#include <linux/bitops.h> +#include <linux/compiler.h> +#include <asm/atomic.h> + +#include <linux/netfilter/nf_conntrack_tcp.h> +#include <linux/netfilter/nf_conntrack_dccp.h> +#include <linux/netfilter/nf_conntrack_sctp.h> +#include <linux/netfilter/nf_conntrack_proto_gre.h> +#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> + +#include <net/netfilter/nf_conntrack_tuple.h> + +/* per conntrack: protocol private data */ +union nf_conntrack_proto { + /* insert conntrack proto private data here */ + struct nf_ct_dccp dccp; + struct ip_ct_sctp sctp; + struct ip_ct_tcp tcp; + struct nf_ct_gre gre; +}; + +union nf_conntrack_expect_proto { + /* insert expect proto private data here */ +}; + +/* Add protocol helper include file here */ +#include <linux/netfilter/nf_conntrack_ftp.h> +#include <linux/netfilter/nf_conntrack_pptp.h> +#include <linux/netfilter/nf_conntrack_h323.h> +#include <linux/netfilter/nf_conntrack_sane.h> +#include <linux/netfilter/nf_conntrack_sip.h> + +/* per conntrack: application helper private data */ +union nf_conntrack_help { + /* insert conntrack helper private data (master) here */ + struct nf_ct_ftp_master ct_ftp_info; + struct nf_ct_pptp_master ct_pptp_info; + struct nf_ct_h323_master ct_h323_info; + struct nf_ct_sane_master ct_sane_info; + struct nf_ct_sip_master ct_sip_info; +}; + +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/timer.h> + +#ifdef CONFIG_NETFILTER_DEBUG +#define NF_CT_ASSERT(x) WARN_ON(!(x)) +#else +#define NF_CT_ASSERT(x) +#endif + +struct nf_conntrack_helper; + +/* Must be kept in sync with the classes defined by helpers */ +#define NF_CT_MAX_EXPECT_CLASSES 4 + +/* nf_conn feature for connections that have a helper */ +struct nf_conn_help { + /* Helper. if any */ + struct nf_conntrack_helper *helper; + + union nf_conntrack_help help; + + struct hlist_head expectations; + + /* Current number of expected connections */ + u8 expecting[NF_CT_MAX_EXPECT_CLASSES]; +}; + +#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> +#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> + +struct nf_conn { + /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, + plus 1 for any connection(s) we are `master' for */ + struct nf_conntrack ct_general; + + spinlock_t lock; + + /* XXX should I move this to the tail ? - Y.K */ + /* These are my tuples; original and reply */ + struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; + + /* Have we seen traffic both ways yet? (bitset) */ + unsigned long status; + + /* If we were expected by an expectation, this will be it */ + struct nf_conn *master; + + /* Timer function; drops refcnt when it goes off. */ + struct timer_list timeout; + +#if defined(CONFIG_NF_CONNTRACK_MARK) + u_int32_t mark; +#endif + +#ifdef CONFIG_NF_CONNTRACK_SECMARK + u_int32_t secmark; +#endif + + /* Storage reserved for other modules: */ + union nf_conntrack_proto proto; + + /* Extensions */ + struct nf_ct_ext *ext; +#ifdef CONFIG_NET_NS + struct net *ct_net; +#endif +}; + +static inline struct nf_conn * +nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) +{ + return container_of(hash, struct nf_conn, + tuplehash[hash->tuple.dst.dir]); +} + +static inline u_int16_t nf_ct_l3num(const struct nf_conn *ct) +{ + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; +} + +static inline u_int8_t nf_ct_protonum(const struct nf_conn *ct) +{ + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; +} + +#define nf_ct_tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) + +/* get master conntrack via master expectation */ +#define master_ct(conntr) (conntr->master) + +extern struct net init_net; + +static inline struct net *nf_ct_net(const struct nf_conn *ct) +{ + return read_pnet(&ct->ct_net); +} + +/* Alter reply tuple (maybe alter helper). */ +extern void +nf_conntrack_alter_reply(struct nf_conn *ct, + const struct nf_conntrack_tuple *newreply); + +/* Is this tuple taken? (ignoring any belonging to the given + conntrack). */ +extern int +nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack); + +/* Return conntrack_info and tuple hash for given skb. */ +static inline struct nf_conn * +nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo) +{ + *ctinfo = skb->nfctinfo; + return (struct nf_conn *)skb->nfct; +} + +/* decrement reference count on a conntrack */ +static inline void nf_ct_put(struct nf_conn *ct) +{ + NF_CT_ASSERT(ct); + nf_conntrack_put(&ct->ct_general); +} + +/* Protocol module loading */ +extern int nf_ct_l3proto_try_module_get(unsigned short l3proto); +extern void nf_ct_l3proto_module_put(unsigned short l3proto); + +/* + * Allocate a hashtable of hlist_head (if nulls == 0), + * or hlist_nulls_head (if nulls == 1) + */ +extern void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls); + +extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size); + +extern struct nf_conntrack_tuple_hash * +__nf_conntrack_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +extern void nf_conntrack_hash_insert(struct nf_conn *ct); +extern void nf_ct_delete_from_lists(struct nf_conn *ct); +extern void nf_ct_insert_dying_list(struct nf_conn *ct); + +extern void nf_conntrack_flush_report(struct net *net, u32 pid, int report); + +extern bool nf_ct_get_tuplepr(const struct sk_buff *skb, + unsigned int nhoff, u_int16_t l3num, + struct nf_conntrack_tuple *tuple); +extern bool nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); + +extern void __nf_ct_refresh_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + unsigned long extra_jiffies, + int do_acct); + +/* Refresh conntrack for this many jiffies and do accounting */ +static inline void nf_ct_refresh_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + unsigned long extra_jiffies) +{ + __nf_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1); +} + +/* Refresh conntrack for this many jiffies */ +static inline void nf_ct_refresh(struct nf_conn *ct, + const struct sk_buff *skb, + unsigned long extra_jiffies) +{ + __nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0); +} + +extern bool __nf_ct_kill_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + int do_acct); + +/* kill conntrack and do accounting */ +static inline bool nf_ct_kill_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb) +{ + return __nf_ct_kill_acct(ct, ctinfo, skb, 1); +} + +/* kill conntrack without accounting */ +static inline bool nf_ct_kill(struct nf_conn *ct) +{ + return __nf_ct_kill_acct(ct, 0, NULL, 0); +} + +/* These are for NAT. Icky. */ +extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq); + +/* Fake conntrack entry for untracked connections */ +DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked); +static inline struct nf_conn *nf_ct_untracked_get(void) +{ + return &__raw_get_cpu_var(nf_conntrack_untracked); +} +extern void nf_ct_untracked_status_or(unsigned long bits); + +/* Iterate over all conntracks: if iter returns true, it's deleted. */ +extern void +nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data); +extern void nf_conntrack_free(struct nf_conn *ct); +extern struct nf_conn * +nf_conntrack_alloc(struct net *net, u16 zone, + const struct nf_conntrack_tuple *orig, + const struct nf_conntrack_tuple *repl, + gfp_t gfp); + +static inline int nf_ct_is_template(const struct nf_conn *ct) +{ + return test_bit(IPS_TEMPLATE_BIT, &ct->status); +} + +/* It's confirmed if it is, or has been in the hash table. */ +static inline int nf_ct_is_confirmed(struct nf_conn *ct) +{ + return test_bit(IPS_CONFIRMED_BIT, &ct->status); +} + +static inline int nf_ct_is_dying(struct nf_conn *ct) +{ + return test_bit(IPS_DYING_BIT, &ct->status); +} + +static inline int nf_ct_is_untracked(const struct nf_conn *ct) +{ + return test_bit(IPS_UNTRACKED_BIT, &ct->status); +} + +extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); +extern unsigned int nf_conntrack_htable_size; +extern unsigned int nf_conntrack_max; + +#define NF_CT_STAT_INC(net, count) \ + __this_cpu_inc((net)->ct.stat->count) +#define NF_CT_STAT_INC_ATOMIC(net, count) \ +do { \ + local_bh_disable(); \ + __this_cpu_inc((net)->ct.stat->count); \ + local_bh_enable(); \ +} while (0) + +#define MODULE_ALIAS_NFCT_HELPER(helper) \ + MODULE_ALIAS("nfct-helper-" helper) + +#endif /* __KERNEL__ */ +#endif /* _NF_CONNTRACK_H */ diff --git a/include/net/netfilter/nf_conntrack_acct.h b/include/net/netfilter/nf_conntrack_acct.h new file mode 100644 index 00000000..4e9c63a2 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_acct.h @@ -0,0 +1,63 @@ +/* + * (C) 2008 Krzysztof Piotr Oledzki <ole@ans.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _NF_CONNTRACK_ACCT_H +#define _NF_CONNTRACK_ACCT_H +#include <net/net_namespace.h> +#include <linux/netfilter/nf_conntrack_common.h> +#include <linux/netfilter/nf_conntrack_tuple_common.h> +#include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_conntrack_extend.h> + +struct nf_conn_counter { + u_int64_t packets; + u_int64_t bytes; +}; + +static inline +struct nf_conn_counter *nf_conn_acct_find(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_ACCT); +} + +static inline +struct nf_conn_counter *nf_ct_acct_ext_add(struct nf_conn *ct, gfp_t gfp) +{ + struct net *net = nf_ct_net(ct); + struct nf_conn_counter *acct; + + if (!net->ct.sysctl_acct) + return NULL; + + acct = nf_ct_ext_add(ct, NF_CT_EXT_ACCT, gfp); + if (!acct) + pr_debug("failed to add accounting extension area"); + + + return acct; +}; + +extern unsigned int +seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir); + +/* Check if connection tracking accounting is enabled */ +static inline bool nf_ct_acct_enabled(struct net *net) +{ + return net->ct.sysctl_acct != 0; +} + +/* Enable/disable connection tracking accounting */ +static inline void nf_ct_set_acct(struct net *net, bool enable) +{ + net->ct.sysctl_acct = enable; +} + +extern int nf_conntrack_acct_init(struct net *net); +extern void nf_conntrack_acct_fini(struct net *net); + +#endif /* _NF_CONNTRACK_ACCT_H */ diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h new file mode 100644 index 00000000..aced0851 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_core.h @@ -0,0 +1,79 @@ +/* + * This header is used to share core functionality between the + * standalone connection tracking module, and the compatibility layer's use + * of connection tracking. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_core.h + */ + +#ifndef _NF_CONNTRACK_CORE_H +#define _NF_CONNTRACK_CORE_H + +#include <linux/netfilter.h> +#include <net/netfilter/nf_conntrack_l3proto.h> +#include <net/netfilter/nf_conntrack_l4proto.h> +#include <net/netfilter/nf_conntrack_ecache.h> + +/* This header is used to share core functionality between the + standalone connection tracking module, and the compatibility layer's use + of connection tracking. */ +extern unsigned int nf_conntrack_in(struct net *net, + u_int8_t pf, + unsigned int hooknum, + struct sk_buff *skb); + +extern int nf_conntrack_init(struct net *net); +extern void nf_conntrack_cleanup(struct net *net); + +extern int nf_conntrack_proto_init(void); +extern void nf_conntrack_proto_fini(void); + +extern bool +nf_ct_get_tuple(const struct sk_buff *skb, + unsigned int nhoff, + unsigned int dataoff, + u_int16_t l3num, + u_int8_t protonum, + struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_l3proto *l3proto, + const struct nf_conntrack_l4proto *l4proto); + +extern bool +nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig, + const struct nf_conntrack_l3proto *l3proto, + const struct nf_conntrack_l4proto *l4proto); + +/* Find a connection corresponding to a tuple. */ +extern struct nf_conntrack_tuple_hash * +nf_conntrack_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +extern int __nf_conntrack_confirm(struct sk_buff *skb); + +/* Confirm a connection: returns NF_DROP if packet must be dropped. */ +static inline int nf_conntrack_confirm(struct sk_buff *skb) +{ + struct nf_conn *ct = (struct nf_conn *)skb->nfct; + int ret = NF_ACCEPT; + + if (ct && !nf_ct_is_untracked(ct)) { + if (!nf_ct_is_confirmed(ct)) + ret = __nf_conntrack_confirm(skb); + if (likely(ret == NF_ACCEPT)) + nf_ct_deliver_cached_events(ct); + } + return ret; +} + +int +print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_l3proto *l3proto, + const struct nf_conntrack_l4proto *proto); + +extern spinlock_t nf_conntrack_lock ; + +#endif /* _NF_CONNTRACK_CORE_H */ diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h new file mode 100644 index 00000000..96ba5f7d --- /dev/null +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -0,0 +1,239 @@ +/* + * connection tracking event cache. + */ + +#ifndef _NF_CONNTRACK_ECACHE_H +#define _NF_CONNTRACK_ECACHE_H +#include <net/netfilter/nf_conntrack.h> + +#include <net/net_namespace.h> +#include <net/netfilter/nf_conntrack_expect.h> +#include <linux/netfilter/nf_conntrack_common.h> +#include <linux/netfilter/nf_conntrack_tuple_common.h> +#include <net/netfilter/nf_conntrack_extend.h> + +struct nf_conntrack_ecache { + unsigned long cache; /* bitops want long */ + unsigned long missed; /* missed events */ + u16 ctmask; /* bitmask of ct events to be delivered */ + u16 expmask; /* bitmask of expect events to be delivered */ + u32 pid; /* netlink pid of destroyer */ +}; + +static inline struct nf_conntrack_ecache * +nf_ct_ecache_find(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE); +} + +static inline struct nf_conntrack_ecache * +nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp) +{ + struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *e; + + if (!ctmask && !expmask && net->ct.sysctl_events) { + ctmask = ~0; + expmask = ~0; + } + if (!ctmask && !expmask) + return NULL; + + e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); + if (e) { + e->ctmask = ctmask; + e->expmask = expmask; + } + return e; +}; + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +/* This structure is passed to event handler */ +struct nf_ct_event { + struct nf_conn *ct; + u32 pid; + int report; +}; + +struct nf_ct_event_notifier { + int (*fcn)(unsigned int events, struct nf_ct_event *item); +}; + +extern struct nf_ct_event_notifier *nf_conntrack_event_cb; +extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); +extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); + +extern void nf_ct_deliver_cached_events(struct nf_conn *ct); + +static inline void +nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) +{ + struct nf_conntrack_ecache *e; + + if (nf_conntrack_event_cb == NULL) + return; + + e = nf_ct_ecache_find(ct); + if (e == NULL) + return; + + if (!(e->ctmask & (1 << event))) + return; + + set_bit(event, &e->cache); +} + +static inline int +nf_conntrack_eventmask_report(unsigned int eventmask, + struct nf_conn *ct, + u32 pid, + int report) +{ + int ret = 0; + struct nf_ct_event_notifier *notify; + struct nf_conntrack_ecache *e; + + rcu_read_lock(); + notify = rcu_dereference(nf_conntrack_event_cb); + if (notify == NULL) + goto out_unlock; + + e = nf_ct_ecache_find(ct); + if (e == NULL) + goto out_unlock; + + if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { + struct nf_ct_event item = { + .ct = ct, + .pid = e->pid ? e->pid : pid, + .report = report + }; + /* This is a resent of a destroy event? If so, skip missed */ + unsigned long missed = e->pid ? 0 : e->missed; + + if (!((eventmask | missed) & e->ctmask)) + goto out_unlock; + + ret = notify->fcn(eventmask | missed, &item); + if (unlikely(ret < 0 || missed)) { + spin_lock_bh(&ct->lock); + if (ret < 0) { + /* This is a destroy event that has been + * triggered by a process, we store the PID + * to include it in the retransmission. */ + if (eventmask & (1 << IPCT_DESTROY) && + e->pid == 0 && pid != 0) + e->pid = pid; + else + e->missed |= eventmask; + } else + e->missed &= ~missed; + spin_unlock_bh(&ct->lock); + } + } +out_unlock: + rcu_read_unlock(); + return ret; +} + +static inline int +nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, + u32 pid, int report) +{ + return nf_conntrack_eventmask_report(1 << event, ct, pid, report); +} + +static inline int +nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) +{ + return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); +} + +struct nf_exp_event { + struct nf_conntrack_expect *exp; + u32 pid; + int report; +}; + +struct nf_exp_event_notifier { + int (*fcn)(unsigned int events, struct nf_exp_event *item); +}; + +extern struct nf_exp_event_notifier *nf_expect_event_cb; +extern int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *nb); +extern void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *nb); + +static inline void +nf_ct_expect_event_report(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp, + u32 pid, + int report) +{ + struct nf_exp_event_notifier *notify; + struct nf_conntrack_ecache *e; + + rcu_read_lock(); + notify = rcu_dereference(nf_expect_event_cb); + if (notify == NULL) + goto out_unlock; + + e = nf_ct_ecache_find(exp->master); + if (e == NULL) + goto out_unlock; + + if (e->expmask & (1 << event)) { + struct nf_exp_event item = { + .exp = exp, + .pid = pid, + .report = report + }; + notify->fcn(1 << event, &item); + } +out_unlock: + rcu_read_unlock(); +} + +static inline void +nf_ct_expect_event(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp) +{ + nf_ct_expect_event_report(event, exp, 0, 0); +} + +extern int nf_conntrack_ecache_init(struct net *net); +extern void nf_conntrack_ecache_fini(struct net *net); + +#else /* CONFIG_NF_CONNTRACK_EVENTS */ + +static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, + struct nf_conn *ct) {} +static inline int nf_conntrack_eventmask_report(unsigned int eventmask, + struct nf_conn *ct, + u32 pid, + int report) { return 0; } +static inline int nf_conntrack_event(enum ip_conntrack_events event, + struct nf_conn *ct) { return 0; } +static inline int nf_conntrack_event_report(enum ip_conntrack_events event, + struct nf_conn *ct, + u32 pid, + int report) { return 0; } +static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} +static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp) {} +static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, + struct nf_conntrack_expect *exp, + u32 pid, + int report) {} + +static inline int nf_conntrack_ecache_init(struct net *net) +{ + return 0; +} + +static inline void nf_conntrack_ecache_fini(struct net *net) +{ +} +#endif /* CONFIG_NF_CONNTRACK_EVENTS */ + +#endif /*_NF_CONNTRACK_ECACHE_H*/ + diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h new file mode 100644 index 00000000..11e81508 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -0,0 +1,108 @@ +/* + * connection tracking expectations. + */ + +#ifndef _NF_CONNTRACK_EXPECT_H +#define _NF_CONNTRACK_EXPECT_H +#include <net/netfilter/nf_conntrack.h> + +extern unsigned int nf_ct_expect_hsize; +extern unsigned int nf_ct_expect_max; + +struct nf_conntrack_expect { + /* Conntrack expectation list member */ + struct hlist_node lnode; + + /* Hash member */ + struct hlist_node hnode; + + /* We expect this tuple, with the following mask */ + struct nf_conntrack_tuple tuple; + struct nf_conntrack_tuple_mask mask; + + /* Function to call after setup and insertion */ + void (*expectfn)(struct nf_conn *new, + struct nf_conntrack_expect *this); + + /* Helper to assign to new connection */ + struct nf_conntrack_helper *helper; + + /* The conntrack of the master connection */ + struct nf_conn *master; + + /* Timer function; deletes the expectation. */ + struct timer_list timeout; + + /* Usage count. */ + atomic_t use; + + /* Flags */ + unsigned int flags; + + /* Expectation class */ + unsigned int class; + +#ifdef CONFIG_NF_NAT_NEEDED + __be32 saved_ip; + /* This is the original per-proto part, used to map the + * expected connection the way the recipient expects. */ + union nf_conntrack_man_proto saved_proto; + /* Direction relative to the master connection. */ + enum ip_conntrack_dir dir; +#endif + + struct rcu_head rcu; +}; + +static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp) +{ + return nf_ct_net(exp->master); +} + +struct nf_conntrack_expect_policy { + unsigned int max_expected; + unsigned int timeout; + const char *name; +}; + +#define NF_CT_EXPECT_CLASS_DEFAULT 0 + +#define NF_CT_EXPECT_PERMANENT 0x1 +#define NF_CT_EXPECT_INACTIVE 0x2 + +int nf_conntrack_expect_init(struct net *net); +void nf_conntrack_expect_fini(struct net *net); + +struct nf_conntrack_expect * +__nf_ct_expect_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +struct nf_conntrack_expect * +nf_ct_expect_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +struct nf_conntrack_expect * +nf_ct_find_expectation(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); +void nf_ct_remove_expectations(struct nf_conn *ct); +void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); + +/* Allocate space for an expectation: this is mandatory before calling + nf_ct_expect_related. You will have to call put afterwards. */ +struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me); +void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, u_int8_t, + const union nf_inet_addr *, + const union nf_inet_addr *, + u_int8_t, const __be16 *, const __be16 *); +void nf_ct_expect_put(struct nf_conntrack_expect *exp); +int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, + u32 pid, int report); +static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect) +{ + return nf_ct_expect_related_report(expect, 0, 0); +} + +#endif /*_NF_CONNTRACK_EXPECT_H*/ + diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h new file mode 100644 index 00000000..0772d296 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_extend.h @@ -0,0 +1,96 @@ +#ifndef _NF_CONNTRACK_EXTEND_H +#define _NF_CONNTRACK_EXTEND_H + +#include <linux/slab.h> + +#include <net/netfilter/nf_conntrack.h> + +enum nf_ct_ext_id { + NF_CT_EXT_HELPER, + NF_CT_EXT_NAT, + NF_CT_EXT_ACCT, + NF_CT_EXT_ECACHE, + NF_CT_EXT_ZONE, + NF_CT_EXT_NUM, +}; + +#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help +#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat +#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter +#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache +#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone + +/* Extensions: optional stuff which isn't permanently in struct. */ +struct nf_ct_ext { + struct rcu_head rcu; + u8 offset[NF_CT_EXT_NUM]; + u8 len; + char data[0]; +}; + +static inline bool __nf_ct_ext_exist(const struct nf_ct_ext *ext, u8 id) +{ + return !!ext->offset[id]; +} + +static inline bool nf_ct_ext_exist(const struct nf_conn *ct, u8 id) +{ + return (ct->ext && __nf_ct_ext_exist(ct->ext, id)); +} + +static inline void *__nf_ct_ext_find(const struct nf_conn *ct, u8 id) +{ + if (!nf_ct_ext_exist(ct, id)) + return NULL; + + return (void *)ct->ext + ct->ext->offset[id]; +} +#define nf_ct_ext_find(ext, id) \ + ((id##_TYPE *)__nf_ct_ext_find((ext), (id))) + +/* Destroy all relationships */ +extern void __nf_ct_ext_destroy(struct nf_conn *ct); +static inline void nf_ct_ext_destroy(struct nf_conn *ct) +{ + if (ct->ext) + __nf_ct_ext_destroy(ct); +} + +/* Free operation. If you want to free a object referred from private area, + * please implement __nf_ct_ext_free() and call it. + */ +static inline void nf_ct_ext_free(struct nf_conn *ct) +{ + if (ct->ext) + kfree(ct->ext); +} + +/* Add this type, returns pointer to data or NULL. */ +void * +__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp); +#define nf_ct_ext_add(ct, id, gfp) \ + ((id##_TYPE *)__nf_ct_ext_add((ct), (id), (gfp))) + +#define NF_CT_EXT_F_PREALLOC 0x0001 + +struct nf_ct_ext_type { + /* Destroys relationships (can be NULL). */ + void (*destroy)(struct nf_conn *ct); + /* Called when realloacted (can be NULL). + Contents has already been moved. */ + void (*move)(void *new, void *old); + + enum nf_ct_ext_id id; + + unsigned int flags; + + /* Length and min alignment. */ + u8 len; + u8 align; + /* initial size of nf_ct_ext. */ + u8 alloc_size; +}; + +int nf_ct_extend_register(struct nf_ct_ext_type *type); +void nf_ct_extend_unregister(struct nf_ct_ext_type *type); +#endif /* _NF_CONNTRACK_EXTEND_H */ diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h new file mode 100644 index 00000000..32c305db --- /dev/null +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -0,0 +1,66 @@ +/* + * connection tracking helpers. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_helper.h + */ + +#ifndef _NF_CONNTRACK_HELPER_H +#define _NF_CONNTRACK_HELPER_H +#include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_conntrack_extend.h> + +struct module; + +#define NF_CT_HELPER_NAME_LEN 16 + +struct nf_conntrack_helper { + struct hlist_node hnode; /* Internal use. */ + + const char *name; /* name of the module */ + struct module *me; /* pointer to self */ + const struct nf_conntrack_expect_policy *expect_policy; + + /* Tuple of things we will help (compared against server response) */ + struct nf_conntrack_tuple tuple; + + /* Function to call when data passes; return verdict, or -1 to + invalidate. */ + int (*help)(struct sk_buff *skb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info conntrackinfo); + + void (*destroy)(struct nf_conn *ct); + + int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct); + unsigned int expect_class_max; +}; + +extern struct nf_conntrack_helper * +__nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum); + +extern struct nf_conntrack_helper * +nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum); + +extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); +extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); + +extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); + +extern int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, + gfp_t flags); + +extern void nf_ct_helper_destroy(struct nf_conn *ct); + +static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); +} + +extern int nf_conntrack_helper_init(void); +extern void nf_conntrack_helper_fini(void); + +#endif /*_NF_CONNTRACK_HELPER_H*/ diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h new file mode 100644 index 00000000..a7547611 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -0,0 +1,95 @@ +/* + * Copyright (C)2003,2004 USAGI/WIDE Project + * + * Header for use in defining a given L3 protocol for connection tracking. + * + * Author: + * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> + * + * Derived from include/netfilter_ipv4/ip_conntrack_protocol.h + */ + +#ifndef _NF_CONNTRACK_L3PROTO_H +#define _NF_CONNTRACK_L3PROTO_H +#include <linux/netlink.h> +#include <net/netlink.h> +#include <linux/seq_file.h> +#include <net/netfilter/nf_conntrack.h> + +struct nf_conntrack_l3proto { + /* L3 Protocol Family number. ex) PF_INET */ + u_int16_t l3proto; + + /* Protocol name */ + const char *name; + + /* + * Try to fill in the third arg: nhoff is offset of l3 proto + * hdr. Return true if possible. + */ + bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int nhoff, + struct nf_conntrack_tuple *tuple); + + /* + * Invert the per-proto part of the tuple: ie. turn xmit into reply. + * Some packets can't be inverted: return 0 in that case. + */ + bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); + + /* Print out the per-protocol part of the tuple. */ + int (*print_tuple)(struct seq_file *s, + const struct nf_conntrack_tuple *); + + /* + * Called before tracking. + * *dataoff: offset of protocol header (TCP, UDP,...) in skb + * *protonum: protocol number + */ + int (*get_l4proto)(const struct sk_buff *skb, unsigned int nhoff, + unsigned int *dataoff, u_int8_t *protonum); + + int (*tuple_to_nlattr)(struct sk_buff *skb, + const struct nf_conntrack_tuple *t); + + /* + * Calculate size of tuple nlattr + */ + int (*nlattr_tuple_size)(void); + + int (*nlattr_to_tuple)(struct nlattr *tb[], + struct nf_conntrack_tuple *t); + const struct nla_policy *nla_policy; + + size_t nla_size; + +#ifdef CONFIG_SYSCTL + struct ctl_table_header *ctl_table_header; + struct ctl_path *ctl_table_path; + struct ctl_table *ctl_table; +#endif /* CONFIG_SYSCTL */ + + /* Module (if any) which this is connected to. */ + struct module *me; +}; + +extern struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX]; + +/* Protocol registration. */ +extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto); +extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto); +extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto); +extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p); + +/* Existing built-in protocols */ +extern struct nf_conntrack_l3proto nf_conntrack_l3proto_generic; + +static inline struct nf_conntrack_l3proto * +__nf_ct_l3proto_find(u_int16_t l3proto) +{ + if (unlikely(l3proto >= AF_MAX)) + return &nf_conntrack_l3proto_generic; + return rcu_dereference(nf_ct_l3protos[l3proto]); +} + +#endif /*_NF_CONNTRACK_L3PROTO_H*/ diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h new file mode 100644 index 00000000..e3d3ee3c --- /dev/null +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -0,0 +1,133 @@ +/* + * Header for use in defining a given L4 protocol for connection tracking. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> + * - generalized L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_protcol.h + */ + +#ifndef _NF_CONNTRACK_L4PROTO_H +#define _NF_CONNTRACK_L4PROTO_H +#include <linux/netlink.h> +#include <net/netlink.h> +#include <net/netfilter/nf_conntrack.h> + +struct seq_file; + +struct nf_conntrack_l4proto { + /* L3 Protocol number. */ + u_int16_t l3proto; + + /* L4 Protocol number. */ + u_int8_t l4proto; + + /* Try to fill in the third arg: dataoff is offset past network protocol + hdr. Return true if possible. */ + bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple); + + /* Invert the per-proto part of the tuple: ie. turn xmit into reply. + * Some packets can't be inverted: return 0 in that case. + */ + bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); + + /* Returns verdict for packet, or -1 for invalid. */ + int (*packet)(struct nf_conn *ct, + const struct sk_buff *skb, + unsigned int dataoff, + enum ip_conntrack_info ctinfo, + u_int8_t pf, + unsigned int hooknum); + + /* Called when a new connection for this protocol found; + * returns TRUE if it's OK. If so, packet() called next. */ + bool (*new)(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff); + + /* Called when a conntrack entry is destroyed */ + void (*destroy)(struct nf_conn *ct); + + int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, + unsigned int dataoff, enum ip_conntrack_info *ctinfo, + u_int8_t pf, unsigned int hooknum); + + /* Print out the per-protocol part of the tuple. Return like seq_* */ + int (*print_tuple)(struct seq_file *s, + const struct nf_conntrack_tuple *); + + /* Print out the private part of the conntrack. */ + int (*print_conntrack)(struct seq_file *s, struct nf_conn *); + + /* convert protoinfo to nfnetink attributes */ + int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, + struct nf_conn *ct); + /* Calculate protoinfo nlattr size */ + int (*nlattr_size)(void); + + /* convert nfnetlink attributes to protoinfo */ + int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); + + int (*tuple_to_nlattr)(struct sk_buff *skb, + const struct nf_conntrack_tuple *t); + /* Calculate tuple nlattr size */ + int (*nlattr_tuple_size)(void); + int (*nlattr_to_tuple)(struct nlattr *tb[], + struct nf_conntrack_tuple *t); + const struct nla_policy *nla_policy; + + size_t nla_size; + +#ifdef CONFIG_SYSCTL + struct ctl_table_header **ctl_table_header; + struct ctl_table *ctl_table; + unsigned int *ctl_table_users; +#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT + struct ctl_table_header *ctl_compat_table_header; + struct ctl_table *ctl_compat_table; +#endif +#endif + /* Protocol name */ + const char *name; + + /* Module (if any) which this is connected to. */ + struct module *me; +}; + +/* Existing built-in generic protocol */ +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; + +#define MAX_NF_CT_PROTO 256 + +extern struct nf_conntrack_l4proto * +__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto); + +/* Protocol registration. */ +extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto); +extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto); + +/* Generic netlink helpers */ +extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, + const struct nf_conntrack_tuple *tuple); +extern int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], + struct nf_conntrack_tuple *t); +extern int nf_ct_port_nlattr_tuple_size(void); +extern const struct nla_policy nf_ct_port_nla_policy[]; + +#ifdef CONFIG_SYSCTL +#ifdef DEBUG_INVALID_PACKETS +#define LOG_INVALID(net, proto) \ + ((net)->ct.sysctl_log_invalid == (proto) || \ + (net)->ct.sysctl_log_invalid == IPPROTO_RAW) +#else +#define LOG_INVALID(net, proto) \ + (((net)->ct.sysctl_log_invalid == (proto) || \ + (net)->ct.sysctl_log_invalid == IPPROTO_RAW) \ + && net_ratelimit()) +#endif +#else +static inline int LOG_INVALID(struct net *net, int proto) { return 0; } +#endif /* CONFIG_SYSCTL */ + +#endif /*_NF_CONNTRACK_PROTOCOL_H*/ diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h new file mode 100644 index 00000000..4ee44c84 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -0,0 +1,216 @@ +/* + * Definitions and Declarations for tuple. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_tuple.h + */ + +#ifndef _NF_CONNTRACK_TUPLE_H +#define _NF_CONNTRACK_TUPLE_H + +#include <linux/netfilter/x_tables.h> +#include <linux/netfilter/nf_conntrack_tuple_common.h> +#include <linux/list_nulls.h> + +/* A `tuple' is a structure containing the information to uniquely + identify a connection. ie. if two packets have the same tuple, they + are in the same connection; if not, they are not. + + We divide the structure along "manipulatable" and + "non-manipulatable" lines, for the benefit of the NAT code. +*/ + +#define NF_CT_TUPLE_L3SIZE ARRAY_SIZE(((union nf_inet_addr *)NULL)->all) + +/* The protocol-specific manipulable parts of the tuple: always in + network order! */ +union nf_conntrack_man_proto { + /* Add other protocols here. */ + __be16 all; + + struct { + __be16 port; + } tcp; + struct { + __be16 port; + } udp; + struct { + __be16 id; + } icmp; + struct { + __be16 port; + } dccp; + struct { + __be16 port; + } sctp; + struct { + __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */ + } gre; +}; + +/* The manipulable part of the tuple. */ +struct nf_conntrack_man { + union nf_inet_addr u3; + union nf_conntrack_man_proto u; + /* Layer 3 protocol */ + u_int16_t l3num; +}; + +/* This contains the information to distinguish a connection. */ +struct nf_conntrack_tuple { + struct nf_conntrack_man src; + + /* These are the parts of the tuple which are fixed. */ + struct { + union nf_inet_addr u3; + union { + /* Add other protocols here. */ + __be16 all; + + struct { + __be16 port; + } tcp; + struct { + __be16 port; + } udp; + struct { + u_int8_t type, code; + } icmp; + struct { + __be16 port; + } dccp; + struct { + __be16 port; + } sctp; + struct { + __be16 key; + } gre; + } u; + + /* The protocol. */ + u_int8_t protonum; + + /* The direction (for tuplehash) */ + u_int8_t dir; + } dst; +}; + +struct nf_conntrack_tuple_mask { + struct { + union nf_inet_addr u3; + union nf_conntrack_man_proto u; + } src; +}; + +#ifdef __KERNEL__ + +static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t) +{ +#ifdef DEBUG + printk("tuple %p: %u %pI4:%hu -> %pI4:%hu\n", + t, t->dst.protonum, + &t->src.u3.ip, ntohs(t->src.u.all), + &t->dst.u3.ip, ntohs(t->dst.u.all)); +#endif +} + +static inline void nf_ct_dump_tuple_ipv6(const struct nf_conntrack_tuple *t) +{ +#ifdef DEBUG + printk("tuple %p: %u %pI6 %hu -> %pI6 %hu\n", + t, t->dst.protonum, + t->src.u3.all, ntohs(t->src.u.all), + t->dst.u3.all, ntohs(t->dst.u.all)); +#endif +} + +static inline void nf_ct_dump_tuple(const struct nf_conntrack_tuple *t) +{ + switch (t->src.l3num) { + case AF_INET: + nf_ct_dump_tuple_ip(t); + break; + case AF_INET6: + nf_ct_dump_tuple_ipv6(t); + break; + } +} + +/* If we're the first tuple, it's the original dir. */ +#define NF_CT_DIRECTION(h) \ + ((enum ip_conntrack_dir)(h)->tuple.dst.dir) + +/* Connections have two entries in the hash table: one for each way */ +struct nf_conntrack_tuple_hash { + struct hlist_nulls_node hnnode; + struct nf_conntrack_tuple tuple; +}; + +#endif /* __KERNEL__ */ + +static inline bool __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) +{ + return (nf_inet_addr_cmp(&t1->src.u3, &t2->src.u3) && + t1->src.u.all == t2->src.u.all && + t1->src.l3num == t2->src.l3num); +} + +static inline bool __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) +{ + return (nf_inet_addr_cmp(&t1->dst.u3, &t2->dst.u3) && + t1->dst.u.all == t2->dst.u.all && + t1->dst.protonum == t2->dst.protonum); +} + +static inline bool nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) +{ + return __nf_ct_tuple_src_equal(t1, t2) && + __nf_ct_tuple_dst_equal(t1, t2); +} + +static inline bool +nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1, + const struct nf_conntrack_tuple_mask *m2) +{ + return (nf_inet_addr_cmp(&m1->src.u3, &m2->src.u3) && + m1->src.u.all == m2->src.u.all); +} + +static inline bool +nf_ct_tuple_src_mask_cmp(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2, + const struct nf_conntrack_tuple_mask *mask) +{ + int count; + + for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++) { + if ((t1->src.u3.all[count] ^ t2->src.u3.all[count]) & + mask->src.u3.all[count]) + return false; + } + + if ((t1->src.u.all ^ t2->src.u.all) & mask->src.u.all) + return false; + + if (t1->src.l3num != t2->src.l3num || + t1->dst.protonum != t2->dst.protonum) + return false; + + return true; +} + +static inline bool +nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple_mask *mask) +{ + return nf_ct_tuple_src_mask_cmp(t, tuple, mask) && + __nf_ct_tuple_dst_equal(t, tuple); +} + +#endif /* _NF_CONNTRACK_TUPLE_H */ diff --git a/include/net/netfilter/nf_conntrack_zones.h b/include/net/netfilter/nf_conntrack_zones.h new file mode 100644 index 00000000..034efe8d --- /dev/null +++ b/include/net/netfilter/nf_conntrack_zones.h @@ -0,0 +1,25 @@ +#ifndef _NF_CONNTRACK_ZONES_H +#define _NF_CONNTRACK_ZONES_H + +#define NF_CT_DEFAULT_ZONE 0 + +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +#include <net/netfilter/nf_conntrack_extend.h> + +struct nf_conntrack_zone { + u16 id; +}; + +static inline u16 nf_ct_zone(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_ZONES + struct nf_conntrack_zone *nf_ct_zone; + nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE); + if (nf_ct_zone) + return nf_ct_zone->id; +#endif + return NF_CT_DEFAULT_ZONE; +} + +#endif /* CONFIG_NF_CONNTRACK || CONFIG_NF_CONNTRACK_MODULE */ +#endif /* _NF_CONNTRACK_ZONES_H */ diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h new file mode 100644 index 00000000..920997f1 --- /dev/null +++ b/include/net/netfilter/nf_log.h @@ -0,0 +1,64 @@ +#ifndef _NF_LOG_H +#define _NF_LOG_H + +#include <linux/netfilter.h> + +/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will + * disappear once iptables is replaced with pkttables. Please DO NOT use them + * for any new code! */ +#define NF_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define NF_LOG_TCPOPT 0x02 /* Log TCP options */ +#define NF_LOG_IPOPT 0x04 /* Log IP options */ +#define NF_LOG_UID 0x08 /* Log UID owning local socket */ +#define NF_LOG_MASK 0x0f + +#define NF_LOG_TYPE_LOG 0x01 +#define NF_LOG_TYPE_ULOG 0x02 + +struct nf_loginfo { + u_int8_t type; + union { + struct { + u_int32_t copy_len; + u_int16_t group; + u_int16_t qthreshold; + } ulog; + struct { + u_int8_t level; + u_int8_t logflags; + } log; + } u; +}; + +typedef void nf_logfn(u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li, + const char *prefix); + +struct nf_logger { + struct module *me; + nf_logfn *logfn; + char *name; + struct list_head list[NFPROTO_NUMPROTO]; +}; + +/* Function to register/unregister log function. */ +int nf_log_register(u_int8_t pf, struct nf_logger *logger); +void nf_log_unregister(struct nf_logger *logger); + +int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger); +void nf_log_unbind_pf(u_int8_t pf); + +/* Calls the registered backend logging function */ +void nf_log_packet(u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li, + const char *fmt, ...) __attribute__ ((format(printf,7,8))); + +#endif /* _NF_LOG_H */ diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h new file mode 100644 index 00000000..f5f09f03 --- /dev/null +++ b/include/net/netfilter/nf_nat.h @@ -0,0 +1,93 @@ +#ifndef _NF_NAT_H +#define _NF_NAT_H +#include <linux/netfilter_ipv4.h> +#include <net/netfilter/nf_conntrack_tuple.h> + +#define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16 + +enum nf_nat_manip_type { + IP_NAT_MANIP_SRC, + IP_NAT_MANIP_DST +}; + +/* SRC manip occurs POST_ROUTING or LOCAL_IN */ +#define HOOK2MANIP(hooknum) ((hooknum) != NF_INET_POST_ROUTING && \ + (hooknum) != NF_INET_LOCAL_IN) + +#define IP_NAT_RANGE_MAP_IPS 1 +#define IP_NAT_RANGE_PROTO_SPECIFIED 2 +#define IP_NAT_RANGE_PROTO_RANDOM 4 +#define IP_NAT_RANGE_PERSISTENT 8 + +/* NAT sequence number modifications */ +struct nf_nat_seq { + /* position of the last TCP sequence number modification (if any) */ + u_int32_t correction_pos; + + /* sequence number offset before and after last modification */ + int16_t offset_before, offset_after; +}; + +/* Single range specification. */ +struct nf_nat_range { + /* Set to OR of flags above. */ + unsigned int flags; + + /* Inclusive: network order. */ + __be32 min_ip, max_ip; + + /* Inclusive: network order */ + union nf_conntrack_man_proto min, max; +}; + +/* For backwards compat: don't use in modern code. */ +struct nf_nat_multi_range_compat { + unsigned int rangesize; /* Must be 1. */ + + /* hangs off end. */ + struct nf_nat_range range[1]; +}; + +#ifdef __KERNEL__ +#include <linux/list.h> +#include <linux/netfilter/nf_conntrack_pptp.h> +#include <net/netfilter/nf_conntrack_extend.h> + +/* per conntrack: nat application helper private data */ +union nf_conntrack_nat_help { + /* insert nat helper private data here */ + struct nf_nat_pptp nat_pptp_info; +}; + +struct nf_conn; + +/* The structure embedded in the conntrack structure. */ +struct nf_conn_nat { + struct hlist_node bysource; + struct nf_nat_seq seq[IP_CT_DIR_MAX]; + struct nf_conn *ct; + union nf_conntrack_nat_help help; +#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ + defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) + int masq_index; +#endif +}; + +/* Set up the info structure to map into this range. */ +extern unsigned int nf_nat_setup_info(struct nf_conn *ct, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype); + +/* Is this tuple already taken? (not by us)*/ +extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack); + +static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_NAT); +} + +#else /* !__KERNEL__: iptables wants this to compile. */ +#define nf_nat_multi_range nf_nat_multi_range_compat +#endif /*__KERNEL__*/ +#endif diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h new file mode 100644 index 00000000..33602ab6 --- /dev/null +++ b/include/net/netfilter/nf_nat_core.h @@ -0,0 +1,36 @@ +#ifndef _NF_NAT_CORE_H +#define _NF_NAT_CORE_H +#include <linux/list.h> +#include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_nat.h> + +/* This header used to share core functionality between the standalone + NAT module, and the compatibility layer's use of NAT for masquerading. */ + +extern unsigned int nf_nat_packet(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff *skb); + +extern int nf_nat_icmp_reply_translation(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff *skb); + +static inline int nf_nat_initialized(struct nf_conn *ct, + enum nf_nat_manip_type manip) +{ + if (manip == IP_NAT_MANIP_SRC) + return test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); + else + return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status); +} + +struct nlattr; + +extern int +(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, + enum nf_nat_manip_type manip, + const struct nlattr *attr); + +#endif /* _NF_NAT_CORE_H */ diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h new file mode 100644 index 00000000..02bb6c29 --- /dev/null +++ b/include/net/netfilter/nf_nat_helper.h @@ -0,0 +1,57 @@ +#ifndef _NF_NAT_HELPER_H +#define _NF_NAT_HELPER_H +/* NAT protocol helper routines. */ + +#include <net/netfilter/nf_conntrack.h> + +struct sk_buff; + +/* These return true or false. */ +extern int __nf_nat_mangle_tcp_packet(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len, bool adjust); + +static inline int nf_nat_mangle_tcp_packet(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + return __nf_nat_mangle_tcp_packet(skb, ct, ctinfo, + match_offset, match_len, + rep_buffer, rep_len, true); +} + +extern int nf_nat_mangle_udp_packet(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len); + +extern void nf_nat_set_seq_adjust(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + __be32 seq, s16 off); +extern int nf_nat_seq_adjust(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); +extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); + +/* Setup NAT on this expected conntrack so it follows master, but goes + * to port ct->master->saved_proto. */ +extern void nf_nat_follow_master(struct nf_conn *ct, + struct nf_conntrack_expect *this); + +extern s16 nf_nat_get_offset(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq); +#endif diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h new file mode 100644 index 00000000..df17bac4 --- /dev/null +++ b/include/net/netfilter/nf_nat_protocol.h @@ -0,0 +1,77 @@ +/* Header for use in defining a given protocol. */ +#ifndef _NF_NAT_PROTOCOL_H +#define _NF_NAT_PROTOCOL_H +#include <net/netfilter/nf_nat.h> +#include <linux/netfilter/nfnetlink_conntrack.h> + +struct nf_nat_range; + +struct nf_nat_protocol { + /* Protocol number. */ + unsigned int protonum; + + struct module *me; + + /* Translate a packet to the target according to manip type. + Return true if succeeded. */ + bool (*manip_pkt)(struct sk_buff *skb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype); + + /* Is the manipable part of the tuple between min and max incl? */ + bool (*in_range)(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); + + /* Alter the per-proto part of the tuple (depending on + maniptype), to give a unique tuple in the given range if + possible. Per-protocol part of tuple is initialized to the + incoming packet. */ + void (*unique_tuple)(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct); + + int (*range_to_nlattr)(struct sk_buff *skb, + const struct nf_nat_range *range); + + int (*nlattr_to_range)(struct nlattr *tb[], + struct nf_nat_range *range); +}; + +/* Protocol registration. */ +extern int nf_nat_protocol_register(const struct nf_nat_protocol *proto); +extern void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto); + +extern const struct nf_nat_protocol *nf_nat_proto_find_get(u_int8_t protocol); +extern void nf_nat_proto_put(const struct nf_nat_protocol *proto); + +/* Built-in protocols. */ +extern const struct nf_nat_protocol nf_nat_protocol_tcp; +extern const struct nf_nat_protocol nf_nat_protocol_udp; +extern const struct nf_nat_protocol nf_nat_protocol_icmp; +extern const struct nf_nat_protocol nf_nat_unknown_protocol; + +extern int init_protocols(void) __init; +extern void cleanup_protocols(void); +extern const struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); + +extern bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); + +extern void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct, + u_int16_t *rover); + +extern int nf_nat_proto_range_to_nlattr(struct sk_buff *skb, + const struct nf_nat_range *range); +extern int nf_nat_proto_nlattr_to_range(struct nlattr *tb[], + struct nf_nat_range *range); + +#endif /*_NF_NAT_PROTO_H*/ diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h new file mode 100644 index 00000000..2890bdc4 --- /dev/null +++ b/include/net/netfilter/nf_nat_rule.h @@ -0,0 +1,15 @@ +#ifndef _NF_NAT_RULE_H +#define _NF_NAT_RULE_H +#include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_nat.h> +#include <linux/netfilter_ipv4/ip_tables.h> + +extern int nf_nat_rule_init(void) __init; +extern void nf_nat_rule_cleanup(void); +extern int nf_nat_rule_find(struct sk_buff *skb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + struct nf_conn *ct); + +#endif /* _NF_NAT_RULE_H */ diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h new file mode 100644 index 00000000..252fd101 --- /dev/null +++ b/include/net/netfilter/nf_queue.h @@ -0,0 +1,34 @@ +#ifndef _NF_QUEUE_H +#define _NF_QUEUE_H + +/* Each queued (to userspace) skbuff has one of these. */ +struct nf_queue_entry { + struct list_head list; + struct sk_buff *skb; + unsigned int id; + + struct nf_hook_ops *elem; + u_int8_t pf; + unsigned int hook; + struct net_device *indev; + struct net_device *outdev; + int (*okfn)(struct sk_buff *); +}; + +#define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry)) + +/* Packet queuing */ +struct nf_queue_handler { + int (*outfn)(struct nf_queue_entry *entry, + unsigned int queuenum); + char *name; +}; + +extern int nf_register_queue_handler(u_int8_t pf, + const struct nf_queue_handler *qh); +extern int nf_unregister_queue_handler(u_int8_t pf, + const struct nf_queue_handler *qh); +extern void nf_unregister_queue_handlers(const struct nf_queue_handler *qh); +extern void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); + +#endif /* _NF_QUEUE_H */ diff --git a/include/net/netfilter/nf_tproxy_core.h b/include/net/netfilter/nf_tproxy_core.h new file mode 100644 index 00000000..208b46f4 --- /dev/null +++ b/include/net/netfilter/nf_tproxy_core.h @@ -0,0 +1,32 @@ +#ifndef _NF_TPROXY_CORE_H +#define _NF_TPROXY_CORE_H + +#include <linux/types.h> +#include <linux/in.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <net/inet_sock.h> +#include <net/tcp.h> + +/* look up and get a reference to a matching socket */ +extern struct sock * +nf_tproxy_get_sock_v4(struct net *net, const u8 protocol, + const __be32 saddr, const __be32 daddr, + const __be16 sport, const __be16 dport, + const struct net_device *in, bool listening); + +static inline void +nf_tproxy_put_sock(struct sock *sk) +{ + /* TIME_WAIT inet sockets have to be handled differently */ + if ((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT)) + inet_twsk_put(inet_twsk(sk)); + else + sock_put(sk); +} + +/* assign a socket to the skb -- consumes sk */ +int +nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk); + +#endif diff --git a/include/net/netfilter/nfnetlink_log.h b/include/net/netfilter/nfnetlink_log.h new file mode 100644 index 00000000..e2dec42c --- /dev/null +++ b/include/net/netfilter/nfnetlink_log.h @@ -0,0 +1,16 @@ +#ifndef _KER_NFNETLINK_LOG_H +#define _KER_NFNETLINK_LOG_H + +void +nfulnl_log_packet(u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li_user, + const char *prefix); + +#define NFULNL_COPY_DISABLED 0xff + +#endif /* _KER_NFNETLINK_LOG_H */ + diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h new file mode 100644 index 00000000..5a2978d1 --- /dev/null +++ b/include/net/netfilter/xt_rateest.h @@ -0,0 +1,22 @@ +#ifndef _XT_RATEEST_H +#define _XT_RATEEST_H + +struct xt_rateest { + /* keep lock and bstats on same cache line to speedup xt_rateest_tg() */ + struct gnet_stats_basic_packed bstats; + spinlock_t lock; + /* keep rstats and lock on same cache line to speedup xt_rateest_mt() */ + struct gnet_stats_rate_est rstats; + + /* following fields not accessed in hot path */ + struct hlist_node list; + char name[IFNAMSIZ]; + unsigned int refcnt; + struct gnet_estimator params; + struct rcu_head rcu; +}; + +extern struct xt_rateest *xt_rateest_lookup(const char *name); +extern void xt_rateest_put(struct xt_rateest *est); + +#endif /* _XT_RATEEST_H */ diff --git a/include/net/netlabel.h b/include/net/netlabel.h new file mode 100644 index 00000000..9db401a8 --- /dev/null +++ b/include/net/netlabel.h @@ -0,0 +1,590 @@ +/* + * NetLabel System + * + * The NetLabel system manages static and dynamic label mappings for network + * protocols such as CIPSO and RIPSO. + * + * Author: Paul Moore <paul.moore@hp.com> + * + */ + +/* + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _NETLABEL_H +#define _NETLABEL_H + +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/net.h> +#include <linux/skbuff.h> +#include <linux/in.h> +#include <linux/in6.h> +#include <net/netlink.h> +#include <net/request_sock.h> +#include <asm/atomic.h> + +struct cipso_v4_doi; + +/* + * NetLabel - A management interface for maintaining network packet label + * mapping tables for explicit packet labling protocols. + * + * Network protocols such as CIPSO and RIPSO require a label translation layer + * to convert the label on the packet into something meaningful on the host + * machine. In the current Linux implementation these mapping tables live + * inside the kernel; NetLabel provides a mechanism for user space applications + * to manage these mapping tables. + * + * NetLabel makes use of the Generic NETLINK mechanism as a transport layer to + * send messages between kernel and user space. The general format of a + * NetLabel message is shown below: + * + * +-----------------+-------------------+--------- --- -- - + * | struct nlmsghdr | struct genlmsghdr | payload + * +-----------------+-------------------+--------- --- -- - + * + * The 'nlmsghdr' and 'genlmsghdr' structs should be dealt with like normal. + * The payload is dependent on the subsystem specified in the + * 'nlmsghdr->nlmsg_type' and should be defined below, supporting functions + * should be defined in the corresponding net/netlabel/netlabel_<subsys>.h|c + * file. All of the fields in the NetLabel payload are NETLINK attributes, see + * the include/net/netlink.h file for more information on NETLINK attributes. + * + */ + +/* + * NetLabel NETLINK protocol + */ + +/* NetLabel NETLINK protocol version + * 1: initial version + * 2: added static labels for unlabeled connections + * 3: network selectors added to the NetLabel/LSM domain mapping and the + * CIPSO_V4_MAP_LOCAL CIPSO mapping was added + */ +#define NETLBL_PROTO_VERSION 3 + +/* NetLabel NETLINK types/families */ +#define NETLBL_NLTYPE_NONE 0 +#define NETLBL_NLTYPE_MGMT 1 +#define NETLBL_NLTYPE_MGMT_NAME "NLBL_MGMT" +#define NETLBL_NLTYPE_RIPSO 2 +#define NETLBL_NLTYPE_RIPSO_NAME "NLBL_RIPSO" +#define NETLBL_NLTYPE_CIPSOV4 3 +#define NETLBL_NLTYPE_CIPSOV4_NAME "NLBL_CIPSOv4" +#define NETLBL_NLTYPE_CIPSOV6 4 +#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6" +#define NETLBL_NLTYPE_UNLABELED 5 +#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" +#define NETLBL_NLTYPE_ADDRSELECT 6 +#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL" + +/* + * NetLabel - Kernel API for accessing the network packet label mappings. + * + * The following functions are provided for use by other kernel modules, + * specifically kernel LSM modules, to provide a consistent, transparent API + * for dealing with explicit packet labeling protocols such as CIPSO and + * RIPSO. The functions defined here are implemented in the + * net/netlabel/netlabel_kapi.c file. + * + */ + +/* NetLabel audit information */ +struct netlbl_audit { + u32 secid; + uid_t loginuid; + u32 sessionid; +}; + +/* + * LSM security attributes + */ + +/** + * struct netlbl_lsm_cache - NetLabel LSM security attribute cache + * @refcount: atomic reference counter + * @free: LSM supplied function to free the cache data + * @data: LSM supplied cache data + * + * Description: + * This structure is provided for LSMs which wish to make use of the NetLabel + * caching mechanism to store LSM specific data/attributes in the NetLabel + * cache. If the LSM has to perform a lot of translation from the NetLabel + * security attributes into it's own internal representation then the cache + * mechanism can provide a way to eliminate some or all of that translation + * overhead on a cache hit. + * + */ +struct netlbl_lsm_cache { + atomic_t refcount; + void (*free) (const void *data); + void *data; +}; + +/** + * struct netlbl_lsm_secattr_catmap - NetLabel LSM secattr category bitmap + * @startbit: the value of the lowest order bit in the bitmap + * @bitmap: the category bitmap + * @next: pointer to the next bitmap "node" or NULL + * + * Description: + * This structure is used to represent category bitmaps. Due to the large + * number of categories supported by most labeling protocols it is not + * practical to transfer a full bitmap internally so NetLabel adopts a sparse + * bitmap structure modeled after SELinux's ebitmap structure. + * The catmap bitmap field MUST be a power of two in length and large + * enough to hold at least 240 bits. Special care (i.e. check the code!) + * should be used when changing these values as the LSM implementation + * probably has functions which rely on the sizes of these types to speed + * processing. + * + */ +#define NETLBL_CATMAP_MAPTYPE u64 +#define NETLBL_CATMAP_MAPCNT 4 +#define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8) +#define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \ + NETLBL_CATMAP_MAPCNT) +#define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01 +struct netlbl_lsm_secattr_catmap { + u32 startbit; + NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; + struct netlbl_lsm_secattr_catmap *next; +}; + +/** + * struct netlbl_lsm_secattr - NetLabel LSM security attributes + * @flags: indicate structure attributes, see NETLBL_SECATTR_* + * @type: indicate the NLTYPE of the attributes + * @domain: the NetLabel LSM domain + * @cache: NetLabel LSM specific cache + * @attr.mls: MLS sensitivity label + * @attr.mls.cat: MLS category bitmap + * @attr.mls.lvl: MLS sensitivity level + * @attr.secid: LSM specific secid token + * + * Description: + * This structure is used to pass security attributes between NetLabel and the + * LSM modules. The flags field is used to specify which fields within the + * struct are valid and valid values can be created by bitwise OR'ing the + * NETLBL_SECATTR_* defines. The domain field is typically set by the LSM to + * specify domain specific configuration settings and is not usually used by + * NetLabel itself when returning security attributes to the LSM. + * + */ +struct netlbl_lsm_secattr { + u32 flags; + /* bitmap values for 'flags' */ +#define NETLBL_SECATTR_NONE 0x00000000 +#define NETLBL_SECATTR_DOMAIN 0x00000001 +#define NETLBL_SECATTR_DOMAIN_CPY (NETLBL_SECATTR_DOMAIN | \ + NETLBL_SECATTR_FREE_DOMAIN) +#define NETLBL_SECATTR_CACHE 0x00000002 +#define NETLBL_SECATTR_MLS_LVL 0x00000004 +#define NETLBL_SECATTR_MLS_CAT 0x00000008 +#define NETLBL_SECATTR_SECID 0x00000010 + /* bitmap meta-values for 'flags' */ +#define NETLBL_SECATTR_FREE_DOMAIN 0x01000000 +#define NETLBL_SECATTR_CACHEABLE (NETLBL_SECATTR_MLS_LVL | \ + NETLBL_SECATTR_MLS_CAT | \ + NETLBL_SECATTR_SECID) + u32 type; + char *domain; + struct netlbl_lsm_cache *cache; + struct { + struct { + struct netlbl_lsm_secattr_catmap *cat; + u32 lvl; + } mls; + u32 secid; + } attr; +}; + +/* + * LSM security attribute operations (inline) + */ + +/** + * netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache + * @flags: the memory allocation flags + * + * Description: + * Allocate and initialize a netlbl_lsm_cache structure. Returns a pointer + * on success, NULL on failure. + * + */ +static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(gfp_t flags) +{ + struct netlbl_lsm_cache *cache; + + cache = kzalloc(sizeof(*cache), flags); + if (cache) + atomic_set(&cache->refcount, 1); + return cache; +} + +/** + * netlbl_secattr_cache_free - Frees a netlbl_lsm_cache struct + * @cache: the struct to free + * + * Description: + * Frees @secattr including all of the internal buffers. + * + */ +static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache) +{ + if (!atomic_dec_and_test(&cache->refcount)) + return; + + if (cache->free) + cache->free(cache->data); + kfree(cache); +} + +/** + * netlbl_secattr_catmap_alloc - Allocate a LSM secattr catmap + * @flags: memory allocation flags + * + * Description: + * Allocate memory for a LSM secattr catmap, returns a pointer on success, NULL + * on failure. + * + */ +static inline struct netlbl_lsm_secattr_catmap *netlbl_secattr_catmap_alloc( + gfp_t flags) +{ + return kzalloc(sizeof(struct netlbl_lsm_secattr_catmap), flags); +} + +/** + * netlbl_secattr_catmap_free - Free a LSM secattr catmap + * @catmap: the category bitmap + * + * Description: + * Free a LSM secattr catmap. + * + */ +static inline void netlbl_secattr_catmap_free( + struct netlbl_lsm_secattr_catmap *catmap) +{ + struct netlbl_lsm_secattr_catmap *iter; + + do { + iter = catmap; + catmap = catmap->next; + kfree(iter); + } while (catmap); +} + +/** + * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct + * @secattr: the struct to initialize + * + * Description: + * Initialize an already allocated netlbl_lsm_secattr struct. + * + */ +static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr) +{ + memset(secattr, 0, sizeof(*secattr)); +} + +/** + * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct + * @secattr: the struct to clear + * + * Description: + * Destroys the @secattr struct, including freeing all of the internal buffers. + * The struct must be reset with a call to netlbl_secattr_init() before reuse. + * + */ +static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr) +{ + if (secattr->flags & NETLBL_SECATTR_FREE_DOMAIN) + kfree(secattr->domain); + if (secattr->flags & NETLBL_SECATTR_CACHE) + netlbl_secattr_cache_free(secattr->cache); + if (secattr->flags & NETLBL_SECATTR_MLS_CAT) + netlbl_secattr_catmap_free(secattr->attr.mls.cat); +} + +/** + * netlbl_secattr_alloc - Allocate and initialize a netlbl_lsm_secattr struct + * @flags: the memory allocation flags + * + * Description: + * Allocate and initialize a netlbl_lsm_secattr struct. Returns a valid + * pointer on success, or NULL on failure. + * + */ +static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(gfp_t flags) +{ + return kzalloc(sizeof(struct netlbl_lsm_secattr), flags); +} + +/** + * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct + * @secattr: the struct to free + * + * Description: + * Frees @secattr including all of the internal buffers. + * + */ +static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr) +{ + netlbl_secattr_destroy(secattr); + kfree(secattr); +} + +#ifdef CONFIG_NETLABEL +/* + * LSM configuration operations + */ +int netlbl_cfg_map_del(const char *domain, + u16 family, + const void *addr, + const void *mask, + struct netlbl_audit *audit_info); +int netlbl_cfg_unlbl_map_add(const char *domain, + u16 family, + const void *addr, + const void *mask, + struct netlbl_audit *audit_info); +int netlbl_cfg_unlbl_static_add(struct net *net, + const char *dev_name, + const void *addr, + const void *mask, + u16 family, + u32 secid, + struct netlbl_audit *audit_info); +int netlbl_cfg_unlbl_static_del(struct net *net, + const char *dev_name, + const void *addr, + const void *mask, + u16 family, + struct netlbl_audit *audit_info); +int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, + struct netlbl_audit *audit_info); +void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info); +int netlbl_cfg_cipsov4_map_add(u32 doi, + const char *domain, + const struct in_addr *addr, + const struct in_addr *mask, + struct netlbl_audit *audit_info); +/* + * LSM security attribute operations + */ +int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, + u32 offset); +int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, + u32 offset); +int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, + u32 bit, + gfp_t flags); +int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, + u32 start, + u32 end, + gfp_t flags); + +/* + * LSM protocol operations (NetLabel LSM/kernel API) + */ +int netlbl_enabled(void); +int netlbl_sock_setattr(struct sock *sk, + u16 family, + const struct netlbl_lsm_secattr *secattr); +void netlbl_sock_delattr(struct sock *sk); +int netlbl_sock_getattr(struct sock *sk, + struct netlbl_lsm_secattr *secattr); +int netlbl_conn_setattr(struct sock *sk, + struct sockaddr *addr, + const struct netlbl_lsm_secattr *secattr); +int netlbl_req_setattr(struct request_sock *req, + const struct netlbl_lsm_secattr *secattr); +void netlbl_req_delattr(struct request_sock *req); +int netlbl_skbuff_setattr(struct sk_buff *skb, + u16 family, + const struct netlbl_lsm_secattr *secattr); +int netlbl_skbuff_getattr(const struct sk_buff *skb, + u16 family, + struct netlbl_lsm_secattr *secattr); +void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway); + +/* + * LSM label mapping cache operations + */ +void netlbl_cache_invalidate(void); +int netlbl_cache_add(const struct sk_buff *skb, + const struct netlbl_lsm_secattr *secattr); + +/* + * Protocol engine operations + */ +struct audit_buffer *netlbl_audit_start(int type, + struct netlbl_audit *audit_info); +#else +static inline int netlbl_cfg_map_del(const char *domain, + u16 family, + const void *addr, + const void *mask, + struct netlbl_audit *audit_info) +{ + return -ENOSYS; +} +static inline int netlbl_cfg_unlbl_map_add(const char *domain, + u16 family, + void *addr, + void *mask, + struct netlbl_audit *audit_info) +{ + return -ENOSYS; +} +static inline int netlbl_cfg_unlbl_static_add(struct net *net, + const char *dev_name, + const void *addr, + const void *mask, + u16 family, + u32 secid, + struct netlbl_audit *audit_info) +{ + return -ENOSYS; +} +static inline int netlbl_cfg_unlbl_static_del(struct net *net, + const char *dev_name, + const void *addr, + const void *mask, + u16 family, + struct netlbl_audit *audit_info) +{ + return -ENOSYS; +} +static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, + struct netlbl_audit *audit_info) +{ + return -ENOSYS; +} +static inline void netlbl_cfg_cipsov4_del(u32 doi, + struct netlbl_audit *audit_info) +{ + return; +} +static inline int netlbl_cfg_cipsov4_map_add(u32 doi, + const char *domain, + const struct in_addr *addr, + const struct in_addr *mask, + struct netlbl_audit *audit_info) +{ + return -ENOSYS; +} +static inline int netlbl_secattr_catmap_walk( + struct netlbl_lsm_secattr_catmap *catmap, + u32 offset) +{ + return -ENOENT; +} +static inline int netlbl_secattr_catmap_walk_rng( + struct netlbl_lsm_secattr_catmap *catmap, + u32 offset) +{ + return -ENOENT; +} +static inline int netlbl_secattr_catmap_setbit( + struct netlbl_lsm_secattr_catmap *catmap, + u32 bit, + gfp_t flags) +{ + return 0; +} +static inline int netlbl_secattr_catmap_setrng( + struct netlbl_lsm_secattr_catmap *catmap, + u32 start, + u32 end, + gfp_t flags) +{ + return 0; +} +static inline int netlbl_enabled(void) +{ + return 0; +} +static inline int netlbl_sock_setattr(struct sock *sk, + u16 family, + const struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} +static inline void netlbl_sock_delattr(struct sock *sk) +{ +} +static inline int netlbl_sock_getattr(struct sock *sk, + struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} +static inline int netlbl_conn_setattr(struct sock *sk, + struct sockaddr *addr, + const struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} +static inline int netlbl_req_setattr(struct request_sock *req, + const struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} +static inline void netlbl_req_delattr(struct request_sock *req) +{ + return; +} +static inline int netlbl_skbuff_setattr(struct sk_buff *skb, + u16 family, + const struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} +static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, + u16 family, + struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} +static inline void netlbl_skbuff_err(struct sk_buff *skb, + int error, + int gateway) +{ + return; +} +static inline void netlbl_cache_invalidate(void) +{ + return; +} +static inline int netlbl_cache_add(const struct sk_buff *skb, + const struct netlbl_lsm_secattr *secattr) +{ + return 0; +} +static inline struct audit_buffer *netlbl_audit_start(int type, + struct netlbl_audit *audit_info) +{ + return NULL; +} +#endif /* CONFIG_NETLABEL */ + +#endif /* _NETLABEL_H */ diff --git a/include/net/netlink.h b/include/net/netlink.h new file mode 100644 index 00000000..f3b201d3 --- /dev/null +++ b/include/net/netlink.h @@ -0,0 +1,1062 @@ +#ifndef __NET_NETLINK_H +#define __NET_NETLINK_H + +#include <linux/types.h> +#include <linux/netlink.h> +#include <linux/jiffies.h> + +/* ======================================================================== + * Netlink Messages and Attributes Interface (As Seen On TV) + * ------------------------------------------------------------------------ + * Messages Interface + * ------------------------------------------------------------------------ + * + * Message Format: + * <--- nlmsg_total_size(payload) ---> + * <-- nlmsg_msg_size(payload) -> + * +----------+- - -+-------------+- - -+-------- - - + * | nlmsghdr | Pad | Payload | Pad | nlmsghdr + * +----------+- - -+-------------+- - -+-------- - - + * nlmsg_data(nlh)---^ ^ + * nlmsg_next(nlh)-----------------------+ + * + * Payload Format: + * <---------------------- nlmsg_len(nlh) ---------------------> + * <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) -> + * +----------------------+- - -+--------------------------------+ + * | Family Header | Pad | Attributes | + * +----------------------+- - -+--------------------------------+ + * nlmsg_attrdata(nlh, hdrlen)---^ + * + * Data Structures: + * struct nlmsghdr netlink message header + * + * Message Construction: + * nlmsg_new() create a new netlink message + * nlmsg_put() add a netlink message to an skb + * nlmsg_put_answer() callback based nlmsg_put() + * nlmsg_end() finalize netlink message + * nlmsg_get_pos() return current position in message + * nlmsg_trim() trim part of message + * nlmsg_cancel() cancel message construction + * nlmsg_free() free a netlink message + * + * Message Sending: + * nlmsg_multicast() multicast message to several groups + * nlmsg_unicast() unicast a message to a single socket + * nlmsg_notify() send notification message + * + * Message Length Calculations: + * nlmsg_msg_size(payload) length of message w/o padding + * nlmsg_total_size(payload) length of message w/ padding + * nlmsg_padlen(payload) length of padding at tail + * + * Message Payload Access: + * nlmsg_data(nlh) head of message payload + * nlmsg_len(nlh) length of message payload + * nlmsg_attrdata(nlh, hdrlen) head of attributes data + * nlmsg_attrlen(nlh, hdrlen) length of attributes data + * + * Message Parsing: + * nlmsg_ok(nlh, remaining) does nlh fit into remaining bytes? + * nlmsg_next(nlh, remaining) get next netlink message + * nlmsg_parse() parse attributes of a message + * nlmsg_find_attr() find an attribute in a message + * nlmsg_for_each_msg() loop over all messages + * nlmsg_validate() validate netlink message incl. attrs + * nlmsg_for_each_attr() loop over all attributes + * + * Misc: + * nlmsg_report() report back to application? + * + * ------------------------------------------------------------------------ + * Attributes Interface + * ------------------------------------------------------------------------ + * + * Attribute Format: + * <------- nla_total_size(payload) -------> + * <---- nla_attr_size(payload) -----> + * +----------+- - -+- - - - - - - - - +- - -+-------- - - + * | Header | Pad | Payload | Pad | Header + * +----------+- - -+- - - - - - - - - +- - -+-------- - - + * <- nla_len(nla) -> ^ + * nla_data(nla)----^ | + * nla_next(nla)-----------------------------' + * + * Data Structures: + * struct nlattr netlink attribute header + * + * Attribute Construction: + * nla_reserve(skb, type, len) reserve room for an attribute + * nla_reserve_nohdr(skb, len) reserve room for an attribute w/o hdr + * nla_put(skb, type, len, data) add attribute to skb + * nla_put_nohdr(skb, len, data) add attribute w/o hdr + * nla_append(skb, len, data) append data to skb + * + * Attribute Construction for Basic Types: + * nla_put_u8(skb, type, value) add u8 attribute to skb + * nla_put_u16(skb, type, value) add u16 attribute to skb + * nla_put_u32(skb, type, value) add u32 attribute to skb + * nla_put_u64(skb, type, value) add u64 attribute to skb + * nla_put_string(skb, type, str) add string attribute to skb + * nla_put_flag(skb, type) add flag attribute to skb + * nla_put_msecs(skb, type, jiffies) add msecs attribute to skb + * + * Exceptions Based Attribute Construction: + * NLA_PUT(skb, type, len, data) add attribute to skb + * NLA_PUT_U8(skb, type, value) add u8 attribute to skb + * NLA_PUT_U16(skb, type, value) add u16 attribute to skb + * NLA_PUT_U32(skb, type, value) add u32 attribute to skb + * NLA_PUT_U64(skb, type, value) add u64 attribute to skb + * NLA_PUT_STRING(skb, type, str) add string attribute to skb + * NLA_PUT_FLAG(skb, type) add flag attribute to skb + * NLA_PUT_MSECS(skb, type, jiffies) add msecs attribute to skb + * + * The meaning of these functions is equal to their lower case + * variants but they jump to the label nla_put_failure in case + * of a failure. + * + * Nested Attributes Construction: + * nla_nest_start(skb, type) start a nested attribute + * nla_nest_end(skb, nla) finalize a nested attribute + * nla_nest_cancel(skb, nla) cancel nested attribute construction + * + * Attribute Length Calculations: + * nla_attr_size(payload) length of attribute w/o padding + * nla_total_size(payload) length of attribute w/ padding + * nla_padlen(payload) length of padding + * + * Attribute Payload Access: + * nla_data(nla) head of attribute payload + * nla_len(nla) length of attribute payload + * + * Attribute Payload Access for Basic Types: + * nla_get_u8(nla) get payload for a u8 attribute + * nla_get_u16(nla) get payload for a u16 attribute + * nla_get_u32(nla) get payload for a u32 attribute + * nla_get_u64(nla) get payload for a u64 attribute + * nla_get_flag(nla) return 1 if flag is true + * nla_get_msecs(nla) get payload for a msecs attribute + * + * Attribute Misc: + * nla_memcpy(dest, nla, count) copy attribute into memory + * nla_memcmp(nla, data, size) compare attribute with memory area + * nla_strlcpy(dst, nla, size) copy attribute to a sized string + * nla_strcmp(nla, str) compare attribute with string + * + * Attribute Parsing: + * nla_ok(nla, remaining) does nla fit into remaining bytes? + * nla_next(nla, remaining) get next netlink attribute + * nla_validate() validate a stream of attributes + * nla_validate_nested() validate a stream of nested attributes + * nla_find() find attribute in stream of attributes + * nla_find_nested() find attribute in nested attributes + * nla_parse() parse and validate stream of attrs + * nla_parse_nested() parse nested attribuets + * nla_for_each_attr() loop over all attributes + * nla_for_each_nested() loop over the nested attributes + *========================================================================= + */ + + /** + * Standard attribute types to specify validation policy + */ +enum { + NLA_UNSPEC, + NLA_U8, + NLA_U16, + NLA_U32, + NLA_U64, + NLA_STRING, + NLA_FLAG, + NLA_MSECS, + NLA_NESTED, + NLA_NESTED_COMPAT, + NLA_NUL_STRING, + NLA_BINARY, + __NLA_TYPE_MAX, +}; + +#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) + +/** + * struct nla_policy - attribute validation policy + * @type: Type of attribute or NLA_UNSPEC + * @len: Type specific length of payload + * + * Policies are defined as arrays of this struct, the array must be + * accessible by attribute type up to the highest identifier to be expected. + * + * Meaning of `len' field: + * NLA_STRING Maximum length of string + * NLA_NUL_STRING Maximum length of string (excluding NUL) + * NLA_FLAG Unused + * NLA_BINARY Maximum length of attribute payload + * NLA_NESTED_COMPAT Exact length of structure payload + * All other Exact length of attribute payload + * + * Example: + * static const struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_FOO] = { .type = NLA_U16 }, + * [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ }, + * [ATTR_BAZ] = { .len = sizeof(struct mystruct) }, + * }; + */ +struct nla_policy { + u16 type; + u16 len; +}; + +/** + * struct nl_info - netlink source information + * @nlh: Netlink message header of original request + * @pid: Netlink PID of requesting application + */ +struct nl_info { + struct nlmsghdr *nlh; + struct net *nl_net; + u32 pid; +}; + +extern int netlink_rcv_skb(struct sk_buff *skb, + int (*cb)(struct sk_buff *, + struct nlmsghdr *)); +extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb, + u32 pid, unsigned int group, int report, + gfp_t flags); + +extern int nla_validate(struct nlattr *head, int len, int maxtype, + const struct nla_policy *policy); +extern int nla_parse(struct nlattr *tb[], int maxtype, + struct nlattr *head, int len, + const struct nla_policy *policy); +extern int nla_policy_len(const struct nla_policy *, int); +extern struct nlattr * nla_find(struct nlattr *head, int len, int attrtype); +extern size_t nla_strlcpy(char *dst, const struct nlattr *nla, + size_t dstsize); +extern int nla_memcpy(void *dest, const struct nlattr *src, int count); +extern int nla_memcmp(const struct nlattr *nla, const void *data, + size_t size); +extern int nla_strcmp(const struct nlattr *nla, const char *str); +extern struct nlattr * __nla_reserve(struct sk_buff *skb, int attrtype, + int attrlen); +extern void * __nla_reserve_nohdr(struct sk_buff *skb, int attrlen); +extern struct nlattr * nla_reserve(struct sk_buff *skb, int attrtype, + int attrlen); +extern void * nla_reserve_nohdr(struct sk_buff *skb, int attrlen); +extern void __nla_put(struct sk_buff *skb, int attrtype, + int attrlen, const void *data); +extern void __nla_put_nohdr(struct sk_buff *skb, int attrlen, + const void *data); +extern int nla_put(struct sk_buff *skb, int attrtype, + int attrlen, const void *data); +extern int nla_put_nohdr(struct sk_buff *skb, int attrlen, + const void *data); +extern int nla_append(struct sk_buff *skb, int attrlen, + const void *data); + +/************************************************************************** + * Netlink Messages + **************************************************************************/ + +/** + * nlmsg_msg_size - length of netlink message not including padding + * @payload: length of message payload + */ +static inline int nlmsg_msg_size(int payload) +{ + return NLMSG_HDRLEN + payload; +} + +/** + * nlmsg_total_size - length of netlink message including padding + * @payload: length of message payload + */ +static inline int nlmsg_total_size(int payload) +{ + return NLMSG_ALIGN(nlmsg_msg_size(payload)); +} + +/** + * nlmsg_padlen - length of padding at the message's tail + * @payload: length of message payload + */ +static inline int nlmsg_padlen(int payload) +{ + return nlmsg_total_size(payload) - nlmsg_msg_size(payload); +} + +/** + * nlmsg_data - head of message payload + * @nlh: netlink messsage header + */ +static inline void *nlmsg_data(const struct nlmsghdr *nlh) +{ + return (unsigned char *) nlh + NLMSG_HDRLEN; +} + +/** + * nlmsg_len - length of message payload + * @nlh: netlink message header + */ +static inline int nlmsg_len(const struct nlmsghdr *nlh) +{ + return nlh->nlmsg_len - NLMSG_HDRLEN; +} + +/** + * nlmsg_attrdata - head of attributes data + * @nlh: netlink message header + * @hdrlen: length of family specific header + */ +static inline struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, + int hdrlen) +{ + unsigned char *data = nlmsg_data(nlh); + return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); +} + +/** + * nlmsg_attrlen - length of attributes data + * @nlh: netlink message header + * @hdrlen: length of family specific header + */ +static inline int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) +{ + return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen); +} + +/** + * nlmsg_ok - check if the netlink message fits into the remaining bytes + * @nlh: netlink message header + * @remaining: number of bytes remaining in message stream + */ +static inline int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) +{ + return (remaining >= (int) sizeof(struct nlmsghdr) && + nlh->nlmsg_len >= sizeof(struct nlmsghdr) && + nlh->nlmsg_len <= remaining); +} + +/** + * nlmsg_next - next netlink message in message stream + * @nlh: netlink message header + * @remaining: number of bytes remaining in message stream + * + * Returns the next netlink message in the message stream and + * decrements remaining by the size of the current message. + */ +static inline struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) +{ + int totlen = NLMSG_ALIGN(nlh->nlmsg_len); + + *remaining -= totlen; + + return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); +} + +/** + * nlmsg_parse - parse attributes of a netlink message + * @nlh: netlink message header + * @hdrlen: length of family specific header + * @tb: destination array with maxtype+1 elements + * @maxtype: maximum attribute type to be expected + * @policy: validation policy + * + * See nla_parse() + */ +static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, + struct nlattr *tb[], int maxtype, + const struct nla_policy *policy) +{ + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + return -EINVAL; + + return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), policy); +} + +/** + * nlmsg_find_attr - find a specific attribute in a netlink message + * @nlh: netlink message header + * @hdrlen: length of familiy specific header + * @attrtype: type of attribute to look for + * + * Returns the first attribute which matches the specified type. + */ +static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, + int hdrlen, int attrtype) +{ + return nla_find(nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), attrtype); +} + +/** + * nlmsg_validate - validate a netlink message including attributes + * @nlh: netlinket message header + * @hdrlen: length of familiy specific header + * @maxtype: maximum attribute type to be expected + * @policy: validation policy + */ +static inline int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, + const struct nla_policy *policy) +{ + if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) + return -EINVAL; + + return nla_validate(nlmsg_attrdata(nlh, hdrlen), + nlmsg_attrlen(nlh, hdrlen), maxtype, policy); +} + +/** + * nlmsg_report - need to report back to application? + * @nlh: netlink message header + * + * Returns 1 if a report back to the application is requested. + */ +static inline int nlmsg_report(const struct nlmsghdr *nlh) +{ + return !!(nlh->nlmsg_flags & NLM_F_ECHO); +} + +/** + * nlmsg_for_each_attr - iterate over a stream of attributes + * @pos: loop counter, set to current attribute + * @nlh: netlink message header + * @hdrlen: length of familiy specific header + * @rem: initialized to len, holds bytes currently remaining in stream + */ +#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \ + nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \ + nlmsg_attrlen(nlh, hdrlen), rem) + +#if 0 +/* FIXME: Enable once all users have been converted */ + +/** + * __nlmsg_put - Add a new netlink message to an skb + * @skb: socket buffer to store message in + * @pid: netlink process id + * @seq: sequence number of message + * @type: message type + * @payload: length of message payload + * @flags: message flags + * + * The caller is responsible to ensure that the skb provides enough + * tailroom for both the netlink header and payload. + */ +static inline struct nlmsghdr *__nlmsg_put(struct sk_buff *skb, u32 pid, + u32 seq, int type, int payload, + int flags) +{ + struct nlmsghdr *nlh; + + nlh = (struct nlmsghdr *) skb_put(skb, nlmsg_total_size(payload)); + nlh->nlmsg_type = type; + nlh->nlmsg_len = nlmsg_msg_size(payload); + nlh->nlmsg_flags = flags; + nlh->nlmsg_pid = pid; + nlh->nlmsg_seq = seq; + + memset((unsigned char *) nlmsg_data(nlh) + payload, 0, + nlmsg_padlen(payload)); + + return nlh; +} +#endif + +/** + * nlmsg_put - Add a new netlink message to an skb + * @skb: socket buffer to store message in + * @pid: netlink process id + * @seq: sequence number of message + * @type: message type + * @payload: length of message payload + * @flags: message flags + * + * Returns NULL if the tailroom of the skb is insufficient to store + * the message header and payload. + */ +static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, + int type, int payload, int flags) +{ + if (unlikely(skb_tailroom(skb) < nlmsg_total_size(payload))) + return NULL; + + return __nlmsg_put(skb, pid, seq, type, payload, flags); +} + +/** + * nlmsg_put_answer - Add a new callback based netlink message to an skb + * @skb: socket buffer to store message in + * @cb: netlink callback + * @type: message type + * @payload: length of message payload + * @flags: message flags + * + * Returns NULL if the tailroom of the skb is insufficient to store + * the message header and payload. + */ +static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, + struct netlink_callback *cb, + int type, int payload, + int flags) +{ + return nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, + type, payload, flags); +} + +/** + * nlmsg_new - Allocate a new netlink message + * @payload: size of the message payload + * @flags: the type of memory to allocate. + * + * Use NLMSG_DEFAULT_SIZE if the size of the payload isn't known + * and a good default is needed. + */ +static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags) +{ + return alloc_skb(nlmsg_total_size(payload), flags); +} + +/** + * nlmsg_end - Finalize a netlink message + * @skb: socket buffer the message is stored in + * @nlh: netlink message header + * + * Corrects the netlink message header to include the appeneded + * attributes. Only necessary if attributes have been added to + * the message. + * + * Returns the total data length of the skb. + */ +static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh) +{ + nlh->nlmsg_len = skb_tail_pointer(skb) - (unsigned char *)nlh; + + return skb->len; +} + +/** + * nlmsg_get_pos - return current position in netlink message + * @skb: socket buffer the message is stored in + * + * Returns a pointer to the current tail of the message. + */ +static inline void *nlmsg_get_pos(struct sk_buff *skb) +{ + return skb_tail_pointer(skb); +} + +/** + * nlmsg_trim - Trim message to a mark + * @skb: socket buffer the message is stored in + * @mark: mark to trim to + * + * Trims the message to the provided mark. + */ +static inline void nlmsg_trim(struct sk_buff *skb, const void *mark) +{ + if (mark) + skb_trim(skb, (unsigned char *) mark - skb->data); +} + +/** + * nlmsg_cancel - Cancel construction of a netlink message + * @skb: socket buffer the message is stored in + * @nlh: netlink message header + * + * Removes the complete netlink message including all + * attributes from the socket buffer again. + */ +static inline void nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh) +{ + nlmsg_trim(skb, nlh); +} + +/** + * nlmsg_free - free a netlink message + * @skb: socket buffer of netlink message + */ +static inline void nlmsg_free(struct sk_buff *skb) +{ + kfree_skb(skb); +} + +/** + * nlmsg_multicast - multicast a netlink message + * @sk: netlink socket to spread messages to + * @skb: netlink message as socket buffer + * @pid: own netlink pid to avoid sending to yourself + * @group: multicast group id + * @flags: allocation flags + */ +static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb, + u32 pid, unsigned int group, gfp_t flags) +{ + int err; + + NETLINK_CB(skb).dst_group = group; + + err = netlink_broadcast(sk, skb, pid, group, flags); + if (err > 0) + err = 0; + + return err; +} + +/** + * nlmsg_unicast - unicast a netlink message + * @sk: netlink socket to spread message to + * @skb: netlink message as socket buffer + * @pid: netlink pid of the destination socket + */ +static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 pid) +{ + int err; + + err = netlink_unicast(sk, skb, pid, MSG_DONTWAIT); + if (err > 0) + err = 0; + + return err; +} + +/** + * nlmsg_for_each_msg - iterate over a stream of messages + * @pos: loop counter, set to current message + * @head: head of message stream + * @len: length of message stream + * @rem: initialized to len, holds bytes currently remaining in stream + */ +#define nlmsg_for_each_msg(pos, head, len, rem) \ + for (pos = head, rem = len; \ + nlmsg_ok(pos, rem); \ + pos = nlmsg_next(pos, &(rem))) + +/************************************************************************** + * Netlink Attributes + **************************************************************************/ + +/** + * nla_attr_size - length of attribute not including padding + * @payload: length of payload + */ +static inline int nla_attr_size(int payload) +{ + return NLA_HDRLEN + payload; +} + +/** + * nla_total_size - total length of attribute including padding + * @payload: length of payload + */ +static inline int nla_total_size(int payload) +{ + return NLA_ALIGN(nla_attr_size(payload)); +} + +/** + * nla_padlen - length of padding at the tail of attribute + * @payload: length of payload + */ +static inline int nla_padlen(int payload) +{ + return nla_total_size(payload) - nla_attr_size(payload); +} + +/** + * nla_type - attribute type + * @nla: netlink attribute + */ +static inline int nla_type(const struct nlattr *nla) +{ + return nla->nla_type & NLA_TYPE_MASK; +} + +/** + * nla_data - head of payload + * @nla: netlink attribute + */ +static inline void *nla_data(const struct nlattr *nla) +{ + return (char *) nla + NLA_HDRLEN; +} + +/** + * nla_len - length of payload + * @nla: netlink attribute + */ +static inline int nla_len(const struct nlattr *nla) +{ + return nla->nla_len - NLA_HDRLEN; +} + +/** + * nla_ok - check if the netlink attribute fits into the remaining bytes + * @nla: netlink attribute + * @remaining: number of bytes remaining in attribute stream + */ +static inline int nla_ok(const struct nlattr *nla, int remaining) +{ + return remaining >= (int) sizeof(*nla) && + nla->nla_len >= sizeof(*nla) && + nla->nla_len <= remaining; +} + +/** + * nla_next - next netlink attribute in attribute stream + * @nla: netlink attribute + * @remaining: number of bytes remaining in attribute stream + * + * Returns the next netlink attribute in the attribute stream and + * decrements remaining by the size of the current attribute. + */ +static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining) +{ + int totlen = NLA_ALIGN(nla->nla_len); + + *remaining -= totlen; + return (struct nlattr *) ((char *) nla + totlen); +} + +/** + * nla_find_nested - find attribute in a set of nested attributes + * @nla: attribute containing the nested attributes + * @attrtype: type of attribute to look for + * + * Returns the first attribute which matches the specified type. + */ +static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype) +{ + return nla_find(nla_data(nla), nla_len(nla), attrtype); +} + +/** + * nla_parse_nested - parse nested attributes + * @tb: destination array with maxtype+1 elements + * @maxtype: maximum attribute type to be expected + * @nla: attribute containing the nested attributes + * @policy: validation policy + * + * See nla_parse() + */ +static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, + const struct nlattr *nla, + const struct nla_policy *policy) +{ + return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); +} + +/** + * nla_put_u8 - Add a u8 netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @value: numeric value + */ +static inline int nla_put_u8(struct sk_buff *skb, int attrtype, u8 value) +{ + return nla_put(skb, attrtype, sizeof(u8), &value); +} + +/** + * nla_put_u16 - Add a u16 netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @value: numeric value + */ +static inline int nla_put_u16(struct sk_buff *skb, int attrtype, u16 value) +{ + return nla_put(skb, attrtype, sizeof(u16), &value); +} + +/** + * nla_put_u32 - Add a u32 netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @value: numeric value + */ +static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value) +{ + return nla_put(skb, attrtype, sizeof(u32), &value); +} + +/** + * nla_put_64 - Add a u64 netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @value: numeric value + */ +static inline int nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) +{ + return nla_put(skb, attrtype, sizeof(u64), &value); +} + +/** + * nla_put_string - Add a string netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @str: NUL terminated string + */ +static inline int nla_put_string(struct sk_buff *skb, int attrtype, + const char *str) +{ + return nla_put(skb, attrtype, strlen(str) + 1, str); +} + +/** + * nla_put_flag - Add a flag netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + */ +static inline int nla_put_flag(struct sk_buff *skb, int attrtype) +{ + return nla_put(skb, attrtype, 0, NULL); +} + +/** + * nla_put_msecs - Add a msecs netlink attribute to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @jiffies: number of msecs in jiffies + */ +static inline int nla_put_msecs(struct sk_buff *skb, int attrtype, + unsigned long jiffies) +{ + u64 tmp = jiffies_to_msecs(jiffies); + return nla_put(skb, attrtype, sizeof(u64), &tmp); +} + +#define NLA_PUT(skb, attrtype, attrlen, data) \ + do { \ + if (unlikely(nla_put(skb, attrtype, attrlen, data) < 0)) \ + goto nla_put_failure; \ + } while(0) + +#define NLA_PUT_TYPE(skb, type, attrtype, value) \ + do { \ + type __tmp = value; \ + NLA_PUT(skb, attrtype, sizeof(type), &__tmp); \ + } while(0) + +#define NLA_PUT_U8(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u8, attrtype, value) + +#define NLA_PUT_U16(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u16, attrtype, value) + +#define NLA_PUT_LE16(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, __le16, attrtype, value) + +#define NLA_PUT_BE16(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, __be16, attrtype, value) + +#define NLA_PUT_U32(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u32, attrtype, value) + +#define NLA_PUT_BE32(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, __be32, attrtype, value) + +#define NLA_PUT_U64(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, u64, attrtype, value) + +#define NLA_PUT_BE64(skb, attrtype, value) \ + NLA_PUT_TYPE(skb, __be64, attrtype, value) + +#define NLA_PUT_STRING(skb, attrtype, value) \ + NLA_PUT(skb, attrtype, strlen(value) + 1, value) + +#define NLA_PUT_FLAG(skb, attrtype) \ + NLA_PUT(skb, attrtype, 0, NULL) + +#define NLA_PUT_MSECS(skb, attrtype, jiffies) \ + NLA_PUT_U64(skb, attrtype, jiffies_to_msecs(jiffies)) + +/** + * nla_get_u32 - return payload of u32 attribute + * @nla: u32 netlink attribute + */ +static inline u32 nla_get_u32(const struct nlattr *nla) +{ + return *(u32 *) nla_data(nla); +} + +/** + * nla_get_be32 - return payload of __be32 attribute + * @nla: __be32 netlink attribute + */ +static inline __be32 nla_get_be32(const struct nlattr *nla) +{ + return *(__be32 *) nla_data(nla); +} + +/** + * nla_get_u16 - return payload of u16 attribute + * @nla: u16 netlink attribute + */ +static inline u16 nla_get_u16(const struct nlattr *nla) +{ + return *(u16 *) nla_data(nla); +} + +/** + * nla_get_be16 - return payload of __be16 attribute + * @nla: __be16 netlink attribute + */ +static inline __be16 nla_get_be16(const struct nlattr *nla) +{ + return *(__be16 *) nla_data(nla); +} + +/** + * nla_get_le16 - return payload of __le16 attribute + * @nla: __le16 netlink attribute + */ +static inline __le16 nla_get_le16(const struct nlattr *nla) +{ + return *(__le16 *) nla_data(nla); +} + +/** + * nla_get_u8 - return payload of u8 attribute + * @nla: u8 netlink attribute + */ +static inline u8 nla_get_u8(const struct nlattr *nla) +{ + return *(u8 *) nla_data(nla); +} + +/** + * nla_get_u64 - return payload of u64 attribute + * @nla: u64 netlink attribute + */ +static inline u64 nla_get_u64(const struct nlattr *nla) +{ + u64 tmp; + + nla_memcpy(&tmp, nla, sizeof(tmp)); + + return tmp; +} + +/** + * nla_get_be64 - return payload of __be64 attribute + * @nla: __be64 netlink attribute + */ +static inline __be64 nla_get_be64(const struct nlattr *nla) +{ + __be64 tmp; + + nla_memcpy(&tmp, nla, sizeof(tmp)); + + return tmp; +} + +/** + * nla_get_flag - return payload of flag attribute + * @nla: flag netlink attribute + */ +static inline int nla_get_flag(const struct nlattr *nla) +{ + return !!nla; +} + +/** + * nla_get_msecs - return payload of msecs attribute + * @nla: msecs netlink attribute + * + * Returns the number of milliseconds in jiffies. + */ +static inline unsigned long nla_get_msecs(const struct nlattr *nla) +{ + u64 msecs = nla_get_u64(nla); + + return msecs_to_jiffies((unsigned long) msecs); +} + +/** + * nla_nest_start - Start a new level of nested attributes + * @skb: socket buffer to add attributes to + * @attrtype: attribute type of container + * + * Returns the container attribute + */ +static inline struct nlattr *nla_nest_start(struct sk_buff *skb, int attrtype) +{ + struct nlattr *start = (struct nlattr *)skb_tail_pointer(skb); + + if (nla_put(skb, attrtype, 0, NULL) < 0) + return NULL; + + return start; +} + +/** + * nla_nest_end - Finalize nesting of attributes + * @skb: socket buffer the attributes are stored in + * @start: container attribute + * + * Corrects the container attribute header to include the all + * appeneded attributes. + * + * Returns the total data length of the skb. + */ +static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start) +{ + start->nla_len = skb_tail_pointer(skb) - (unsigned char *)start; + return skb->len; +} + +/** + * nla_nest_cancel - Cancel nesting of attributes + * @skb: socket buffer the message is stored in + * @start: container attribute + * + * Removes the container attribute and including all nested + * attributes. Returns -EMSGSIZE + */ +static inline void nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) +{ + nlmsg_trim(skb, start); +} + +/** + * nla_validate_nested - Validate a stream of nested attributes + * @start: container attribute + * @maxtype: maximum attribute type to be expected + * @policy: validation policy + * + * Validates all attributes in the nested attribute stream against the + * specified policy. Attributes with a type exceeding maxtype will be + * ignored. See documenation of struct nla_policy for more details. + * + * Returns 0 on success or a negative error code. + */ +static inline int nla_validate_nested(struct nlattr *start, int maxtype, + const struct nla_policy *policy) +{ + return nla_validate(nla_data(start), nla_len(start), maxtype, policy); +} + +/** + * nla_for_each_attr - iterate over a stream of attributes + * @pos: loop counter, set to current attribute + * @head: head of attribute stream + * @len: length of attribute stream + * @rem: initialized to len, holds bytes currently remaining in stream + */ +#define nla_for_each_attr(pos, head, len, rem) \ + for (pos = head, rem = len; \ + nla_ok(pos, rem); \ + pos = nla_next(pos, &(rem))) + +/** + * nla_for_each_nested - iterate over nested attributes + * @pos: loop counter, set to current attribute + * @nla: attribute containing the nested attributes + * @rem: initialized to len, holds bytes currently remaining in stream + */ +#define nla_for_each_nested(pos, nla, rem) \ + nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem) + +#endif diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h new file mode 100644 index 00000000..d4958d4c --- /dev/null +++ b/include/net/netns/conntrack.h @@ -0,0 +1,35 @@ +#ifndef __NETNS_CONNTRACK_H +#define __NETNS_CONNTRACK_H + +#include <linux/list.h> +#include <linux/list_nulls.h> +#include <asm/atomic.h> + +struct ctl_table_header; +struct nf_conntrack_ecache; + +struct netns_ct { + atomic_t count; + unsigned int expect_count; + unsigned int htable_size; + struct kmem_cache *nf_conntrack_cachep; + struct hlist_nulls_head *hash; + struct hlist_head *expect_hash; + struct hlist_nulls_head unconfirmed; + struct hlist_nulls_head dying; + struct ip_conntrack_stat __percpu *stat; + int sysctl_events; + unsigned int sysctl_events_retry_timeout; + int sysctl_acct; + int sysctl_checksum; + unsigned int sysctl_log_invalid; /* Log invalid packets */ +#ifdef CONFIG_SYSCTL + struct ctl_table_header *sysctl_header; + struct ctl_table_header *acct_sysctl_header; + struct ctl_table_header *event_sysctl_header; +#endif + int hash_vmalloc; + int expect_vmalloc; + char *slabname; +}; +#endif diff --git a/include/net/netns/core.h b/include/net/netns/core.h new file mode 100644 index 00000000..78eb1ff7 --- /dev/null +++ b/include/net/netns/core.h @@ -0,0 +1,16 @@ +#ifndef __NETNS_CORE_H__ +#define __NETNS_CORE_H__ + +struct ctl_table_header; +struct prot_inuse; + +struct netns_core { + /* core sysctls */ + struct ctl_table_header *sysctl_hdr; + + int sysctl_somaxconn; + + struct prot_inuse __percpu *inuse; +}; + +#endif diff --git a/include/net/netns/dccp.h b/include/net/netns/dccp.h new file mode 100644 index 00000000..98d2a7ce --- /dev/null +++ b/include/net/netns/dccp.h @@ -0,0 +1,11 @@ +#ifndef __NETNS_DCCP_H__ +#define __NETNS_DCCP_H__ + +struct sock; + +struct netns_dccp { + struct sock *v4_ctl_sk; + struct sock *v6_ctl_sk; +}; + +#endif diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h new file mode 100644 index 00000000..81a31c0d --- /dev/null +++ b/include/net/netns/generic.h @@ -0,0 +1,46 @@ +/* + * generic net pointers + */ + +#ifndef __NET_GENERIC_H__ +#define __NET_GENERIC_H__ + +#include <linux/rcupdate.h> + +/* + * Generic net pointers are to be used by modules to put some private + * stuff on the struct net without explicit struct net modification + * + * The rules are simple: + * 1. set pernet_operations->id. After register_pernet_device you + * will have the id of your private pointer. + * 2. set pernet_operations->size to have the code allocate and free + * a private structure pointed to from struct net. + * 3. do not change this pointer while the net is alive; + * 4. do not try to have any private reference on the net_generic object. + * + * After accomplishing all of the above, the private pointer can be + * accessed with the net_generic() call. + */ + +struct net_generic { + unsigned int len; + struct rcu_head rcu; + + void *ptr[0]; +}; + +static inline void *net_generic(struct net *net, int id) +{ + struct net_generic *ng; + void *ptr; + + rcu_read_lock(); + ng = rcu_dereference(net->gen); + BUG_ON(id == 0 || id > ng->len); + ptr = ng->ptr[id - 1]; + rcu_read_unlock(); + + return ptr; +} +#endif diff --git a/include/net/netns/hash.h b/include/net/netns/hash.h new file mode 100644 index 00000000..548d78f2 --- /dev/null +++ b/include/net/netns/hash.h @@ -0,0 +1,21 @@ +#ifndef __NET_NS_HASH_H__ +#define __NET_NS_HASH_H__ + +#include <asm/cache.h> + +struct net; + +static inline unsigned net_hash_mix(struct net *net) +{ +#ifdef CONFIG_NET_NS + /* + * shift this right to eliminate bits, that are + * always zeroed + */ + + return (unsigned)(((unsigned long)net) >> L1_CACHE_SHIFT); +#else + return 0; +#endif +} +#endif diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h new file mode 100644 index 00000000..d68c3f12 --- /dev/null +++ b/include/net/netns/ipv4.h @@ -0,0 +1,69 @@ +/* + * ipv4 in net namespaces + */ + +#ifndef __NETNS_IPV4_H__ +#define __NETNS_IPV4_H__ + +#include <net/inet_frag.h> + +struct ctl_table_header; +struct ipv4_devconf; +struct fib_rules_ops; +struct hlist_head; +struct sock; + +struct netns_ipv4 { +#ifdef CONFIG_SYSCTL + struct ctl_table_header *forw_hdr; + struct ctl_table_header *frags_hdr; + struct ctl_table_header *ipv4_hdr; + struct ctl_table_header *route_hdr; +#endif + struct ipv4_devconf *devconf_all; + struct ipv4_devconf *devconf_dflt; +#ifdef CONFIG_IP_MULTIPLE_TABLES + struct fib_rules_ops *rules_ops; +#endif + struct hlist_head *fib_table_hash; + struct sock *fibnl; + + struct sock **icmp_sk; + struct sock *tcp_sock; + + struct netns_frags frags; +#ifdef CONFIG_NETFILTER + struct xt_table *iptable_filter; + struct xt_table *iptable_mangle; + struct xt_table *iptable_raw; + struct xt_table *arptable_filter; +#ifdef CONFIG_SECURITY + struct xt_table *iptable_security; +#endif + struct xt_table *nat_table; + struct hlist_head *nat_bysource; + unsigned int nat_htable_size; + int nat_vmalloced; +#endif + + int sysctl_icmp_echo_ignore_all; + int sysctl_icmp_echo_ignore_broadcasts; + int sysctl_icmp_ignore_bogus_error_responses; + int sysctl_icmp_ratelimit; + int sysctl_icmp_ratemask; + int sysctl_icmp_errors_use_inbound_ifaddr; + int sysctl_rt_cache_rebuild_count; + int current_rt_cache_rebuild_count; + + atomic_t rt_genid; + +#ifdef CONFIG_IP_MROUTE +#ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES + struct mr_table *mrt; +#else + struct list_head mr_tables; + struct fib_rules_ops *mr_rules_ops; +#endif +#endif +}; +#endif diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h new file mode 100644 index 00000000..81abfcb2 --- /dev/null +++ b/include/net/netns/ipv6.h @@ -0,0 +1,70 @@ +/* + * ipv6 in net namespaces + */ + +#include <net/inet_frag.h> + +#ifndef __NETNS_IPV6_H__ +#define __NETNS_IPV6_H__ +#include <net/dst_ops.h> + +struct ctl_table_header; + +struct netns_sysctl_ipv6 { +#ifdef CONFIG_SYSCTL + struct ctl_table_header *table; + struct ctl_table_header *frags_hdr; +#endif + int bindv6only; + int flush_delay; + int ip6_rt_max_size; + int ip6_rt_gc_min_interval; + int ip6_rt_gc_timeout; + int ip6_rt_gc_interval; + int ip6_rt_gc_elasticity; + int ip6_rt_mtu_expires; + int ip6_rt_min_advmss; + int icmpv6_time; +}; + +struct netns_ipv6 { + struct netns_sysctl_ipv6 sysctl; + struct ipv6_devconf *devconf_all; + struct ipv6_devconf *devconf_dflt; + struct netns_frags frags; +#ifdef CONFIG_NETFILTER + struct xt_table *ip6table_filter; + struct xt_table *ip6table_mangle; + struct xt_table *ip6table_raw; +#ifdef CONFIG_SECURITY + struct xt_table *ip6table_security; +#endif +#endif + struct rt6_info *ip6_null_entry; + struct rt6_statistics *rt6_stats; + struct timer_list ip6_fib_timer; + struct hlist_head *fib_table_hash; + struct fib6_table *fib6_main_tbl; + struct dst_ops ip6_dst_ops; + unsigned int ip6_rt_gc_expire; + unsigned long ip6_rt_last_gc; +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +#endif + struct sock **icmp_sk; + struct sock *ndisc_sk; + struct sock *tcp_sk; + struct sock *igmp_sk; +#ifdef CONFIG_IPV6_MROUTE +#ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES + struct mr6_table *mrt6; +#else + struct list_head mr6_tables; + struct fib_rules_ops *mr6_rules_ops; +#endif +#endif +}; +#endif diff --git a/include/net/netns/mib.h b/include/net/netns/mib.h new file mode 100644 index 00000000..0b44112e --- /dev/null +++ b/include/net/netns/mib.h @@ -0,0 +1,28 @@ +#ifndef __NETNS_MIB_H__ +#define __NETNS_MIB_H__ + +#include <net/snmp.h> + +struct netns_mib { + DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics); + DEFINE_SNMP_STAT(struct ipstats_mib, ip_statistics); + DEFINE_SNMP_STAT(struct linux_mib, net_statistics); + DEFINE_SNMP_STAT(struct udp_mib, udp_statistics); + DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics); + DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics); + DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics); + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct proc_dir_entry *proc_net_devsnmp6; + DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6); + DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6); + DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); + DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); + DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics); +#endif +#ifdef CONFIG_XFRM_STATISTICS + DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics); +#endif +}; + +#endif diff --git a/include/net/netns/packet.h b/include/net/netns/packet.h new file mode 100644 index 00000000..cb4e894c --- /dev/null +++ b/include/net/netns/packet.h @@ -0,0 +1,15 @@ +/* + * Packet network namespace + */ +#ifndef __NETNS_PACKET_H__ +#define __NETNS_PACKET_H__ + +#include <linux/rculist.h> +#include <linux/spinlock.h> + +struct netns_packet { + spinlock_t sklist_lock; + struct hlist_head sklist; +}; + +#endif /* __NETNS_PACKET_H__ */ diff --git a/include/net/netns/unix.h b/include/net/netns/unix.h new file mode 100644 index 00000000..284649d4 --- /dev/null +++ b/include/net/netns/unix.h @@ -0,0 +1,13 @@ +/* + * Unix network namespace + */ +#ifndef __NETNS_UNIX_H__ +#define __NETNS_UNIX_H__ + +struct ctl_table_header; +struct netns_unix { + int sysctl_max_dgram_qlen; + struct ctl_table_header *ctl; +}; + +#endif /* __NETNS_UNIX_H__ */ diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h new file mode 100644 index 00000000..591db7d6 --- /dev/null +++ b/include/net/netns/x_tables.h @@ -0,0 +1,18 @@ +#ifndef __NETNS_X_TABLES_H +#define __NETNS_X_TABLES_H + +#include <linux/list.h> +#include <linux/netfilter.h> + +struct ebt_table; + +struct netns_xt { + struct list_head tables[NFPROTO_NUMPROTO]; +#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \ + defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE) + struct ebt_table *broute_table; + struct ebt_table *frame_filter; + struct ebt_table *frame_nat; +#endif +}; +#endif diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h new file mode 100644 index 00000000..74f119a2 --- /dev/null +++ b/include/net/netns/xfrm.h @@ -0,0 +1,63 @@ +#ifndef __NETNS_XFRM_H +#define __NETNS_XFRM_H + +#include <linux/list.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <linux/xfrm.h> +#include <net/dst_ops.h> + +struct ctl_table_header; + +struct xfrm_policy_hash { + struct hlist_head *table; + unsigned int hmask; +}; + +struct netns_xfrm { + struct list_head state_all; + /* + * Hash table to find appropriate SA towards given target (endpoint of + * tunnel or destination of transport mode) allowed by selector. + * + * Main use is finding SA after policy selected tunnel or transport + * mode. Also, it can be used by ah/esp icmp error handler to find + * offending SA. + */ + struct hlist_head *state_bydst; + struct hlist_head *state_bysrc; + struct hlist_head *state_byspi; + unsigned int state_hmask; + unsigned int state_num; + struct work_struct state_hash_work; + struct hlist_head state_gc_list; + struct work_struct state_gc_work; + + wait_queue_head_t km_waitq; + + struct list_head policy_all; + struct hlist_head *policy_byidx; + unsigned int policy_idx_hmask; + struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; + struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; + unsigned int policy_count[XFRM_POLICY_MAX * 2]; + struct work_struct policy_hash_work; + + struct dst_ops xfrm4_dst_ops; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct dst_ops xfrm6_dst_ops; +#endif + + struct sock *nlsk; + struct sock *nlsk_stash; + + u32 sysctl_aevent_etime; + u32 sysctl_aevent_rseqth; + int sysctl_larval_drop; + u32 sysctl_acq_expires; +#ifdef CONFIG_SYSCTL + struct ctl_table_header *sysctl_hdr; +#endif +}; + +#endif diff --git a/include/net/netrom.h b/include/net/netrom.h new file mode 100644 index 00000000..f0793c1c --- /dev/null +++ b/include/net/netrom.h @@ -0,0 +1,270 @@ +/* + * Declarations of NET/ROM type objects. + * + * Jonathan Naylor G4KLX 9/4/95 + */ + +#ifndef _NETROM_H +#define _NETROM_H + +#include <linux/netrom.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <net/sock.h> + +#define NR_NETWORK_LEN 15 +#define NR_TRANSPORT_LEN 5 + +#define NR_PROTO_IP 0x0C + +#define NR_PROTOEXT 0x00 +#define NR_CONNREQ 0x01 +#define NR_CONNACK 0x02 +#define NR_DISCREQ 0x03 +#define NR_DISCACK 0x04 +#define NR_INFO 0x05 +#define NR_INFOACK 0x06 +#define NR_RESET 0x07 + +#define NR_CHOKE_FLAG 0x80 +#define NR_NAK_FLAG 0x40 +#define NR_MORE_FLAG 0x20 + +/* Define Link State constants. */ +enum { + NR_STATE_0, + NR_STATE_1, + NR_STATE_2, + NR_STATE_3 +}; + +#define NR_COND_ACK_PENDING 0x01 +#define NR_COND_REJECT 0x02 +#define NR_COND_PEER_RX_BUSY 0x04 +#define NR_COND_OWN_RX_BUSY 0x08 + +#define NR_DEFAULT_T1 120000 /* Outstanding frames - 120 seconds */ +#define NR_DEFAULT_T2 5000 /* Response delay - 5 seconds */ +#define NR_DEFAULT_N2 3 /* Number of Retries - 3 */ +#define NR_DEFAULT_T4 180000 /* Busy Delay - 180 seconds */ +#define NR_DEFAULT_IDLE 0 /* No Activity Timeout - none */ +#define NR_DEFAULT_WINDOW 4 /* Default Window Size - 4 */ +#define NR_DEFAULT_OBS 6 /* Default Obsolescence Count - 6 */ +#define NR_DEFAULT_QUAL 10 /* Default Neighbour Quality - 10 */ +#define NR_DEFAULT_TTL 16 /* Default Time To Live - 16 */ +#define NR_DEFAULT_ROUTING 1 /* Is routing enabled ? */ +#define NR_DEFAULT_FAILS 2 /* Link fails until route fails */ +#define NR_DEFAULT_RESET 0 /* Sent / accept reset cmds? */ + +#define NR_MODULUS 256 +#define NR_MAX_WINDOW_SIZE 127 /* Maximum Window Allowable - 127 */ +#define NR_MAX_PACKET_SIZE 236 /* Maximum Packet Length - 236 */ + +struct nr_sock { + struct sock sock; + ax25_address user_addr, source_addr, dest_addr; + struct net_device *device; + unsigned char my_index, my_id; + unsigned char your_index, your_id; + unsigned char state, condition, bpqext, window; + unsigned short vs, vr, va, vl; + unsigned char n2, n2count; + unsigned long t1, t2, t4, idle; + unsigned short fraglen; + struct timer_list t1timer; + struct timer_list t2timer; + struct timer_list t4timer; + struct timer_list idletimer; + struct sk_buff_head ack_queue; + struct sk_buff_head reseq_queue; + struct sk_buff_head frag_queue; +}; + +#define nr_sk(sk) ((struct nr_sock *)(sk)) + +struct nr_neigh { + struct hlist_node neigh_node; + ax25_address callsign; + ax25_digi *digipeat; + ax25_cb *ax25; + struct net_device *dev; + unsigned char quality; + unsigned char locked; + unsigned short count; + unsigned int number; + unsigned char failed; + atomic_t refcount; +}; + +struct nr_route { + unsigned char quality; + unsigned char obs_count; + struct nr_neigh *neighbour; +}; + +struct nr_node { + struct hlist_node node_node; + ax25_address callsign; + char mnemonic[7]; + unsigned char which; + unsigned char count; + struct nr_route routes[3]; + atomic_t refcount; + spinlock_t node_lock; +}; + +/********************************************************************* + * nr_node & nr_neigh lists, refcounting and locking + *********************************************************************/ + +#define nr_node_hold(__nr_node) \ + atomic_inc(&((__nr_node)->refcount)) + +static __inline__ void nr_node_put(struct nr_node *nr_node) +{ + if (atomic_dec_and_test(&nr_node->refcount)) { + kfree(nr_node); + } +} + +#define nr_neigh_hold(__nr_neigh) \ + atomic_inc(&((__nr_neigh)->refcount)) + +static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) +{ + if (atomic_dec_and_test(&nr_neigh->refcount)) { + if (nr_neigh->ax25) + ax25_cb_put(nr_neigh->ax25); + kfree(nr_neigh->digipeat); + kfree(nr_neigh); + } +} + +/* nr_node_lock and nr_node_unlock also hold/put the node's refcounter. + */ +static __inline__ void nr_node_lock(struct nr_node *nr_node) +{ + nr_node_hold(nr_node); + spin_lock_bh(&nr_node->node_lock); +} + +static __inline__ void nr_node_unlock(struct nr_node *nr_node) +{ + spin_unlock_bh(&nr_node->node_lock); + nr_node_put(nr_node); +} + +#define nr_neigh_for_each(__nr_neigh, node, list) \ + hlist_for_each_entry(__nr_neigh, node, list, neigh_node) + +#define nr_neigh_for_each_safe(__nr_neigh, node, node2, list) \ + hlist_for_each_entry_safe(__nr_neigh, node, node2, list, neigh_node) + +#define nr_node_for_each(__nr_node, node, list) \ + hlist_for_each_entry(__nr_node, node, list, node_node) + +#define nr_node_for_each_safe(__nr_node, node, node2, list) \ + hlist_for_each_entry_safe(__nr_node, node, node2, list, node_node) + + +/*********************************************************************/ + +/* af_netrom.c */ +extern int sysctl_netrom_default_path_quality; +extern int sysctl_netrom_obsolescence_count_initialiser; +extern int sysctl_netrom_network_ttl_initialiser; +extern int sysctl_netrom_transport_timeout; +extern int sysctl_netrom_transport_maximum_tries; +extern int sysctl_netrom_transport_acknowledge_delay; +extern int sysctl_netrom_transport_busy_delay; +extern int sysctl_netrom_transport_requested_window_size; +extern int sysctl_netrom_transport_no_activity_timeout; +extern int sysctl_netrom_routing_control; +extern int sysctl_netrom_link_fails_count; +extern int sysctl_netrom_reset_circuit; + +extern int nr_rx_frame(struct sk_buff *, struct net_device *); +extern void nr_destroy_socket(struct sock *); + +/* nr_dev.c */ +extern int nr_rx_ip(struct sk_buff *, struct net_device *); +extern void nr_setup(struct net_device *); + +/* nr_in.c */ +extern int nr_process_rx_frame(struct sock *, struct sk_buff *); + +/* nr_loopback.c */ +extern void nr_loopback_init(void); +extern void nr_loopback_clear(void); +extern int nr_loopback_queue(struct sk_buff *); + +/* nr_out.c */ +extern void nr_output(struct sock *, struct sk_buff *); +extern void nr_send_nak_frame(struct sock *); +extern void nr_kick(struct sock *); +extern void nr_transmit_buffer(struct sock *, struct sk_buff *); +extern void nr_establish_data_link(struct sock *); +extern void nr_enquiry_response(struct sock *); +extern void nr_check_iframes_acked(struct sock *, unsigned short); + +/* nr_route.c */ +extern void nr_rt_device_down(struct net_device *); +extern struct net_device *nr_dev_first(void); +extern struct net_device *nr_dev_get(ax25_address *); +extern int nr_rt_ioctl(unsigned int, void __user *); +extern void nr_link_failed(ax25_cb *, int); +extern int nr_route_frame(struct sk_buff *, ax25_cb *); +extern const struct file_operations nr_nodes_fops; +extern const struct file_operations nr_neigh_fops; +extern void nr_rt_free(void); + +/* nr_subr.c */ +extern void nr_clear_queues(struct sock *); +extern void nr_frames_acked(struct sock *, unsigned short); +extern void nr_requeue_frames(struct sock *); +extern int nr_validate_nr(struct sock *, unsigned short); +extern int nr_in_rx_window(struct sock *, unsigned short); +extern void nr_write_internal(struct sock *, int); + +extern void __nr_transmit_reply(struct sk_buff *skb, int mine, + unsigned char cmdflags); + +/* + * This routine is called when a Connect Acknowledge with the Choke Flag + * set is needed to refuse a connection. + */ +#define nr_transmit_refusal(skb, mine) \ +do { \ + __nr_transmit_reply((skb), (mine), NR_CONNACK | NR_CHOKE_FLAG); \ +} while (0) + +/* + * This routine is called when we don't have a circuit matching an incoming + * NET/ROM packet. This is an G8PZT Xrouter extension. + */ +#define nr_transmit_reset(skb, mine) \ +do { \ + __nr_transmit_reply((skb), (mine), NR_RESET); \ +} while (0) + +extern void nr_disconnect(struct sock *, int); + +/* nr_timer.c */ +extern void nr_init_timers(struct sock *sk); +extern void nr_start_heartbeat(struct sock *); +extern void nr_start_t1timer(struct sock *); +extern void nr_start_t2timer(struct sock *); +extern void nr_start_t4timer(struct sock *); +extern void nr_start_idletimer(struct sock *); +extern void nr_stop_heartbeat(struct sock *); +extern void nr_stop_t1timer(struct sock *); +extern void nr_stop_t2timer(struct sock *); +extern void nr_stop_t4timer(struct sock *); +extern void nr_stop_idletimer(struct sock *); +extern int nr_t1timer_running(struct sock *); + +/* sysctl_net_netrom.c */ +extern void nr_register_sysctl(void); +extern void nr_unregister_sysctl(void); + +#endif diff --git a/include/net/nexthop.h b/include/net/nexthop.h new file mode 100644 index 00000000..3334dbfa --- /dev/null +++ b/include/net/nexthop.h @@ -0,0 +1,33 @@ +#ifndef __NET_NEXTHOP_H +#define __NET_NEXTHOP_H + +#include <linux/rtnetlink.h> +#include <net/netlink.h> + +static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining) +{ + return remaining >= sizeof(*rtnh) && + rtnh->rtnh_len >= sizeof(*rtnh) && + rtnh->rtnh_len <= remaining; +} + +static inline struct rtnexthop *rtnh_next(const struct rtnexthop *rtnh, + int *remaining) +{ + int totlen = NLA_ALIGN(rtnh->rtnh_len); + + *remaining -= totlen; + return (struct rtnexthop *) ((char *) rtnh + totlen); +} + +static inline struct nlattr *rtnh_attrs(const struct rtnexthop *rtnh) +{ + return (struct nlattr *) ((char *) rtnh + NLA_ALIGN(sizeof(*rtnh))); +} + +static inline int rtnh_attrlen(const struct rtnexthop *rtnh) +{ + return rtnh->rtnh_len - NLA_ALIGN(sizeof(*rtnh)); +} + +#endif diff --git a/include/net/nl802154.h b/include/net/nl802154.h new file mode 100644 index 00000000..99d2ba1c --- /dev/null +++ b/include/net/nl802154.h @@ -0,0 +1,126 @@ +/* + * nl802154.h + * + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef IEEE802154_NL_H +#define IEEE802154_NL_H + +struct net_device; +struct ieee802154_addr; + +/** + * ieee802154_nl_assoc_indic - Notify userland of an association request. + * @dev: The network device on which this association request was + * received. + * @addr: The address of the device requesting association. + * @cap: The capability information field from the device. + * + * This informs a userland coordinator of a device requesting to + * associate with the PAN controlled by the coordinator. + * + * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document. + */ +int ieee802154_nl_assoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 cap); + +/** + * ieee802154_nl_assoc_confirm - Notify userland of association. + * @dev: The device which has completed association. + * @short_addr: The short address assigned to the device. + * @status: The status of the association. + * + * Inform userland of the result of an association request. If the + * association request included asking the coordinator to allocate + * a short address then it is returned in @short_addr. + * + * Note: This is in section 7.3.2 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_assoc_confirm(struct net_device *dev, + u16 short_addr, u8 status); + +/** + * ieee802154_nl_disassoc_indic - Notify userland of disassociation. + * @dev: The device on which disassociation was indicated. + * @addr: The device which is disassociating. + * @reason: The reason for the disassociation. + * + * Inform userland that a device has disassociated from the network. + * + * Note: This is in section 7.3.3 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_disassoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason); + +/** + * ieee802154_nl_disassoc_confirm - Notify userland of disassociation + * completion. + * @dev: The device on which disassociation was ordered. + * @status: The result of the disassociation. + * + * Inform userland of the result of requesting that a device + * disassociate, or the result of requesting that we disassociate from + * a PAN managed by another coordinator. + * + * Note: This is in section 7.1.4.3 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_disassoc_confirm(struct net_device *dev, + u8 status); + +/** + * ieee802154_nl_scan_confirm - Notify userland of completion of scan. + * @dev: The device which was instructed to scan. + * @status: The status of the scan operation. + * @scan_type: What type of scan was performed. + * @unscanned: Any channels that the device was unable to scan. + * @edl: The energy levels (if a passive scan). + * + * + * Note: This is in section 7.1.11 of the IEEE 802.15.4 document. + * Note: This API does not permit the return of an active scan result. + */ +int ieee802154_nl_scan_confirm(struct net_device *dev, + u8 status, u8 scan_type, u32 unscanned, u8 page, + u8 *edl/*, struct list_head *pan_desc_list */); + +/** + * ieee802154_nl_beacon_indic - Notify userland of a received beacon. + * @dev: The device on which a beacon was received. + * @panid: The PAN of the coordinator. + * @coord_addr: The short address of the coordinator on that PAN. + * + * Note: This is in section 7.1.5 of the IEEE 802.15.4 document. + * Note: This API does not provide extended information such as what + * channel the PAN is on or what the LQI of the beacon frame was on + * receipt. + * Note: This API cannot indicate a beacon frame for a coordinator + * operating in long addressing mode. + */ +int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, + u16 coord_addr); + +/** + * ieee802154_nl_start_confirm - Notify userland of completion of start. + * @dev: The device which was instructed to scan. + * @status: The status of the scan operation. + * + * Note: This is in section 7.1.14 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_start_confirm(struct net_device *dev, u8 status); + +#endif diff --git a/include/net/p8022.h b/include/net/p8022.h new file mode 100644 index 00000000..42e9fac5 --- /dev/null +++ b/include/net/p8022.h @@ -0,0 +1,13 @@ +#ifndef _NET_P8022_H +#define _NET_P8022_H +extern struct datalink_proto * + register_8022_client(unsigned char type, + int (*func)(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt, + struct net_device *orig_dev)); +extern void unregister_8022_client(struct datalink_proto *proto); + +extern struct datalink_proto *make_8023_client(void); +extern void destroy_8023_client(struct datalink_proto *dl); +#endif diff --git a/include/net/phonet/gprs.h b/include/net/phonet/gprs.h new file mode 100644 index 00000000..928daf59 --- /dev/null +++ b/include/net/phonet/gprs.h @@ -0,0 +1,38 @@ +/* + * File: pep_gprs.h + * + * GPRS over Phonet pipe end point socket + * + * Copyright (C) 2008 Nokia Corporation. + * + * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef NET_PHONET_GPRS_H +#define NET_PHONET_GPRS_H + +struct sock; +struct sk_buff; + +int pep_writeable(struct sock *sk); +int pep_write(struct sock *sk, struct sk_buff *skb); +struct sk_buff *pep_read(struct sock *sk); + +int gprs_attach(struct sock *sk); +void gprs_detach(struct sock *sk); + +#endif diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h new file mode 100644 index 00000000..35672b1c --- /dev/null +++ b/include/net/phonet/pep.h @@ -0,0 +1,163 @@ +/* + * File: pep.h + * + * Phonet Pipe End Point sockets definitions + * + * Copyright (C) 2008 Nokia Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef NET_PHONET_PEP_H +#define NET_PHONET_PEP_H + +struct pep_sock { + struct pn_sock pn_sk; + + /* XXX: union-ify listening vs connected stuff ? */ + /* Listening socket stuff: */ + struct hlist_head ackq; + struct hlist_head hlist; + + /* Connected socket stuff: */ + struct sock *listener; + struct sk_buff_head ctrlreq_queue; +#define PNPIPE_CTRLREQ_MAX 10 + atomic_t tx_credits; + int ifindex; + u16 peer_type; /* peer type/subtype */ + u8 pipe_handle; + + u8 rx_credits; + u8 rx_fc; /* RX flow control */ + u8 tx_fc; /* TX flow control */ + u8 init_enable; /* auto-enable at creation */ + u8 aligned; +}; + +static inline struct pep_sock *pep_sk(struct sock *sk) +{ + return (struct pep_sock *)sk; +} + +extern const struct proto_ops phonet_stream_ops; + +/* Pipe protocol definitions */ +struct pnpipehdr { + u8 utid; /* transaction ID */ + u8 message_id; + u8 pipe_handle; + union { + u8 state_after_connect; /* connect request */ + u8 state_after_reset; /* reset request */ + u8 error_code; /* any response */ + u8 pep_type; /* status indication */ + u8 data[1]; + }; +}; +#define other_pep_type data[1] + +static inline struct pnpipehdr *pnp_hdr(struct sk_buff *skb) +{ + return (struct pnpipehdr *)skb_transport_header(skb); +} + +#define MAX_PNPIPE_HEADER (MAX_PHONET_HEADER + 4) + +enum { + PNS_PIPE_DATA = 0x20, + PNS_PIPE_ALIGNED_DATA, + + PNS_PEP_CONNECT_REQ = 0x40, + PNS_PEP_CONNECT_RESP, + PNS_PEP_DISCONNECT_REQ, + PNS_PEP_DISCONNECT_RESP, + PNS_PEP_RESET_REQ, + PNS_PEP_RESET_RESP, + PNS_PEP_ENABLE_REQ, + PNS_PEP_ENABLE_RESP, + PNS_PEP_CTRL_REQ, + PNS_PEP_CTRL_RESP, + PNS_PEP_DISABLE_REQ = 0x4C, + PNS_PEP_DISABLE_RESP, + + PNS_PEP_STATUS_IND = 0x60, + PNS_PIPE_CREATED_IND, + PNS_PIPE_RESET_IND = 0x63, + PNS_PIPE_ENABLED_IND, + PNS_PIPE_REDIRECTED_IND, + PNS_PIPE_DISABLED_IND = 0x66, +}; + +#define PN_PIPE_INVALID_HANDLE 0xff +#define PN_PEP_TYPE_COMMON 0x00 + +/* Phonet pipe status indication */ +enum { + PN_PEP_IND_FLOW_CONTROL, + PN_PEP_IND_ID_MCFC_GRANT_CREDITS, +}; + +/* Phonet pipe error codes */ +enum { + PN_PIPE_NO_ERROR, + PN_PIPE_ERR_INVALID_PARAM, + PN_PIPE_ERR_INVALID_HANDLE, + PN_PIPE_ERR_INVALID_CTRL_ID, + PN_PIPE_ERR_NOT_ALLOWED, + PN_PIPE_ERR_PEP_IN_USE, + PN_PIPE_ERR_OVERLOAD, + PN_PIPE_ERR_DEV_DISCONNECTED, + PN_PIPE_ERR_TIMEOUT, + PN_PIPE_ERR_ALL_PIPES_IN_USE, + PN_PIPE_ERR_GENERAL, + PN_PIPE_ERR_NOT_SUPPORTED, +}; + +/* Phonet pipe states */ +enum { + PN_PIPE_DISABLE, + PN_PIPE_ENABLE, +}; + +/* Phonet pipe sub-block types */ +enum { + PN_PIPE_SB_CREATE_REQ_PEP_SUB_TYPE, + PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE, + PN_PIPE_SB_REDIRECT_REQ_PEP_SUB_TYPE, + PN_PIPE_SB_NEGOTIATED_FC, + PN_PIPE_SB_REQUIRED_FC_TX, + PN_PIPE_SB_PREFERRED_FC_RX, + PN_PIPE_SB_ALIGNED_DATA, +}; + +/* Phonet pipe flow control models */ +enum { + PN_NO_FLOW_CONTROL, + PN_LEGACY_FLOW_CONTROL, + PN_ONE_CREDIT_FLOW_CONTROL, + PN_MULTI_CREDIT_FLOW_CONTROL, +}; + +#define pn_flow_safe(fc) ((fc) >> 1) + +/* Phonet pipe flow control states */ +enum { + PEP_IND_EMPTY, + PEP_IND_BUSY, + PEP_IND_READY, +}; + +#endif diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h new file mode 100644 index 00000000..7b114079 --- /dev/null +++ b/include/net/phonet/phonet.h @@ -0,0 +1,113 @@ +/* + * File: af_phonet.h + * + * Phonet sockets kernel definitions + * + * Copyright (C) 2008 Nokia Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef AF_PHONET_H +#define AF_PHONET_H + +/* + * The lower layers may not require more space, ever. Make sure it's + * enough. + */ +#define MAX_PHONET_HEADER (8 + MAX_HEADER) + +/* + * Every Phonet* socket has this structure first in its + * protocol-specific structure under name c. + */ +struct pn_sock { + struct sock sk; + u16 sobject; + u8 resource; +}; + +static inline struct pn_sock *pn_sk(struct sock *sk) +{ + return (struct pn_sock *)sk; +} + +extern const struct proto_ops phonet_dgram_ops; + +void pn_sock_init(void); +struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa); +void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb); +void phonet_get_local_port_range(int *min, int *max); +void pn_sock_hash(struct sock *sk); +void pn_sock_unhash(struct sock *sk); +int pn_sock_get_port(struct sock *sk, unsigned short sport); + +int pn_skb_send(struct sock *sk, struct sk_buff *skb, + const struct sockaddr_pn *target); + +static inline struct phonethdr *pn_hdr(struct sk_buff *skb) +{ + return (struct phonethdr *)skb_network_header(skb); +} + +static inline struct phonetmsg *pn_msg(struct sk_buff *skb) +{ + return (struct phonetmsg *)skb_transport_header(skb); +} + +/* + * Get the other party's sockaddr from received skb. The skb begins + * with a Phonet header. + */ +static inline +void pn_skb_get_src_sockaddr(struct sk_buff *skb, struct sockaddr_pn *sa) +{ + struct phonethdr *ph = pn_hdr(skb); + u16 obj = pn_object(ph->pn_sdev, ph->pn_sobj); + + sa->spn_family = AF_PHONET; + pn_sockaddr_set_object(sa, obj); + pn_sockaddr_set_resource(sa, ph->pn_res); + memset(sa->spn_zero, 0, sizeof(sa->spn_zero)); +} + +static inline +void pn_skb_get_dst_sockaddr(struct sk_buff *skb, struct sockaddr_pn *sa) +{ + struct phonethdr *ph = pn_hdr(skb); + u16 obj = pn_object(ph->pn_rdev, ph->pn_robj); + + sa->spn_family = AF_PHONET; + pn_sockaddr_set_object(sa, obj); + pn_sockaddr_set_resource(sa, ph->pn_res); + memset(sa->spn_zero, 0, sizeof(sa->spn_zero)); +} + +/* Protocols in Phonet protocol family. */ +struct phonet_protocol { + const struct proto_ops *ops; + struct proto *prot; + int sock_type; +}; + +int phonet_proto_register(int protocol, struct phonet_protocol *pp); +void phonet_proto_unregister(int protocol, struct phonet_protocol *pp); + +int phonet_sysctl_init(void); +void phonet_sysctl_exit(void); +int isi_register(void); +void isi_unregister(void); + +#endif diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h new file mode 100644 index 00000000..2d16783d --- /dev/null +++ b/include/net/phonet/pn_dev.h @@ -0,0 +1,61 @@ +/* + * File: pn_dev.h + * + * Phonet network device + * + * Copyright (C) 2008 Nokia Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef PN_DEV_H +#define PN_DEV_H + +struct phonet_device_list { + struct list_head list; + struct mutex lock; +}; + +struct phonet_device_list *phonet_device_list(struct net *net); + +struct phonet_device { + struct list_head list; + struct net_device *netdev; + DECLARE_BITMAP(addrs, 64); + struct rcu_head rcu; +}; + +int phonet_device_init(void); +void phonet_device_exit(void); +int phonet_netlink_register(void); +struct net_device *phonet_device_get(struct net *net); + +int phonet_address_add(struct net_device *dev, u8 addr); +int phonet_address_del(struct net_device *dev, u8 addr); +u8 phonet_address_get(struct net_device *dev, u8 addr); +int phonet_address_lookup(struct net *net, u8 addr); +void phonet_address_notify(int event, struct net_device *dev, u8 addr); + +int phonet_route_add(struct net_device *dev, u8 daddr); +int phonet_route_del(struct net_device *dev, u8 daddr); +void rtm_phonet_notify(int event, struct net_device *dev, u8 dst); +struct net_device *phonet_route_get(struct net *net, u8 daddr); +struct net_device *phonet_route_output(struct net *net, u8 daddr); + +#define PN_NO_ADDR 0xff + +extern const struct file_operations pn_sock_seq_fops; + +#endif diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h new file mode 100644 index 00000000..dd3031ae --- /dev/null +++ b/include/net/pkt_cls.h @@ -0,0 +1,357 @@ +#ifndef __NET_PKT_CLS_H +#define __NET_PKT_CLS_H + +#include <linux/pkt_cls.h> +#include <net/sch_generic.h> +#include <net/act_api.h> + +/* Basic packet classifier frontend definitions. */ + +struct tcf_walker { + int stop; + int skip; + int count; + int (*fn)(struct tcf_proto *, unsigned long node, struct tcf_walker *); +}; + +extern int register_tcf_proto_ops(struct tcf_proto_ops *ops); +extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); + +static inline unsigned long +__cls_set_class(unsigned long *clp, unsigned long cl) +{ + unsigned long old_cl; + + old_cl = *clp; + *clp = cl; + return old_cl; +} + +static inline unsigned long +cls_set_class(struct tcf_proto *tp, unsigned long *clp, + unsigned long cl) +{ + unsigned long old_cl; + + tcf_tree_lock(tp); + old_cl = __cls_set_class(clp, cl); + tcf_tree_unlock(tp); + + return old_cl; +} + +static inline void +tcf_bind_filter(struct tcf_proto *tp, struct tcf_result *r, unsigned long base) +{ + unsigned long cl; + + cl = tp->q->ops->cl_ops->bind_tcf(tp->q, base, r->classid); + cl = cls_set_class(tp, &r->class, cl); + if (cl) + tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +} + +static inline void +tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r) +{ + unsigned long cl; + + if ((cl = __cls_set_class(&r->class, 0)) != 0) + tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +} + +struct tcf_exts { +#ifdef CONFIG_NET_CLS_ACT + struct tc_action *action; +#endif +}; + +/* Map to export classifier specific extension TLV types to the + * generic extensions API. Unsupported extensions must be set to 0. + */ +struct tcf_ext_map { + int action; + int police; +}; + +/** + * tcf_exts_is_predicative - check if a predicative extension is present + * @exts: tc filter extensions handle + * + * Returns 1 if a predicative extension is present, i.e. an extension which + * might cause further actions and thus overrule the regular tcf_result. + */ +static inline int +tcf_exts_is_predicative(struct tcf_exts *exts) +{ +#ifdef CONFIG_NET_CLS_ACT + return !!exts->action; +#else + return 0; +#endif +} + +/** + * tcf_exts_is_available - check if at least one extension is present + * @exts: tc filter extensions handle + * + * Returns 1 if at least one extension is present. + */ +static inline int +tcf_exts_is_available(struct tcf_exts *exts) +{ + /* All non-predicative extensions must be added here. */ + return tcf_exts_is_predicative(exts); +} + +/** + * tcf_exts_exec - execute tc filter extensions + * @skb: socket buffer + * @exts: tc filter extensions handle + * @res: desired result + * + * Executes all configured extensions. Returns 0 on a normal execution, + * a negative number if the filter must be considered unmatched or + * a positive action code (TC_ACT_*) which must be returned to the + * underlying layer. + */ +static inline int +tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts, + struct tcf_result *res) +{ +#ifdef CONFIG_NET_CLS_ACT + if (exts->action) + return tcf_action_exec(skb, exts->action, res); +#endif + return 0; +} + +extern int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb, + struct nlattr *rate_tlv, struct tcf_exts *exts, + const struct tcf_ext_map *map); +extern void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts); +extern void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, + struct tcf_exts *src); +extern int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, + const struct tcf_ext_map *map); +extern int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts, + const struct tcf_ext_map *map); + +/** + * struct tcf_pkt_info - packet information + */ +struct tcf_pkt_info { + unsigned char * ptr; + int nexthdr; +}; + +#ifdef CONFIG_NET_EMATCH + +struct tcf_ematch_ops; + +/** + * struct tcf_ematch - extended match (ematch) + * + * @matchid: identifier to allow userspace to reidentify a match + * @flags: flags specifying attributes and the relation to other matches + * @ops: the operations lookup table of the corresponding ematch module + * @datalen: length of the ematch specific configuration data + * @data: ematch specific data + */ +struct tcf_ematch { + struct tcf_ematch_ops * ops; + unsigned long data; + unsigned int datalen; + u16 matchid; + u16 flags; +}; + +static inline int tcf_em_is_container(struct tcf_ematch *em) +{ + return !em->ops; +} + +static inline int tcf_em_is_simple(struct tcf_ematch *em) +{ + return em->flags & TCF_EM_SIMPLE; +} + +static inline int tcf_em_is_inverted(struct tcf_ematch *em) +{ + return em->flags & TCF_EM_INVERT; +} + +static inline int tcf_em_last_match(struct tcf_ematch *em) +{ + return (em->flags & TCF_EM_REL_MASK) == TCF_EM_REL_END; +} + +static inline int tcf_em_early_end(struct tcf_ematch *em, int result) +{ + if (tcf_em_last_match(em)) + return 1; + + if (result == 0 && em->flags & TCF_EM_REL_AND) + return 1; + + if (result != 0 && em->flags & TCF_EM_REL_OR) + return 1; + + return 0; +} + +/** + * struct tcf_ematch_tree - ematch tree handle + * + * @hdr: ematch tree header supplied by userspace + * @matches: array of ematches + */ +struct tcf_ematch_tree { + struct tcf_ematch_tree_hdr hdr; + struct tcf_ematch * matches; + +}; + +/** + * struct tcf_ematch_ops - ematch module operations + * + * @kind: identifier (kind) of this ematch module + * @datalen: length of expected configuration data (optional) + * @change: called during validation (optional) + * @match: called during ematch tree evaluation, must return 1/0 + * @destroy: called during destroyage (optional) + * @dump: called during dumping process (optional) + * @owner: owner, must be set to THIS_MODULE + * @link: link to previous/next ematch module (internal use) + */ +struct tcf_ematch_ops { + int kind; + int datalen; + int (*change)(struct tcf_proto *, void *, + int, struct tcf_ematch *); + int (*match)(struct sk_buff *, struct tcf_ematch *, + struct tcf_pkt_info *); + void (*destroy)(struct tcf_proto *, + struct tcf_ematch *); + int (*dump)(struct sk_buff *, struct tcf_ematch *); + struct module *owner; + struct list_head link; +}; + +extern int tcf_em_register(struct tcf_ematch_ops *); +extern void tcf_em_unregister(struct tcf_ematch_ops *); +extern int tcf_em_tree_validate(struct tcf_proto *, struct nlattr *, + struct tcf_ematch_tree *); +extern void tcf_em_tree_destroy(struct tcf_proto *, struct tcf_ematch_tree *); +extern int tcf_em_tree_dump(struct sk_buff *, struct tcf_ematch_tree *, int); +extern int __tcf_em_tree_match(struct sk_buff *, struct tcf_ematch_tree *, + struct tcf_pkt_info *); + +/** + * tcf_em_tree_change - replace ematch tree of a running classifier + * + * @tp: classifier kind handle + * @dst: destination ematch tree variable + * @src: source ematch tree (temporary tree from tcf_em_tree_validate) + * + * This functions replaces the ematch tree in @dst with the ematch + * tree in @src. The classifier in charge of the ematch tree may be + * running. + */ +static inline void tcf_em_tree_change(struct tcf_proto *tp, + struct tcf_ematch_tree *dst, + struct tcf_ematch_tree *src) +{ + tcf_tree_lock(tp); + memcpy(dst, src, sizeof(*dst)); + tcf_tree_unlock(tp); +} + +/** + * tcf_em_tree_match - evaulate an ematch tree + * + * @skb: socket buffer of the packet in question + * @tree: ematch tree to be used for evaluation + * @info: packet information examined by classifier + * + * This function matches @skb against the ematch tree in @tree by going + * through all ematches respecting their logic relations returning + * as soon as the result is obvious. + * + * Returns 1 if the ematch tree as-one matches, no ematches are configured + * or ematch is not enabled in the kernel, otherwise 0 is returned. + */ +static inline int tcf_em_tree_match(struct sk_buff *skb, + struct tcf_ematch_tree *tree, + struct tcf_pkt_info *info) +{ + if (tree->hdr.nmatches) + return __tcf_em_tree_match(skb, tree, info); + else + return 1; +} + +#define MODULE_ALIAS_TCF_EMATCH(kind) MODULE_ALIAS("ematch-kind-" __stringify(kind)) + +#else /* CONFIG_NET_EMATCH */ + +struct tcf_ematch_tree { +}; + +#define tcf_em_tree_validate(tp, tb, t) ((void)(t), 0) +#define tcf_em_tree_destroy(tp, t) do { (void)(t); } while(0) +#define tcf_em_tree_dump(skb, t, tlv) (0) +#define tcf_em_tree_change(tp, dst, src) do { } while(0) +#define tcf_em_tree_match(skb, t, info) ((void)(info), 1) + +#endif /* CONFIG_NET_EMATCH */ + +static inline unsigned char * tcf_get_base_ptr(struct sk_buff *skb, int layer) +{ + switch (layer) { + case TCF_LAYER_LINK: + return skb->data; + case TCF_LAYER_NETWORK: + return skb_network_header(skb); + case TCF_LAYER_TRANSPORT: + return skb_transport_header(skb); + } + + return NULL; +} + +static inline int tcf_valid_offset(const struct sk_buff *skb, + const unsigned char *ptr, const int len) +{ + return unlikely((ptr + len) < skb_tail_pointer(skb) && ptr > skb->head); +} + +#ifdef CONFIG_NET_CLS_IND +#include <net/net_namespace.h> + +static inline int +tcf_change_indev(struct tcf_proto *tp, char *indev, struct nlattr *indev_tlv) +{ + if (nla_strlcpy(indev, indev_tlv, IFNAMSIZ) >= IFNAMSIZ) + return -EINVAL; + return 0; +} + +static inline int +tcf_match_indev(struct sk_buff *skb, char *indev) +{ + struct net_device *dev; + + if (indev[0]) { + if (!skb->skb_iif) + return 0; + dev = __dev_get_by_index(dev_net(skb->dev), skb->skb_iif); + if (!dev || strcmp(indev, dev->name)) + return 0; + } + + return 1; +} +#endif /* CONFIG_NET_CLS_IND */ + +#endif diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h new file mode 100644 index 00000000..d9549af6 --- /dev/null +++ b/include/net/pkt_sched.h @@ -0,0 +1,115 @@ +#ifndef __NET_PKT_SCHED_H +#define __NET_PKT_SCHED_H + +#include <linux/jiffies.h> +#include <linux/ktime.h> +#include <net/sch_generic.h> + +struct qdisc_walker { + int stop; + int skip; + int count; + int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *); +}; + +#define QDISC_ALIGNTO 64 +#define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1)) + +static inline void *qdisc_priv(struct Qdisc *q) +{ + return (char *) q + QDISC_ALIGN(sizeof(struct Qdisc)); +} + +/* + Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth + + Normal IP packet size ~ 512byte, hence: + + 0.5Kbyte/1Mbyte/sec = 0.5msec, so that we need 50usec timer for + 10Mbit ethernet. + + 10msec resolution -> <50Kbit/sec. + + The result: [34]86 is not good choice for QoS router :-( + + The things are not so bad, because we may use artifical + clock evaluated by integration of network data flow + in the most critical places. + */ + +typedef u64 psched_time_t; +typedef long psched_tdiff_t; + +/* Avoid doing 64 bit divide */ +#define PSCHED_SHIFT 6 +#define PSCHED_TICKS2NS(x) ((s64)(x) << PSCHED_SHIFT) +#define PSCHED_NS2TICKS(x) ((x) >> PSCHED_SHIFT) + +#define PSCHED_TICKS_PER_SEC PSCHED_NS2TICKS(NSEC_PER_SEC) +#define PSCHED_PASTPERFECT 0 + +static inline psched_time_t psched_get_time(void) +{ + return PSCHED_NS2TICKS(ktime_to_ns(ktime_get())); +} + +static inline psched_tdiff_t +psched_tdiff_bounded(psched_time_t tv1, psched_time_t tv2, psched_time_t bound) +{ + return min(tv1 - tv2, bound); +} + +struct qdisc_watchdog { + struct hrtimer timer; + struct Qdisc *qdisc; +}; + +extern void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc); +extern void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, + psched_time_t expires); +extern void qdisc_watchdog_cancel(struct qdisc_watchdog *wd); + +extern struct Qdisc_ops pfifo_qdisc_ops; +extern struct Qdisc_ops bfifo_qdisc_ops; +extern struct Qdisc_ops pfifo_head_drop_qdisc_ops; + +extern int fifo_set_limit(struct Qdisc *q, unsigned int limit); +extern struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, + unsigned int limit); + +extern int register_qdisc(struct Qdisc_ops *qops); +extern int unregister_qdisc(struct Qdisc_ops *qops); +extern void qdisc_list_del(struct Qdisc *q); +extern struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); +extern struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); +extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, + struct nlattr *tab); +extern void qdisc_put_rtab(struct qdisc_rate_table *tab); +extern void qdisc_put_stab(struct qdisc_size_table *tab); +extern void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc); +extern int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, + struct net_device *dev, struct netdev_queue *txq, + spinlock_t *root_lock); + +extern void __qdisc_run(struct Qdisc *q); + +static inline void qdisc_run(struct Qdisc *q) +{ + if (qdisc_run_begin(q)) + __qdisc_run(q); +} + +extern int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp, + struct tcf_result *res); +extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, + struct tcf_result *res); + +/* Calculate maximal size of packet seen by hard_start_xmit + routine of this device. + */ +static inline unsigned psched_mtu(const struct net_device *dev) +{ + return dev->mtu + dev->hard_header_len; +} + +#endif diff --git a/include/net/protocol.h b/include/net/protocol.h new file mode 100644 index 00000000..f1effdd3 --- /dev/null +++ b/include/net/protocol.h @@ -0,0 +1,110 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the protocol dispatcher. + * + * Version: @(#)protocol.h 1.0.2 05/07/93 + * + * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Changes: + * Alan Cox : Added a name field and a frag handler + * field for later. + * Alan Cox : Cleaned up, and sorted types. + * Pedro Roque : inet6 protocols + */ + +#ifndef _PROTOCOL_H +#define _PROTOCOL_H + +#include <linux/in6.h> +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +#include <linux/ipv6.h> +#endif + +#define MAX_INET_PROTOS 256 /* Must be a power of 2 */ + + +/* This is used to register protocols. */ +struct net_protocol { + int (*handler)(struct sk_buff *skb); + void (*err_handler)(struct sk_buff *skb, u32 info); + int (*gso_send_check)(struct sk_buff *skb); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); + struct sk_buff **(*gro_receive)(struct sk_buff **head, + struct sk_buff *skb); + int (*gro_complete)(struct sk_buff *skb); + unsigned int no_policy:1, + netns_ok:1; +}; + +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +struct inet6_protocol { + int (*handler)(struct sk_buff *skb); + + void (*err_handler)(struct sk_buff *skb, + struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, + __be32 info); + + int (*gso_send_check)(struct sk_buff *skb); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); + struct sk_buff **(*gro_receive)(struct sk_buff **head, + struct sk_buff *skb); + int (*gro_complete)(struct sk_buff *skb); + + unsigned int flags; /* INET6_PROTO_xxx */ +}; + +#define INET6_PROTO_NOPOLICY 0x1 +#define INET6_PROTO_FINAL 0x2 +/* This should be set for any extension header which is compatible with GSO. */ +#define INET6_PROTO_GSO_EXTHDR 0x4 +#endif + +/* This is used to register socket interfaces for IP protocols. */ +struct inet_protosw { + struct list_head list; + + /* These two fields form the lookup key. */ + unsigned short type; /* This is the 2nd argument to socket(2). */ + unsigned short protocol; /* This is the L4 protocol number. */ + + struct proto *prot; + const struct proto_ops *ops; + + char no_check; /* checksum on rcv/xmit/none? */ + unsigned char flags; /* See INET_PROTOSW_* below. */ +}; +#define INET_PROTOSW_REUSE 0x01 /* Are ports automatically reusable? */ +#define INET_PROTOSW_PERMANENT 0x02 /* Permanent protocols are unremovable. */ +#define INET_PROTOSW_ICSK 0x04 /* Is this an inet_connection_sock? */ + +extern const struct net_protocol *inet_protos[MAX_INET_PROTOS]; + +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +extern const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; +#endif + +extern int inet_add_protocol(const struct net_protocol *prot, unsigned char num); +extern int inet_del_protocol(const struct net_protocol *prot, unsigned char num); +extern void inet_register_protosw(struct inet_protosw *p); +extern void inet_unregister_protosw(struct inet_protosw *p); + +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +extern int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char num); +extern int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char num); +extern int inet6_register_protosw(struct inet_protosw *p); +extern void inet6_unregister_protosw(struct inet_protosw *p); +#endif + +#endif /* _PROTOCOL_H */ diff --git a/include/net/psnap.h b/include/net/psnap.h new file mode 100644 index 00000000..fe456c29 --- /dev/null +++ b/include/net/psnap.h @@ -0,0 +1,11 @@ +#ifndef _NET_PSNAP_H +#define _NET_PSNAP_H + +extern struct datalink_proto * +register_snap_client(const unsigned char *desc, + int (*rcvfunc)(struct sk_buff *, struct net_device *, + struct packet_type *, + struct net_device *orig_dev)); +extern void unregister_snap_client(struct datalink_proto *proto); + +#endif diff --git a/include/net/raw.h b/include/net/raw.h new file mode 100644 index 00000000..43c57502 --- /dev/null +++ b/include/net/raw.h @@ -0,0 +1,72 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the RAW-IP module. + * + * Version: @(#)raw.h 1.0.2 05/07/93 + * + * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _RAW_H +#define _RAW_H + + +#include <net/protocol.h> +#include <linux/icmp.h> + +extern struct proto raw_prot; + +void raw_icmp_error(struct sk_buff *, int, u32); +int raw_local_deliver(struct sk_buff *, int); + +extern int raw_rcv(struct sock *, struct sk_buff *); + +#define RAW_HTABLE_SIZE MAX_INET_PROTOS + +struct raw_hashinfo { + rwlock_t lock; + struct hlist_head ht[RAW_HTABLE_SIZE]; +}; + +#ifdef CONFIG_PROC_FS +extern int raw_proc_init(void); +extern void raw_proc_exit(void); + +struct raw_iter_state { + struct seq_net_private p; + int bucket; + struct raw_hashinfo *h; +}; + +#define raw_seq_private(seq) ((struct raw_iter_state *)(seq)->private) +void *raw_seq_start(struct seq_file *seq, loff_t *pos); +void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos); +void raw_seq_stop(struct seq_file *seq, void *v); +int raw_seq_open(struct inode *ino, struct file *file, + struct raw_hashinfo *h, const struct seq_operations *ops); + +#endif + +void raw_hash_sk(struct sock *sk); +void raw_unhash_sk(struct sock *sk); + +struct raw_sock { + /* inet_sock has to be the first member */ + struct inet_sock inet; + struct icmp_filter filter; + u32 ipmr_table; +}; + +static inline struct raw_sock *raw_sk(const struct sock *sk) +{ + return (struct raw_sock *)sk; +} + +#endif /* _RAW_H */ diff --git a/include/net/rawv6.h b/include/net/rawv6.h new file mode 100644 index 00000000..f6b9b830 --- /dev/null +++ b/include/net/rawv6.h @@ -0,0 +1,24 @@ +#ifndef _NET_RAWV6_H +#define _NET_RAWV6_H + +#ifdef __KERNEL__ + +#include <net/protocol.h> + +void raw6_icmp_error(struct sk_buff *, int nexthdr, + u8 type, u8 code, int inner_offset, __be32); +int raw6_local_deliver(struct sk_buff *, int); + +extern int rawv6_rcv(struct sock *sk, + struct sk_buff *skb); + +#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) +int rawv6_mh_filter_register(int (*filter)(struct sock *sock, + struct sk_buff *skb)); +int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock, + struct sk_buff *skb)); +#endif + +#endif + +#endif diff --git a/include/net/red.h b/include/net/red.h new file mode 100644 index 00000000..995108e5 --- /dev/null +++ b/include/net/red.h @@ -0,0 +1,322 @@ +#ifndef __NET_SCHED_RED_H +#define __NET_SCHED_RED_H + +#include <linux/types.h> +#include <net/pkt_sched.h> +#include <net/inet_ecn.h> +#include <net/dsfield.h> + +/* Random Early Detection (RED) algorithm. + ======================================= + + Source: Sally Floyd and Van Jacobson, "Random Early Detection Gateways + for Congestion Avoidance", 1993, IEEE/ACM Transactions on Networking. + + This file codes a "divisionless" version of RED algorithm + as written down in Fig.17 of the paper. + + Short description. + ------------------ + + When a new packet arrives we calculate the average queue length: + + avg = (1-W)*avg + W*current_queue_len, + + W is the filter time constant (chosen as 2^(-Wlog)), it controls + the inertia of the algorithm. To allow larger bursts, W should be + decreased. + + if (avg > th_max) -> packet marked (dropped). + if (avg < th_min) -> packet passes. + if (th_min < avg < th_max) we calculate probability: + + Pb = max_P * (avg - th_min)/(th_max-th_min) + + and mark (drop) packet with this probability. + Pb changes from 0 (at avg==th_min) to max_P (avg==th_max). + max_P should be small (not 1), usually 0.01..0.02 is good value. + + max_P is chosen as a number, so that max_P/(th_max-th_min) + is a negative power of two in order arithmetics to contain + only shifts. + + + Parameters, settable by user: + ----------------------------- + + qth_min - bytes (should be < qth_max/2) + qth_max - bytes (should be at least 2*qth_min and less limit) + Wlog - bits (<32) log(1/W). + Plog - bits (<32) + + Plog is related to max_P by formula: + + max_P = (qth_max-qth_min)/2^Plog; + + F.e. if qth_max=128K and qth_min=32K, then Plog=22 + corresponds to max_P=0.02 + + Scell_log + Stab + + Lookup table for log((1-W)^(t/t_ave). + + + NOTES: + + Upper bound on W. + ----------------- + + If you want to allow bursts of L packets of size S, + you should choose W: + + L + 1 - th_min/S < (1-(1-W)^L)/W + + th_min/S = 32 th_min/S = 4 + + log(W) L + -1 33 + -2 35 + -3 39 + -4 46 + -5 57 + -6 75 + -7 101 + -8 135 + -9 190 + etc. + */ + +#define RED_STAB_SIZE 256 +#define RED_STAB_MASK (RED_STAB_SIZE - 1) + +struct red_stats { + u32 prob_drop; /* Early probability drops */ + u32 prob_mark; /* Early probability marks */ + u32 forced_drop; /* Forced drops, qavg > max_thresh */ + u32 forced_mark; /* Forced marks, qavg > max_thresh */ + u32 pdrop; /* Drops due to queue limits */ + u32 other; /* Drops due to drop() calls */ + u32 backlog; +}; + +struct red_parms { + /* Parameters */ + u32 qth_min; /* Min avg length threshold: A scaled */ + u32 qth_max; /* Max avg length threshold: A scaled */ + u32 Scell_max; + u32 Rmask; /* Cached random mask, see red_rmask */ + u8 Scell_log; + u8 Wlog; /* log(W) */ + u8 Plog; /* random number bits */ + u8 Stab[RED_STAB_SIZE]; + + /* Variables */ + int qcount; /* Number of packets since last random + number generation */ + u32 qR; /* Cached random number */ + + unsigned long qavg; /* Average queue length: A scaled */ + psched_time_t qidlestart; /* Start of current idle period */ +}; + +static inline u32 red_rmask(u8 Plog) +{ + return Plog < 32 ? ((1 << Plog) - 1) : ~0UL; +} + +static inline void red_set_parms(struct red_parms *p, + u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog, + u8 Scell_log, u8 *stab) +{ + /* Reset average queue length, the value is strictly bound + * to the parameters below, reseting hurts a bit but leaving + * it might result in an unreasonable qavg for a while. --TGR + */ + p->qavg = 0; + + p->qcount = -1; + p->qth_min = qth_min << Wlog; + p->qth_max = qth_max << Wlog; + p->Wlog = Wlog; + p->Plog = Plog; + p->Rmask = red_rmask(Plog); + p->Scell_log = Scell_log; + p->Scell_max = (255 << Scell_log); + + memcpy(p->Stab, stab, sizeof(p->Stab)); +} + +static inline int red_is_idling(struct red_parms *p) +{ + return p->qidlestart != PSCHED_PASTPERFECT; +} + +static inline void red_start_of_idle_period(struct red_parms *p) +{ + p->qidlestart = psched_get_time(); +} + +static inline void red_end_of_idle_period(struct red_parms *p) +{ + p->qidlestart = PSCHED_PASTPERFECT; +} + +static inline void red_restart(struct red_parms *p) +{ + red_end_of_idle_period(p); + p->qavg = 0; + p->qcount = -1; +} + +static inline unsigned long red_calc_qavg_from_idle_time(struct red_parms *p) +{ + psched_time_t now; + long us_idle; + int shift; + + now = psched_get_time(); + us_idle = psched_tdiff_bounded(now, p->qidlestart, p->Scell_max); + + /* + * The problem: ideally, average length queue recalcultion should + * be done over constant clock intervals. This is too expensive, so + * that the calculation is driven by outgoing packets. + * When the queue is idle we have to model this clock by hand. + * + * SF+VJ proposed to "generate": + * + * m = idletime / (average_pkt_size / bandwidth) + * + * dummy packets as a burst after idle time, i.e. + * + * p->qavg *= (1-W)^m + * + * This is an apparently overcomplicated solution (f.e. we have to + * precompute a table to make this calculation in reasonable time) + * I believe that a simpler model may be used here, + * but it is field for experiments. + */ + + shift = p->Stab[(us_idle >> p->Scell_log) & RED_STAB_MASK]; + + if (shift) + return p->qavg >> shift; + else { + /* Approximate initial part of exponent with linear function: + * + * (1-W)^m ~= 1-mW + ... + * + * Seems, it is the best solution to + * problem of too coarse exponent tabulation. + */ + us_idle = (p->qavg * (u64)us_idle) >> p->Scell_log; + + if (us_idle < (p->qavg >> 1)) + return p->qavg - us_idle; + else + return p->qavg >> 1; + } +} + +static inline unsigned long red_calc_qavg_no_idle_time(struct red_parms *p, + unsigned int backlog) +{ + /* + * NOTE: p->qavg is fixed point number with point at Wlog. + * The formula below is equvalent to floating point + * version: + * + * qavg = qavg*(1-W) + backlog*W; + * + * --ANK (980924) + */ + return p->qavg + (backlog - (p->qavg >> p->Wlog)); +} + +static inline unsigned long red_calc_qavg(struct red_parms *p, + unsigned int backlog) +{ + if (!red_is_idling(p)) + return red_calc_qavg_no_idle_time(p, backlog); + else + return red_calc_qavg_from_idle_time(p); +} + +static inline u32 red_random(struct red_parms *p) +{ + return net_random() & p->Rmask; +} + +static inline int red_mark_probability(struct red_parms *p, unsigned long qavg) +{ + /* The formula used below causes questions. + + OK. qR is random number in the interval 0..Rmask + i.e. 0..(2^Plog). If we used floating point + arithmetics, it would be: (2^Plog)*rnd_num, + where rnd_num is less 1. + + Taking into account, that qavg have fixed + point at Wlog, and Plog is related to max_P by + max_P = (qth_max-qth_min)/2^Plog; two lines + below have the following floating point equivalent: + + max_P*(qavg - qth_min)/(qth_max-qth_min) < rnd/qcount + + Any questions? --ANK (980924) + */ + return !(((qavg - p->qth_min) >> p->Wlog) * p->qcount < p->qR); +} + +enum { + RED_BELOW_MIN_THRESH, + RED_BETWEEN_TRESH, + RED_ABOVE_MAX_TRESH, +}; + +static inline int red_cmp_thresh(struct red_parms *p, unsigned long qavg) +{ + if (qavg < p->qth_min) + return RED_BELOW_MIN_THRESH; + else if (qavg >= p->qth_max) + return RED_ABOVE_MAX_TRESH; + else + return RED_BETWEEN_TRESH; +} + +enum { + RED_DONT_MARK, + RED_PROB_MARK, + RED_HARD_MARK, +}; + +static inline int red_action(struct red_parms *p, unsigned long qavg) +{ + switch (red_cmp_thresh(p, qavg)) { + case RED_BELOW_MIN_THRESH: + p->qcount = -1; + return RED_DONT_MARK; + + case RED_BETWEEN_TRESH: + if (++p->qcount) { + if (red_mark_probability(p, qavg)) { + p->qcount = 0; + p->qR = red_random(p); + return RED_PROB_MARK; + } + } else + p->qR = red_random(p); + + return RED_DONT_MARK; + + case RED_ABOVE_MAX_TRESH: + p->qcount = -1; + return RED_HARD_MARK; + } + + BUG(); + return RED_DONT_MARK; +} + +#endif diff --git a/include/net/regulatory.h b/include/net/regulatory.h new file mode 100644 index 00000000..9e103a4e --- /dev/null +++ b/include/net/regulatory.h @@ -0,0 +1,101 @@ +#ifndef __NET_REGULATORY_H +#define __NET_REGULATORY_H +/* + * regulatory support structures + * + * Copyright 2008-2009 Luis R. Rodriguez <lrodriguez@atheros.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +/** + * enum environment_cap - Environment parsed from country IE + * @ENVIRON_ANY: indicates country IE applies to both indoor and + * outdoor operation. + * @ENVIRON_INDOOR: indicates country IE applies only to indoor operation + * @ENVIRON_OUTDOOR: indicates country IE applies only to outdoor operation + */ +enum environment_cap { + ENVIRON_ANY, + ENVIRON_INDOOR, + ENVIRON_OUTDOOR, +}; + +/** + * struct regulatory_request - used to keep track of regulatory requests + * + * @wiphy_idx: this is set if this request's initiator is + * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This + * can be used by the wireless core to deal with conflicts + * and potentially inform users of which devices specifically + * cased the conflicts. + * @initiator: indicates who sent this request, could be any of + * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) + * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested + * regulatory domain. We have a few special codes: + * 00 - World regulatory domain + * 99 - built by driver but a specific alpha2 cannot be determined + * 98 - result of an intersection between two regulatory domains + * 97 - regulatory domain has not yet been configured + * @intersect: indicates whether the wireless core should intersect + * the requested regulatory domain with the presently set regulatory + * domain. + * @country_ie_checksum: checksum of the last processed and accepted + * country IE + * @country_ie_env: lets us know if the AP is telling us we are outdoor, + * indoor, or if it doesn't matter + * @list: used to insert into the reg_requests_list linked list + */ +struct regulatory_request { + int wiphy_idx; + enum nl80211_reg_initiator initiator; + char alpha2[2]; + bool intersect; + enum environment_cap country_ie_env; + struct list_head list; +}; + +struct ieee80211_freq_range { + u32 start_freq_khz; + u32 end_freq_khz; + u32 max_bandwidth_khz; +}; + +struct ieee80211_power_rule { + u32 max_antenna_gain; + u32 max_eirp; +}; + +struct ieee80211_reg_rule { + struct ieee80211_freq_range freq_range; + struct ieee80211_power_rule power_rule; + u32 flags; +}; + +struct ieee80211_regdomain { + u32 n_reg_rules; + char alpha2[2]; + struct ieee80211_reg_rule reg_rules[]; +}; + +#define MHZ_TO_KHZ(freq) ((freq) * 1000) +#define KHZ_TO_MHZ(freq) ((freq) / 1000) +#define DBI_TO_MBI(gain) ((gain) * 100) +#define MBI_TO_DBI(gain) ((gain) / 100) +#define DBM_TO_MBM(gain) ((gain) * 100) +#define MBM_TO_DBM(gain) ((gain) / 100) + +#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ +{ \ + .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ + .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ + .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ + .power_rule.max_antenna_gain = DBI_TO_MBI(gain),\ + .power_rule.max_eirp = DBM_TO_MBM(eirp), \ + .flags = reg_flags, \ +} + +#endif diff --git a/include/net/request_sock.h b/include/net/request_sock.h new file mode 100644 index 00000000..99e6e19b --- /dev/null +++ b/include/net/request_sock.h @@ -0,0 +1,257 @@ +/* + * NET Generic infrastructure for Network protocols. + * + * Definitions for request_sock + * + * Authors: Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * From code originally in include/net/tcp.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _REQUEST_SOCK_H +#define _REQUEST_SOCK_H + +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/bug.h> + +#include <net/sock.h> + +struct request_sock; +struct sk_buff; +struct dst_entry; +struct proto; + +/* empty to "strongly type" an otherwise void parameter. + */ +struct request_values { +}; + +struct request_sock_ops { + int family; + int obj_size; + struct kmem_cache *slab; + char *slab_name; + int (*rtx_syn_ack)(struct sock *sk, + struct request_sock *req, + struct request_values *rvp); + void (*send_ack)(struct sock *sk, struct sk_buff *skb, + struct request_sock *req); + void (*send_reset)(struct sock *sk, + struct sk_buff *skb); + void (*destructor)(struct request_sock *req); + void (*syn_ack_timeout)(struct sock *sk, + struct request_sock *req); +}; + +/* struct request_sock - mini sock to represent a connection request + */ +struct request_sock { + struct request_sock *dl_next; /* Must be first member! */ + u16 mss; + u8 retrans; + u8 cookie_ts; /* syncookie: encode tcpopts in timestamp */ + /* The following two fields can be easily recomputed I think -AK */ + u32 window_clamp; /* window clamp at creation time */ + u32 rcv_wnd; /* rcv_wnd offered first time */ + u32 ts_recent; + unsigned long expires; + const struct request_sock_ops *rsk_ops; + struct sock *sk; + u32 secid; + u32 peer_secid; +}; + +static inline struct request_sock *reqsk_alloc(const struct request_sock_ops *ops) +{ + struct request_sock *req = kmem_cache_alloc(ops->slab, GFP_ATOMIC); + + if (req != NULL) + req->rsk_ops = ops; + + return req; +} + +static inline void __reqsk_free(struct request_sock *req) +{ + kmem_cache_free(req->rsk_ops->slab, req); +} + +static inline void reqsk_free(struct request_sock *req) +{ + req->rsk_ops->destructor(req); + __reqsk_free(req); +} + +extern int sysctl_max_syn_backlog; + +/** struct listen_sock - listen state + * + * @max_qlen_log - log_2 of maximal queued SYNs/REQUESTs + */ +struct listen_sock { + u8 max_qlen_log; + /* 3 bytes hole, try to use */ + int qlen; + int qlen_young; + int clock_hand; + u32 hash_rnd; + u32 nr_table_entries; + struct request_sock *syn_table[0]; +}; + +/** struct request_sock_queue - queue of request_socks + * + * @rskq_accept_head - FIFO head of established children + * @rskq_accept_tail - FIFO tail of established children + * @rskq_defer_accept - User waits for some data after accept() + * @syn_wait_lock - serializer + * + * %syn_wait_lock is necessary only to avoid proc interface having to grab the main + * lock sock while browsing the listening hash (otherwise it's deadlock prone). + * + * This lock is acquired in read mode only from listening_get_next() seq_file + * op and it's acquired in write mode _only_ from code that is actively + * changing rskq_accept_head. All readers that are holding the master sock lock + * don't need to grab this lock in read mode too as rskq_accept_head. writes + * are always protected from the main sock lock. + */ +struct request_sock_queue { + struct request_sock *rskq_accept_head; + struct request_sock *rskq_accept_tail; + rwlock_t syn_wait_lock; + u8 rskq_defer_accept; + /* 3 bytes hole, try to pack */ + struct listen_sock *listen_opt; +}; + +extern int reqsk_queue_alloc(struct request_sock_queue *queue, + unsigned int nr_table_entries); + +extern void __reqsk_queue_destroy(struct request_sock_queue *queue); +extern void reqsk_queue_destroy(struct request_sock_queue *queue); + +static inline struct request_sock * + reqsk_queue_yank_acceptq(struct request_sock_queue *queue) +{ + struct request_sock *req = queue->rskq_accept_head; + + queue->rskq_accept_head = NULL; + return req; +} + +static inline int reqsk_queue_empty(struct request_sock_queue *queue) +{ + return queue->rskq_accept_head == NULL; +} + +static inline void reqsk_queue_unlink(struct request_sock_queue *queue, + struct request_sock *req, + struct request_sock **prev_req) +{ + write_lock(&queue->syn_wait_lock); + *prev_req = req->dl_next; + write_unlock(&queue->syn_wait_lock); +} + +static inline void reqsk_queue_add(struct request_sock_queue *queue, + struct request_sock *req, + struct sock *parent, + struct sock *child) +{ + req->sk = child; + sk_acceptq_added(parent); + + if (queue->rskq_accept_head == NULL) + queue->rskq_accept_head = req; + else + queue->rskq_accept_tail->dl_next = req; + + queue->rskq_accept_tail = req; + req->dl_next = NULL; +} + +static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue *queue) +{ + struct request_sock *req = queue->rskq_accept_head; + + WARN_ON(req == NULL); + + queue->rskq_accept_head = req->dl_next; + if (queue->rskq_accept_head == NULL) + queue->rskq_accept_tail = NULL; + + return req; +} + +static inline struct sock *reqsk_queue_get_child(struct request_sock_queue *queue, + struct sock *parent) +{ + struct request_sock *req = reqsk_queue_remove(queue); + struct sock *child = req->sk; + + WARN_ON(child == NULL); + + sk_acceptq_removed(parent); + __reqsk_free(req); + return child; +} + +static inline int reqsk_queue_removed(struct request_sock_queue *queue, + struct request_sock *req) +{ + struct listen_sock *lopt = queue->listen_opt; + + if (req->retrans == 0) + --lopt->qlen_young; + + return --lopt->qlen; +} + +static inline int reqsk_queue_added(struct request_sock_queue *queue) +{ + struct listen_sock *lopt = queue->listen_opt; + const int prev_qlen = lopt->qlen; + + lopt->qlen_young++; + lopt->qlen++; + return prev_qlen; +} + +static inline int reqsk_queue_len(const struct request_sock_queue *queue) +{ + return queue->listen_opt != NULL ? queue->listen_opt->qlen : 0; +} + +static inline int reqsk_queue_len_young(const struct request_sock_queue *queue) +{ + return queue->listen_opt->qlen_young; +} + +static inline int reqsk_queue_is_full(const struct request_sock_queue *queue) +{ + return queue->listen_opt->qlen >> queue->listen_opt->max_qlen_log; +} + +static inline void reqsk_queue_hash_req(struct request_sock_queue *queue, + u32 hash, struct request_sock *req, + unsigned long timeout) +{ + struct listen_sock *lopt = queue->listen_opt; + + req->expires = jiffies + timeout; + req->retrans = 0; + req->sk = NULL; + req->dl_next = lopt->syn_table[hash]; + + write_lock(&queue->syn_wait_lock); + lopt->syn_table[hash] = req; + write_unlock(&queue->syn_wait_lock); +} + +#endif /* _REQUEST_SOCK_H */ diff --git a/include/net/rose.h b/include/net/rose.h new file mode 100644 index 00000000..5ba9f027 --- /dev/null +++ b/include/net/rose.h @@ -0,0 +1,235 @@ +/* + * Declarations of Rose type objects. + * + * Jonathan Naylor G4KLX 25/8/96 + */ + +#ifndef _ROSE_H +#define _ROSE_H + +#include <linux/rose.h> +#include <net/sock.h> + +#define ROSE_ADDR_LEN 5 + +#define ROSE_MIN_LEN 3 + +#define ROSE_GFI 0x10 +#define ROSE_Q_BIT 0x80 +#define ROSE_D_BIT 0x40 +#define ROSE_M_BIT 0x10 + +#define ROSE_CALL_REQUEST 0x0B +#define ROSE_CALL_ACCEPTED 0x0F +#define ROSE_CLEAR_REQUEST 0x13 +#define ROSE_CLEAR_CONFIRMATION 0x17 +#define ROSE_DATA 0x00 +#define ROSE_INTERRUPT 0x23 +#define ROSE_INTERRUPT_CONFIRMATION 0x27 +#define ROSE_RR 0x01 +#define ROSE_RNR 0x05 +#define ROSE_REJ 0x09 +#define ROSE_RESET_REQUEST 0x1B +#define ROSE_RESET_CONFIRMATION 0x1F +#define ROSE_REGISTRATION_REQUEST 0xF3 +#define ROSE_REGISTRATION_CONFIRMATION 0xF7 +#define ROSE_RESTART_REQUEST 0xFB +#define ROSE_RESTART_CONFIRMATION 0xFF +#define ROSE_DIAGNOSTIC 0xF1 +#define ROSE_ILLEGAL 0xFD + +/* Define Link State constants. */ + +enum { + ROSE_STATE_0, /* Ready */ + ROSE_STATE_1, /* Awaiting Call Accepted */ + ROSE_STATE_2, /* Awaiting Clear Confirmation */ + ROSE_STATE_3, /* Data Transfer */ + ROSE_STATE_4, /* Awaiting Reset Confirmation */ + ROSE_STATE_5 /* Deferred Call Acceptance */ +}; + +#define ROSE_DEFAULT_T0 180000 /* Default T10 T20 value */ +#define ROSE_DEFAULT_T1 200000 /* Default T11 T21 value */ +#define ROSE_DEFAULT_T2 180000 /* Default T12 T22 value */ +#define ROSE_DEFAULT_T3 180000 /* Default T13 T23 value */ +#define ROSE_DEFAULT_HB 5000 /* Default Holdback value */ +#define ROSE_DEFAULT_IDLE 0 /* No Activity Timeout - none */ +#define ROSE_DEFAULT_ROUTING 1 /* Default routing flag */ +#define ROSE_DEFAULT_FAIL_TIMEOUT 120000 /* Time until link considered usable */ +#define ROSE_DEFAULT_MAXVC 50 /* Maximum number of VCs per neighbour */ +#define ROSE_DEFAULT_WINDOW_SIZE 7 /* Default window size */ + +#define ROSE_MODULUS 8 +#define ROSE_MAX_PACKET_SIZE 251 /* Maximum packet size */ + +#define ROSE_COND_ACK_PENDING 0x01 +#define ROSE_COND_PEER_RX_BUSY 0x02 +#define ROSE_COND_OWN_RX_BUSY 0x04 + +#define FAC_NATIONAL 0x00 +#define FAC_CCITT 0x0F + +#define FAC_NATIONAL_RAND 0x7F +#define FAC_NATIONAL_FLAGS 0x3F +#define FAC_NATIONAL_DEST_DIGI 0xE9 +#define FAC_NATIONAL_SRC_DIGI 0xEB +#define FAC_NATIONAL_FAIL_CALL 0xED +#define FAC_NATIONAL_FAIL_ADD 0xEE +#define FAC_NATIONAL_DIGIS 0xEF + +#define FAC_CCITT_DEST_NSAP 0xC9 +#define FAC_CCITT_SRC_NSAP 0xCB + +struct rose_neigh { + struct rose_neigh *next; + ax25_address callsign; + ax25_digi *digipeat; + ax25_cb *ax25; + struct net_device *dev; + unsigned short count; + unsigned short use; + unsigned int number; + char restarted; + char dce_mode; + char loopback; + struct sk_buff_head queue; + struct timer_list t0timer; + struct timer_list ftimer; +}; + +struct rose_node { + struct rose_node *next; + rose_address address; + unsigned short mask; + unsigned char count; + char loopback; + struct rose_neigh *neighbour[3]; +}; + +struct rose_route { + struct rose_route *next; + unsigned int lci1, lci2; + rose_address src_addr, dest_addr; + ax25_address src_call, dest_call; + struct rose_neigh *neigh1, *neigh2; + unsigned int rand; +}; + +struct rose_sock { + struct sock sock; + rose_address source_addr, dest_addr; + ax25_address source_call, dest_call; + unsigned char source_ndigis, dest_ndigis; + ax25_address source_digis[ROSE_MAX_DIGIS]; + ax25_address dest_digis[ROSE_MAX_DIGIS]; + struct rose_neigh *neighbour; + struct net_device *device; + unsigned int lci, rand; + unsigned char state, condition, qbitincl, defer; + unsigned char cause, diagnostic; + unsigned short vs, vr, va, vl; + unsigned long t1, t2, t3, hb, idle; +#ifdef M_BIT + unsigned short fraglen; + struct sk_buff_head frag_queue; +#endif + struct sk_buff_head ack_queue; + struct rose_facilities_struct facilities; + struct timer_list timer; + struct timer_list idletimer; +}; + +#define rose_sk(sk) ((struct rose_sock *)(sk)) + +/* af_rose.c */ +extern ax25_address rose_callsign; +extern int sysctl_rose_restart_request_timeout; +extern int sysctl_rose_call_request_timeout; +extern int sysctl_rose_reset_request_timeout; +extern int sysctl_rose_clear_request_timeout; +extern int sysctl_rose_no_activity_timeout; +extern int sysctl_rose_ack_hold_back_timeout; +extern int sysctl_rose_routing_control; +extern int sysctl_rose_link_fail_timeout; +extern int sysctl_rose_maximum_vcs; +extern int sysctl_rose_window_size; +extern int rosecmp(rose_address *, rose_address *); +extern int rosecmpm(rose_address *, rose_address *, unsigned short); +extern char *rose2asc(char *buf, const rose_address *); +extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *); +extern void rose_kill_by_neigh(struct rose_neigh *); +extern unsigned int rose_new_lci(struct rose_neigh *); +extern int rose_rx_call_request(struct sk_buff *, struct net_device *, struct rose_neigh *, unsigned int); +extern void rose_destroy_socket(struct sock *); + +/* rose_dev.c */ +extern void rose_setup(struct net_device *); + +/* rose_in.c */ +extern int rose_process_rx_frame(struct sock *, struct sk_buff *); + +/* rose_link.c */ +extern void rose_start_ftimer(struct rose_neigh *); +extern void rose_stop_ftimer(struct rose_neigh *); +extern void rose_stop_t0timer(struct rose_neigh *); +extern int rose_ftimer_running(struct rose_neigh *); +extern void rose_link_rx_restart(struct sk_buff *, struct rose_neigh *, unsigned short); +extern void rose_transmit_clear_request(struct rose_neigh *, unsigned int, unsigned char, unsigned char); +extern void rose_transmit_link(struct sk_buff *, struct rose_neigh *); + +/* rose_loopback.c */ +extern void rose_loopback_init(void); +extern void rose_loopback_clear(void); +extern int rose_loopback_queue(struct sk_buff *, struct rose_neigh *); + +/* rose_out.c */ +extern void rose_kick(struct sock *); +extern void rose_enquiry_response(struct sock *); + +/* rose_route.c */ +extern struct rose_neigh *rose_loopback_neigh; +extern const struct file_operations rose_neigh_fops; +extern const struct file_operations rose_nodes_fops; +extern const struct file_operations rose_routes_fops; + +extern void rose_add_loopback_neigh(void); +extern int __must_check rose_add_loopback_node(rose_address *); +extern void rose_del_loopback_node(rose_address *); +extern void rose_rt_device_down(struct net_device *); +extern void rose_link_device_down(struct net_device *); +extern struct net_device *rose_dev_first(void); +extern struct net_device *rose_dev_get(rose_address *); +extern struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *); +extern struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsigned char *, int); +extern int rose_rt_ioctl(unsigned int, void __user *); +extern void rose_link_failed(ax25_cb *, int); +extern int rose_route_frame(struct sk_buff *, ax25_cb *); +extern void rose_rt_free(void); + +/* rose_subr.c */ +extern void rose_clear_queues(struct sock *); +extern void rose_frames_acked(struct sock *, unsigned short); +extern void rose_requeue_frames(struct sock *); +extern int rose_validate_nr(struct sock *, unsigned short); +extern void rose_write_internal(struct sock *, int); +extern int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *); +extern int rose_parse_facilities(unsigned char *, struct rose_facilities_struct *); +extern void rose_disconnect(struct sock *, int, int, int); + +/* rose_timer.c */ +extern void rose_start_heartbeat(struct sock *); +extern void rose_start_t1timer(struct sock *); +extern void rose_start_t2timer(struct sock *); +extern void rose_start_t3timer(struct sock *); +extern void rose_start_hbtimer(struct sock *); +extern void rose_start_idletimer(struct sock *); +extern void rose_stop_heartbeat(struct sock *); +extern void rose_stop_timer(struct sock *); +extern void rose_stop_idletimer(struct sock *); + +/* sysctl_net_rose.c */ +extern void rose_register_sysctl(void); +extern void rose_unregister_sysctl(void); + +#endif diff --git a/include/net/route.h b/include/net/route.h new file mode 100644 index 00000000..7e5e73bf --- /dev/null +++ b/include/net/route.h @@ -0,0 +1,228 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the IP router. + * + * Version: @(#)route.h 1.0.4 05/27/93 + * + * Authors: Ross Biro + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Fixes: + * Alan Cox : Reformatted. Added ip_rt_local() + * Alan Cox : Support for TCP parameters. + * Alexey Kuznetsov: Major changes for new routing code. + * Mike McLagan : Routing by source + * Robert Olsson : Added rt_cache statistics + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _ROUTE_H +#define _ROUTE_H + +#include <net/dst.h> +#include <net/inetpeer.h> +#include <net/flow.h> +#include <net/inet_sock.h> +#include <linux/in_route.h> +#include <linux/rtnetlink.h> +#include <linux/route.h> +#include <linux/ip.h> +#include <linux/cache.h> +#include <linux/security.h> + +#ifndef __KERNEL__ +#warning This file is not supposed to be used outside of kernel. +#endif + +#define RTO_ONLINK 0x01 + +#define RTO_CONN 0 +/* RTO_CONN is not used (being alias for 0), but preserved not to break + * some modules referring to it. */ + +#define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE)) + +struct fib_nh; +struct inet_peer; +struct rtable { + struct dst_entry dst; + + /* Cache lookup keys */ + struct flowi fl; + + struct in_device *idev; + + int rt_genid; + unsigned rt_flags; + __u16 rt_type; + + __be32 rt_dst; /* Path destination */ + __be32 rt_src; /* Path source */ + int rt_iif; + + /* Info on neighbour */ + __be32 rt_gateway; + + /* Miscellaneous cached information */ + __be32 rt_spec_dst; /* RFC1122 specific destination */ + struct inet_peer *peer; /* long-living peer info */ +}; + +struct ip_rt_acct { + __u32 o_bytes; + __u32 o_packets; + __u32 i_bytes; + __u32 i_packets; +}; + +struct rt_cache_stat { + unsigned int in_hit; + unsigned int in_slow_tot; + unsigned int in_slow_mc; + unsigned int in_no_route; + unsigned int in_brd; + unsigned int in_martian_dst; + unsigned int in_martian_src; + unsigned int out_hit; + unsigned int out_slow_tot; + unsigned int out_slow_mc; + unsigned int gc_total; + unsigned int gc_ignored; + unsigned int gc_goal_miss; + unsigned int gc_dst_overflow; + unsigned int in_hlist_search; + unsigned int out_hlist_search; +}; + +extern struct ip_rt_acct __percpu *ip_rt_acct; + +struct in_device; +extern int ip_rt_init(void); +extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw, + __be32 src, struct net_device *dev); +extern void rt_cache_flush(struct net *net, int how); +extern void rt_cache_flush_batch(void); +extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp); +extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp); +extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags); + +extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src, + u8 tos, struct net_device *devin, bool noref); + +static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, + u8 tos, struct net_device *devin) +{ + return ip_route_input_common(skb, dst, src, tos, devin, false); +} + +static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src, + u8 tos, struct net_device *devin) +{ + return ip_route_input_common(skb, dst, src, tos, devin, true); +} + +extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev); +extern void ip_rt_send_redirect(struct sk_buff *skb); + +extern unsigned inet_addr_type(struct net *net, __be32 addr); +extern unsigned inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr); +extern void ip_rt_multicast_event(struct in_device *); +extern int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg); +extern void ip_rt_get_source(u8 *src, struct rtable *rt); +extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb); + +struct in_ifaddr; +extern void fib_add_ifaddr(struct in_ifaddr *); + +static inline void ip_rt_put(struct rtable * rt) +{ + if (rt) + dst_release(&rt->dst); +} + +#define IPTOS_RT_MASK (IPTOS_TOS_MASK & ~3) + +extern const __u8 ip_tos2prio[16]; + +static inline char rt_tos2priority(u8 tos) +{ + return ip_tos2prio[IPTOS_TOS(tos)>>1]; +} + +static inline int ip_route_connect(struct rtable **rp, __be32 dst, + __be32 src, u32 tos, int oif, u8 protocol, + __be16 sport, __be16 dport, struct sock *sk, + int flags) +{ + struct flowi fl = { .oif = oif, + .mark = sk->sk_mark, + .nl_u = { .ip4_u = { .daddr = dst, + .saddr = src, + .tos = tos } }, + .proto = protocol, + .uli_u = { .ports = + { .sport = sport, + .dport = dport } } }; + + int err; + struct net *net = sock_net(sk); + + if (inet_sk(sk)->transparent) + fl.flags |= FLOWI_FLAG_ANYSRC; + + if (!dst || !src) { + err = __ip_route_output_key(net, rp, &fl); + if (err) + return err; + fl.fl4_dst = (*rp)->rt_dst; + fl.fl4_src = (*rp)->rt_src; + ip_rt_put(*rp); + *rp = NULL; + } + security_sk_classify_flow(sk, &fl); + return ip_route_output_flow(net, rp, &fl, sk, flags); +} + +static inline int ip_route_newports(struct rtable **rp, u8 protocol, + __be16 sport, __be16 dport, struct sock *sk) +{ + if (sport != (*rp)->fl.fl_ip_sport || + dport != (*rp)->fl.fl_ip_dport) { + struct flowi fl; + + memcpy(&fl, &(*rp)->fl, sizeof(fl)); + fl.fl_ip_sport = sport; + fl.fl_ip_dport = dport; + fl.proto = protocol; + if (inet_sk(sk)->transparent) + fl.flags |= FLOWI_FLAG_ANYSRC; + ip_rt_put(*rp); + *rp = NULL; + security_sk_classify_flow(sk, &fl); + return ip_route_output_flow(sock_net(sk), rp, &fl, sk, 0); + } + return 0; +} + +extern void rt_bind_peer(struct rtable *rt, int create); + +static inline struct inet_peer *rt_get_peer(struct rtable *rt) +{ + if (rt->peer) + return rt->peer; + + rt_bind_peer(rt, 0); + return rt->peer; +} + +static inline int inet_iif(const struct sk_buff *skb) +{ + return skb_rtable(skb)->rt_iif; +} + +#endif /* _ROUTE_H */ diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h new file mode 100644 index 00000000..af60fd05 --- /dev/null +++ b/include/net/rtnetlink.h @@ -0,0 +1,96 @@ +#ifndef __NET_RTNETLINK_H +#define __NET_RTNETLINK_H + +#include <linux/rtnetlink.h> +#include <net/netlink.h> + +typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *); +typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *); + +extern int __rtnl_register(int protocol, int msgtype, + rtnl_doit_func, rtnl_dumpit_func); +extern void rtnl_register(int protocol, int msgtype, + rtnl_doit_func, rtnl_dumpit_func); +extern int rtnl_unregister(int protocol, int msgtype); +extern void rtnl_unregister_all(int protocol); + +static inline int rtnl_msg_family(const struct nlmsghdr *nlh) +{ + if (nlmsg_len(nlh) >= sizeof(struct rtgenmsg)) + return ((struct rtgenmsg *) nlmsg_data(nlh))->rtgen_family; + else + return AF_UNSPEC; +} + +/** + * struct rtnl_link_ops - rtnetlink link operations + * + * @list: Used internally + * @kind: Identifier + * @maxtype: Highest device specific netlink attribute number + * @policy: Netlink policy for device specific attribute validation + * @validate: Optional validation function for netlink/changelink parameters + * @priv_size: sizeof net_device private space + * @setup: net_device setup function + * @newlink: Function for configuring and registering a new device + * @changelink: Function for changing parameters of an existing device + * @dellink: Function to remove a device + * @get_size: Function to calculate required room for dumping device + * specific netlink attributes + * @fill_info: Function to dump device specific netlink attributes + * @get_xstats_size: Function to calculate required room for dumping devic + * specific statistics + * @fill_xstats: Function to dump device specific statistics + */ +struct rtnl_link_ops { + struct list_head list; + + const char *kind; + + size_t priv_size; + void (*setup)(struct net_device *dev); + + int maxtype; + const struct nla_policy *policy; + int (*validate)(struct nlattr *tb[], + struct nlattr *data[]); + + int (*newlink)(struct net *src_net, + struct net_device *dev, + struct nlattr *tb[], + struct nlattr *data[]); + int (*changelink)(struct net_device *dev, + struct nlattr *tb[], + struct nlattr *data[]); + void (*dellink)(struct net_device *dev, + struct list_head *head); + + size_t (*get_size)(const struct net_device *dev); + int (*fill_info)(struct sk_buff *skb, + const struct net_device *dev); + + size_t (*get_xstats_size)(const struct net_device *dev); + int (*fill_xstats)(struct sk_buff *skb, + const struct net_device *dev); + int (*get_tx_queues)(struct net *net, struct nlattr *tb[], + unsigned int *tx_queues, + unsigned int *real_tx_queues); +}; + +extern int __rtnl_link_register(struct rtnl_link_ops *ops); +extern void __rtnl_link_unregister(struct rtnl_link_ops *ops); +extern void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops); + +extern int rtnl_link_register(struct rtnl_link_ops *ops); +extern void rtnl_link_unregister(struct rtnl_link_ops *ops); + +extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); +extern struct net_device *rtnl_create_link(struct net *src_net, struct net *net, + char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]); +extern int rtnl_configure_link(struct net_device *dev, + const struct ifinfomsg *ifm); +extern const struct nla_policy ifla_policy[IFLA_MAX+1]; + +#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) + +#endif diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h new file mode 100644 index 00000000..3c8728aa --- /dev/null +++ b/include/net/sch_generic.h @@ -0,0 +1,629 @@ +#ifndef __NET_SCHED_GENERIC_H +#define __NET_SCHED_GENERIC_H + +#include <linux/netdevice.h> +#include <linux/types.h> +#include <linux/rcupdate.h> +#include <linux/module.h> +#include <linux/pkt_sched.h> +#include <linux/pkt_cls.h> +#include <net/gen_stats.h> +#include <net/rtnetlink.h> + +struct Qdisc_ops; +struct qdisc_walker; +struct tcf_walker; +struct module; + +struct qdisc_rate_table { + struct tc_ratespec rate; + u32 data[256]; + struct qdisc_rate_table *next; + int refcnt; +}; + +enum qdisc_state_t { + __QDISC_STATE_SCHED, + __QDISC_STATE_DEACTIVATED, +}; + +/* + * following bits are only changed while qdisc lock is held + */ +enum qdisc___state_t { + __QDISC___STATE_RUNNING, +}; + +struct qdisc_size_table { + struct list_head list; + struct tc_sizespec szopts; + int refcnt; + u16 data[]; +}; + +struct Qdisc { + int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev); + struct sk_buff * (*dequeue)(struct Qdisc *dev); + unsigned flags; +#define TCQ_F_BUILTIN 1 +#define TCQ_F_THROTTLED 2 +#define TCQ_F_INGRESS 4 +#define TCQ_F_CAN_BYPASS 8 +#define TCQ_F_MQROOT 16 +#define TCQ_F_WARN_NONWC (1 << 16) + int padded; + struct Qdisc_ops *ops; + struct qdisc_size_table *stab; + struct list_head list; + u32 handle; + u32 parent; + atomic_t refcnt; + struct gnet_stats_rate_est rate_est; + int (*reshape_fail)(struct sk_buff *skb, + struct Qdisc *q); + + void *u32_node; + + /* This field is deprecated, but it is still used by CBQ + * and it will live until better solution will be invented. + */ + struct Qdisc *__parent; + struct netdev_queue *dev_queue; + struct Qdisc *next_sched; + + struct sk_buff *gso_skb; + /* + * For performance sake on SMP, we put highly modified fields at the end + */ + unsigned long state; + struct sk_buff_head q; + struct gnet_stats_basic_packed bstats; + unsigned long __state; + struct gnet_stats_queue qstats; + struct rcu_head rcu_head; + spinlock_t busylock; +}; + +static inline bool qdisc_is_running(struct Qdisc *qdisc) +{ + return test_bit(__QDISC___STATE_RUNNING, &qdisc->__state); +} + +static inline bool qdisc_run_begin(struct Qdisc *qdisc) +{ + return !__test_and_set_bit(__QDISC___STATE_RUNNING, &qdisc->__state); +} + +static inline void qdisc_run_end(struct Qdisc *qdisc) +{ + __clear_bit(__QDISC___STATE_RUNNING, &qdisc->__state); +} + +struct Qdisc_class_ops { + /* Child qdisc manipulation */ + struct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *); + int (*graft)(struct Qdisc *, unsigned long cl, + struct Qdisc *, struct Qdisc **); + struct Qdisc * (*leaf)(struct Qdisc *, unsigned long cl); + void (*qlen_notify)(struct Qdisc *, unsigned long); + + /* Class manipulation routines */ + unsigned long (*get)(struct Qdisc *, u32 classid); + void (*put)(struct Qdisc *, unsigned long); + int (*change)(struct Qdisc *, u32, u32, + struct nlattr **, unsigned long *); + int (*delete)(struct Qdisc *, unsigned long); + void (*walk)(struct Qdisc *, struct qdisc_walker * arg); + + /* Filter manipulation */ + struct tcf_proto ** (*tcf_chain)(struct Qdisc *, unsigned long); + unsigned long (*bind_tcf)(struct Qdisc *, unsigned long, + u32 classid); + void (*unbind_tcf)(struct Qdisc *, unsigned long); + + /* rtnetlink specific */ + int (*dump)(struct Qdisc *, unsigned long, + struct sk_buff *skb, struct tcmsg*); + int (*dump_stats)(struct Qdisc *, unsigned long, + struct gnet_dump *); +}; + +struct Qdisc_ops { + struct Qdisc_ops *next; + const struct Qdisc_class_ops *cl_ops; + char id[IFNAMSIZ]; + int priv_size; + + int (*enqueue)(struct sk_buff *, struct Qdisc *); + struct sk_buff * (*dequeue)(struct Qdisc *); + struct sk_buff * (*peek)(struct Qdisc *); + unsigned int (*drop)(struct Qdisc *); + + int (*init)(struct Qdisc *, struct nlattr *arg); + void (*reset)(struct Qdisc *); + void (*destroy)(struct Qdisc *); + int (*change)(struct Qdisc *, struct nlattr *arg); + void (*attach)(struct Qdisc *); + + int (*dump)(struct Qdisc *, struct sk_buff *); + int (*dump_stats)(struct Qdisc *, struct gnet_dump *); + + struct module *owner; +}; + + +struct tcf_result { + unsigned long class; + u32 classid; +}; + +struct tcf_proto_ops { + struct tcf_proto_ops *next; + char kind[IFNAMSIZ]; + + int (*classify)(struct sk_buff*, struct tcf_proto*, + struct tcf_result *); + int (*init)(struct tcf_proto*); + void (*destroy)(struct tcf_proto*); + + unsigned long (*get)(struct tcf_proto*, u32 handle); + void (*put)(struct tcf_proto*, unsigned long); + int (*change)(struct tcf_proto*, unsigned long, + u32 handle, struct nlattr **, + unsigned long *); + int (*delete)(struct tcf_proto*, unsigned long); + void (*walk)(struct tcf_proto*, struct tcf_walker *arg); + + /* rtnetlink specific */ + int (*dump)(struct tcf_proto*, unsigned long, + struct sk_buff *skb, struct tcmsg*); + + struct module *owner; +}; + +struct tcf_proto { + /* Fast access part */ + struct tcf_proto *next; + void *root; + int (*classify)(struct sk_buff*, struct tcf_proto*, + struct tcf_result *); + __be16 protocol; + + /* All the rest */ + u32 prio; + u32 classid; + struct Qdisc *q; + void *data; + struct tcf_proto_ops *ops; +}; + +struct qdisc_skb_cb { + unsigned int pkt_len; + char data[]; +}; + +static inline int qdisc_qlen(struct Qdisc *q) +{ + return q->q.qlen; +} + +static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb) +{ + return (struct qdisc_skb_cb *)skb->cb; +} + +static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc) +{ + return &qdisc->q.lock; +} + +static inline struct Qdisc *qdisc_root(struct Qdisc *qdisc) +{ + return qdisc->dev_queue->qdisc; +} + +static inline struct Qdisc *qdisc_root_sleeping(struct Qdisc *qdisc) +{ + return qdisc->dev_queue->qdisc_sleeping; +} + +/* The qdisc root lock is a mechanism by which to top level + * of a qdisc tree can be locked from any qdisc node in the + * forest. This allows changing the configuration of some + * aspect of the qdisc tree while blocking out asynchronous + * qdisc access in the packet processing paths. + * + * It is only legal to do this when the root will not change + * on us. Otherwise we'll potentially lock the wrong qdisc + * root. This is enforced by holding the RTNL semaphore, which + * all users of this lock accessor must do. + */ +static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc) +{ + struct Qdisc *root = qdisc_root(qdisc); + + ASSERT_RTNL(); + return qdisc_lock(root); +} + +static inline spinlock_t *qdisc_root_sleeping_lock(struct Qdisc *qdisc) +{ + struct Qdisc *root = qdisc_root_sleeping(qdisc); + + ASSERT_RTNL(); + return qdisc_lock(root); +} + +static inline struct net_device *qdisc_dev(struct Qdisc *qdisc) +{ + return qdisc->dev_queue->dev; +} + +static inline void sch_tree_lock(struct Qdisc *q) +{ + spin_lock_bh(qdisc_root_sleeping_lock(q)); +} + +static inline void sch_tree_unlock(struct Qdisc *q) +{ + spin_unlock_bh(qdisc_root_sleeping_lock(q)); +} + +#define tcf_tree_lock(tp) sch_tree_lock((tp)->q) +#define tcf_tree_unlock(tp) sch_tree_unlock((tp)->q) + +extern struct Qdisc noop_qdisc; +extern struct Qdisc_ops noop_qdisc_ops; +extern struct Qdisc_ops pfifo_fast_ops; +extern struct Qdisc_ops mq_qdisc_ops; + +struct Qdisc_class_common { + u32 classid; + struct hlist_node hnode; +}; + +struct Qdisc_class_hash { + struct hlist_head *hash; + unsigned int hashsize; + unsigned int hashmask; + unsigned int hashelems; +}; + +static inline unsigned int qdisc_class_hash(u32 id, u32 mask) +{ + id ^= id >> 8; + id ^= id >> 4; + return id & mask; +} + +static inline struct Qdisc_class_common * +qdisc_class_find(struct Qdisc_class_hash *hash, u32 id) +{ + struct Qdisc_class_common *cl; + struct hlist_node *n; + unsigned int h; + + h = qdisc_class_hash(id, hash->hashmask); + hlist_for_each_entry(cl, n, &hash->hash[h], hnode) { + if (cl->classid == id) + return cl; + } + return NULL; +} + +extern int qdisc_class_hash_init(struct Qdisc_class_hash *); +extern void qdisc_class_hash_insert(struct Qdisc_class_hash *, struct Qdisc_class_common *); +extern void qdisc_class_hash_remove(struct Qdisc_class_hash *, struct Qdisc_class_common *); +extern void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *); +extern void qdisc_class_hash_destroy(struct Qdisc_class_hash *); + +extern void dev_init_scheduler(struct net_device *dev); +extern void dev_shutdown(struct net_device *dev); +extern void dev_activate(struct net_device *dev); +extern void dev_deactivate(struct net_device *dev); +extern struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, + struct Qdisc *qdisc); +extern void qdisc_reset(struct Qdisc *qdisc); +extern void qdisc_destroy(struct Qdisc *qdisc); +extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n); +extern struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + struct Qdisc_ops *ops); +extern struct Qdisc *qdisc_create_dflt(struct net_device *dev, + struct netdev_queue *dev_queue, + struct Qdisc_ops *ops, u32 parentid); +extern void qdisc_calculate_pkt_len(struct sk_buff *skb, + struct qdisc_size_table *stab); +extern void tcf_destroy(struct tcf_proto *tp); +extern void tcf_destroy_chain(struct tcf_proto **fl); + +/* Reset all TX qdiscs greater then index of a device. */ +static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) +{ + struct Qdisc *qdisc; + + for (; i < dev->num_tx_queues; i++) { + qdisc = netdev_get_tx_queue(dev, i)->qdisc; + if (qdisc) { + spin_lock_bh(qdisc_lock(qdisc)); + qdisc_reset(qdisc); + spin_unlock_bh(qdisc_lock(qdisc)); + } + } +} + +static inline void qdisc_reset_all_tx(struct net_device *dev) +{ + qdisc_reset_all_tx_gt(dev, 0); +} + +/* Are all TX queues of the device empty? */ +static inline bool qdisc_all_tx_empty(const struct net_device *dev) +{ + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + const struct Qdisc *q = txq->qdisc; + + if (q->q.qlen) + return false; + } + return true; +} + +/* Are any of the TX qdiscs changing? */ +static inline bool qdisc_tx_changing(struct net_device *dev) +{ + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + if (txq->qdisc != txq->qdisc_sleeping) + return true; + } + return false; +} + +/* Is the device using the noop qdisc on all queues? */ +static inline bool qdisc_tx_is_noop(const struct net_device *dev) +{ + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + if (txq->qdisc != &noop_qdisc) + return false; + } + return true; +} + +static inline unsigned int qdisc_pkt_len(struct sk_buff *skb) +{ + return qdisc_skb_cb(skb)->pkt_len; +} + +/* additional qdisc xmit flags (NET_XMIT_MASK in linux/netdevice.h) */ +enum net_xmit_qdisc_t { + __NET_XMIT_STOLEN = 0x00010000, + __NET_XMIT_BYPASS = 0x00020000, +}; + +#ifdef CONFIG_NET_CLS_ACT +#define net_xmit_drop_count(e) ((e) & __NET_XMIT_STOLEN ? 0 : 1) +#else +#define net_xmit_drop_count(e) (1) +#endif + +static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ +#ifdef CONFIG_NET_SCHED + if (sch->stab) + qdisc_calculate_pkt_len(skb, sch->stab); +#endif + return sch->enqueue(skb, sch); +} + +static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch) +{ + qdisc_skb_cb(skb)->pkt_len = skb->len; + return qdisc_enqueue(skb, sch) & NET_XMIT_MASK; +} + +static inline void __qdisc_update_bstats(struct Qdisc *sch, unsigned int len) +{ + sch->bstats.bytes += len; + sch->bstats.packets++; +} + +static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, + struct sk_buff_head *list) +{ + __skb_queue_tail(list, skb); + sch->qstats.backlog += qdisc_pkt_len(skb); + __qdisc_update_bstats(sch, qdisc_pkt_len(skb)); + + return NET_XMIT_SUCCESS; +} + +static inline int qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch) +{ + return __qdisc_enqueue_tail(skb, sch, &sch->q); +} + +static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch, + struct sk_buff_head *list) +{ + struct sk_buff *skb = __skb_dequeue(list); + + if (likely(skb != NULL)) + sch->qstats.backlog -= qdisc_pkt_len(skb); + + return skb; +} + +static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch) +{ + return __qdisc_dequeue_head(sch, &sch->q); +} + +static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch, + struct sk_buff_head *list) +{ + struct sk_buff *skb = __qdisc_dequeue_head(sch, list); + + if (likely(skb != NULL)) { + unsigned int len = qdisc_pkt_len(skb); + kfree_skb(skb); + return len; + } + + return 0; +} + +static inline unsigned int qdisc_queue_drop_head(struct Qdisc *sch) +{ + return __qdisc_queue_drop_head(sch, &sch->q); +} + +static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch, + struct sk_buff_head *list) +{ + struct sk_buff *skb = __skb_dequeue_tail(list); + + if (likely(skb != NULL)) + sch->qstats.backlog -= qdisc_pkt_len(skb); + + return skb; +} + +static inline struct sk_buff *qdisc_dequeue_tail(struct Qdisc *sch) +{ + return __qdisc_dequeue_tail(sch, &sch->q); +} + +static inline struct sk_buff *qdisc_peek_head(struct Qdisc *sch) +{ + return skb_peek(&sch->q); +} + +/* generic pseudo peek method for non-work-conserving qdisc */ +static inline struct sk_buff *qdisc_peek_dequeued(struct Qdisc *sch) +{ + /* we can reuse ->gso_skb because peek isn't called for root qdiscs */ + if (!sch->gso_skb) { + sch->gso_skb = sch->dequeue(sch); + if (sch->gso_skb) + /* it's still part of the queue */ + sch->q.qlen++; + } + + return sch->gso_skb; +} + +/* use instead of qdisc->dequeue() for all qdiscs queried with ->peek() */ +static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch) +{ + struct sk_buff *skb = sch->gso_skb; + + if (skb) { + sch->gso_skb = NULL; + sch->q.qlen--; + } else { + skb = sch->dequeue(sch); + } + + return skb; +} + +static inline void __qdisc_reset_queue(struct Qdisc *sch, + struct sk_buff_head *list) +{ + /* + * We do not know the backlog in bytes of this list, it + * is up to the caller to correct it + */ + __skb_queue_purge(list); +} + +static inline void qdisc_reset_queue(struct Qdisc *sch) +{ + __qdisc_reset_queue(sch, &sch->q); + sch->qstats.backlog = 0; +} + +static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch, + struct sk_buff_head *list) +{ + struct sk_buff *skb = __qdisc_dequeue_tail(sch, list); + + if (likely(skb != NULL)) { + unsigned int len = qdisc_pkt_len(skb); + kfree_skb(skb); + return len; + } + + return 0; +} + +static inline unsigned int qdisc_queue_drop(struct Qdisc *sch) +{ + return __qdisc_queue_drop(sch, &sch->q); +} + +static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch) +{ + kfree_skb(skb); + sch->qstats.drops++; + + return NET_XMIT_DROP; +} + +static inline int qdisc_reshape_fail(struct sk_buff *skb, struct Qdisc *sch) +{ + sch->qstats.drops++; + +#ifdef CONFIG_NET_CLS_ACT + if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch)) + goto drop; + + return NET_XMIT_SUCCESS; + +drop: +#endif + kfree_skb(skb); + return NET_XMIT_DROP; +} + +/* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how + long it will take to send a packet given its size. + */ +static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen) +{ + int slot = pktlen + rtab->rate.cell_align + rtab->rate.overhead; + if (slot < 0) + slot = 0; + slot >>= rtab->rate.cell_log; + if (slot > 255) + return (rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]); + return rtab->data[slot]; +} + +#ifdef CONFIG_NET_CLS_ACT +static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask, + int action) +{ + struct sk_buff *n; + + if ((action == TC_ACT_STOLEN || action == TC_ACT_QUEUED) && + !skb_shared(skb)) + n = skb_get(skb); + else + n = skb_clone(skb, gfp_mask); + + if (n) { + n->tc_verd = SET_TC_VERD(n->tc_verd, 0); + n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd); + n->tc_verd = CLR_TC_MUNGED(n->tc_verd); + } + return n; +} +#endif + +#endif diff --git a/include/net/scm.h b/include/net/scm.h new file mode 100644 index 00000000..31656506 --- /dev/null +++ b/include/net/scm.h @@ -0,0 +1,129 @@ +#ifndef __LINUX_NET_SCM_H +#define __LINUX_NET_SCM_H + +#include <linux/limits.h> +#include <linux/net.h> +#include <linux/security.h> +#include <linux/pid.h> +#include <linux/nsproxy.h> + +/* Well, we should have at least one descriptor open + * to accept passed FDs 8) + */ +#define SCM_MAX_FD 255 + +struct scm_fp_list { + struct list_head list; + int count; + struct file *fp[SCM_MAX_FD]; +}; + +struct scm_cookie { + struct pid *pid; /* Skb credentials */ + const struct cred *cred; + struct scm_fp_list *fp; /* Passed files */ + struct ucred creds; /* Skb credentials */ +#ifdef CONFIG_SECURITY_NETWORK + u32 secid; /* Passed security ID */ +#endif +}; + +extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm); +extern void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm); +extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm); +extern void __scm_destroy(struct scm_cookie *scm); +extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl); + +#ifdef CONFIG_SECURITY_NETWORK +static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) +{ + security_socket_getpeersec_dgram(sock, NULL, &scm->secid); +} +#else +static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + +static __inline__ void scm_set_cred(struct scm_cookie *scm, + struct pid *pid, const struct cred *cred) +{ + scm->pid = get_pid(pid); + scm->cred = get_cred(cred); + cred_to_ucred(pid, cred, &scm->creds); +} + +static __inline__ void scm_destroy_cred(struct scm_cookie *scm) +{ + put_pid(scm->pid); + scm->pid = NULL; + + if (scm->cred) + put_cred(scm->cred); + scm->cred = NULL; +} + +static __inline__ void scm_destroy(struct scm_cookie *scm) +{ + scm_destroy_cred(scm); + if (scm && scm->fp) + __scm_destroy(scm); +} + +static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, + struct scm_cookie *scm) +{ + scm_set_cred(scm, task_tgid(current), current_cred()); + scm->fp = NULL; + unix_get_peersec_dgram(sock, scm); + if (msg->msg_controllen <= 0) + return 0; + return __scm_send(sock, msg, scm); +} + +#ifdef CONFIG_SECURITY_NETWORK +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) +{ + char *secdata; + u32 seclen; + int err; + + if (test_bit(SOCK_PASSSEC, &sock->flags)) { + err = security_secid_to_secctx(scm->secid, &secdata, &seclen); + + if (!err) { + put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata); + security_release_secctx(secdata, seclen); + } + } +} +#else +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + +static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, + struct scm_cookie *scm, int flags) +{ + if (!msg->msg_control) { + if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp) + msg->msg_flags |= MSG_CTRUNC; + scm_destroy(scm); + return; + } + + if (test_bit(SOCK_PASSCRED, &sock->flags)) + put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); + + scm_destroy_cred(scm); + + scm_passec(sock, msg, scm); + + if (!scm->fp) + return; + + scm_detach_fds(msg, scm); +} + + +#endif /* __LINUX_NET_SCM_H */ + diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h new file mode 100644 index 00000000..49bc9577 --- /dev/null +++ b/include/net/sctp/auth.h @@ -0,0 +1,127 @@ +/* SCTP kernel implementation + * (C) Copyright 2007 Hewlett-Packard Development Company, L.P. + * + * This file is part of the SCTP kernel implementation + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Vlad Yasevich <vladislav.yasevich@hp.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_auth_h__ +#define __sctp_auth_h__ + +#include <linux/list.h> +#include <linux/crypto.h> + +struct sctp_endpoint; +struct sctp_association; +struct sctp_authkey; +struct sctp_hmacalgo; + +/* + * Define a generic struct that will hold all the info + * necessary for an HMAC transform + */ +struct sctp_hmac { + __u16 hmac_id; /* one of the above ids */ + char *hmac_name; /* name for loading */ + __u16 hmac_len; /* length of the signature */ +}; + +/* This is generic structure that containst authentication bytes used + * as keying material. It's a what is referred to as byte-vector all + * over SCTP-AUTH + */ +struct sctp_auth_bytes { + atomic_t refcnt; + __u32 len; + __u8 data[]; +}; + +/* Definition for a shared key, weather endpoint or association */ +struct sctp_shared_key { + struct list_head key_list; + __u16 key_id; + struct sctp_auth_bytes *key; +}; + +#define key_for_each(__key, __list_head) \ + list_for_each_entry(__key, __list_head, key_list) + +#define key_for_each_safe(__key, __tmp, __list_head) \ + list_for_each_entry_safe(__key, __tmp, __list_head, key_list) + +static inline void sctp_auth_key_hold(struct sctp_auth_bytes *key) +{ + if (!key) + return; + + atomic_inc(&key->refcnt); +} + +void sctp_auth_key_put(struct sctp_auth_bytes *key); +struct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp); +void sctp_auth_destroy_keys(struct list_head *keys); +int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp); +struct sctp_shared_key *sctp_auth_get_shkey( + const struct sctp_association *asoc, + __u16 key_id); +int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, + struct sctp_association *asoc, + gfp_t gfp); +int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp); +void sctp_auth_destroy_hmacs(struct crypto_hash *auth_hmacs[]); +struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id); +struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc); +void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, + struct sctp_hmac_algo_param *hmacs); +int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, + __be16 hmac_id); +int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc); +int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc); +void sctp_auth_calculate_hmac(const struct sctp_association *asoc, + struct sk_buff *skb, + struct sctp_auth_chunk *auth, gfp_t gfp); + +/* API Helpers */ +int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id); +int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, + struct sctp_hmacalgo *hmacs); +int sctp_auth_set_key(struct sctp_endpoint *ep, + struct sctp_association *asoc, + struct sctp_authkey *auth_key); +int sctp_auth_set_active_key(struct sctp_endpoint *ep, + struct sctp_association *asoc, + __u16 key_id); +int sctp_auth_del_key_id(struct sctp_endpoint *ep, + struct sctp_association *asoc, + __u16 key_id); + +#endif diff --git a/include/net/sctp/checksum.h b/include/net/sctp/checksum.h new file mode 100644 index 00000000..befc8d2a --- /dev/null +++ b/include/net/sctp/checksum.h @@ -0,0 +1,83 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001-2003 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * SCTP Checksum functions + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Dinakaran Joseph + * Jon Grimm <jgrimm@us.ibm.com> + * Sridhar Samudrala <sri@us.ibm.com> + * + * Rewritten to use libcrc32c by: + * Vlad Yasevich <vladislav.yasevich@hp.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include <linux/types.h> +#include <net/sctp/sctp.h> +#include <linux/crc32c.h> + +static inline __u32 sctp_crc32c(__u32 crc, u8 *buffer, u16 length) +{ + return crc32c(crc, buffer, length); +} + +static inline __u32 sctp_start_cksum(__u8 *buffer, __u16 length) +{ + __u32 crc = ~(__u32)0; + __u8 zero[sizeof(__u32)] = {0}; + + /* Optimize this routine to be SCTP specific, knowing how + * to skip the checksum field of the SCTP header. + */ + + /* Calculate CRC up to the checksum. */ + crc = sctp_crc32c(crc, buffer, sizeof(struct sctphdr) - sizeof(__u32)); + + /* Skip checksum field of the header. */ + crc = sctp_crc32c(crc, zero, sizeof(__u32)); + + /* Calculate the rest of the CRC. */ + crc = sctp_crc32c(crc, &buffer[sizeof(struct sctphdr)], + length - sizeof(struct sctphdr)); + return crc; +} + +static inline __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32) +{ + return sctp_crc32c(crc32, buffer, length); +} + +static inline __le32 sctp_end_cksum(__be32 crc32) +{ + return cpu_to_le32(~crc32); +} diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h new file mode 100644 index 00000000..2c55a7ea --- /dev/null +++ b/include/net/sctp/command.h @@ -0,0 +1,226 @@ +/* SCTP kernel Implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (C) 1999-2001 Cisco, Motorola + * + * This file is part of the SCTP kernel implementation + * + * These are the definitions needed for the command object. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to one of the + * following email addresses: + * + * La Monte H.P. Yarroll <piggy@acm.org> + * Karl Knutson <karl@athena.chicago.il.us> + * Ardelle Fan <ardelle.fan@intel.com> + * Sridhar Samudrala <sri@us.ibm.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + + +#ifndef __net_sctp_command_h__ +#define __net_sctp_command_h__ + +#include <net/sctp/constants.h> +#include <net/sctp/structs.h> + + +typedef enum { + SCTP_CMD_NOP = 0, /* Do nothing. */ + SCTP_CMD_NEW_ASOC, /* Register a new association. */ + SCTP_CMD_DELETE_TCB, /* Delete the current association. */ + SCTP_CMD_NEW_STATE, /* Enter a new state. */ + SCTP_CMD_REPORT_TSN, /* Record the arrival of a TSN. */ + SCTP_CMD_GEN_SACK, /* Send a Selective ACK (maybe). */ + SCTP_CMD_PROCESS_SACK, /* Process an inbound SACK. */ + SCTP_CMD_GEN_INIT_ACK, /* Generate an INIT ACK chunk. */ + SCTP_CMD_PEER_INIT, /* Process a INIT from the peer. */ + SCTP_CMD_GEN_COOKIE_ECHO, /* Generate a COOKIE ECHO chunk. */ + SCTP_CMD_CHUNK_ULP, /* Send a chunk to the sockets layer. */ + SCTP_CMD_EVENT_ULP, /* Send a notification to the sockets layer. */ + SCTP_CMD_REPLY, /* Send a chunk to our peer. */ + SCTP_CMD_SEND_PKT, /* Send a full packet to our peer. */ + SCTP_CMD_RETRAN, /* Mark a transport for retransmission. */ + SCTP_CMD_ECN_CE, /* Do delayed CE processing. */ + SCTP_CMD_ECN_ECNE, /* Do delayed ECNE processing. */ + SCTP_CMD_ECN_CWR, /* Do delayed CWR processing. */ + SCTP_CMD_TIMER_START, /* Start a timer. */ + SCTP_CMD_TIMER_RESTART, /* Restart a timer. */ + SCTP_CMD_TIMER_STOP, /* Stop a timer. */ + SCTP_CMD_INIT_CHOOSE_TRANSPORT, /* Choose transport for an INIT. */ + SCTP_CMD_INIT_COUNTER_RESET, /* Reset init counter. */ + SCTP_CMD_INIT_COUNTER_INC, /* Increment init counter. */ + SCTP_CMD_INIT_RESTART, /* High level, do init timer work. */ + SCTP_CMD_COOKIEECHO_RESTART, /* High level, do cookie-echo timer work. */ + SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */ + SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */ + SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ + SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */ + SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ + SCTP_CMD_HB_TIMER_UPDATE, /* Update a heartbeat timers. */ + SCTP_CMD_HB_TIMERS_STOP, /* Stop the heartbeat timers. */ + SCTP_CMD_TRANSPORT_HB_SENT, /* Reset the status of a transport. */ + SCTP_CMD_TRANSPORT_IDLE, /* Do manipulations on idle transport */ + SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */ + SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */ + SCTP_CMD_REPORT_BAD_TAG, /* Verification tags didn't match. */ + SCTP_CMD_PROCESS_CTSN, /* Sideeffect from shutdown. */ + SCTP_CMD_ASSOC_FAILED, /* Handle association failure. */ + SCTP_CMD_DISCARD_PACKET, /* Discard the whole packet. */ + SCTP_CMD_GEN_SHUTDOWN, /* Generate a SHUTDOWN chunk. */ + SCTP_CMD_UPDATE_ASSOC, /* Update association information. */ + SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ + SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ + SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */ + SCTP_CMD_PART_DELIVER, /* Partial data delivery considerations. */ + SCTP_CMD_RENEGE, /* Renege data on an association. */ + SCTP_CMD_SETUP_T4, /* ADDIP, setup T4 RTO timer parms. */ + SCTP_CMD_PROCESS_OPERR, /* Process an ERROR chunk. */ + SCTP_CMD_REPORT_FWDTSN, /* Report new cumulative TSN Ack. */ + SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */ + SCTP_CMD_CLEAR_INIT_TAG, /* Clears association peer's inittag. */ + SCTP_CMD_DEL_NON_PRIMARY, /* Removes non-primary peer transports. */ + SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */ + SCTP_CMD_FORCE_PRIM_RETRAN, /* Forces retrans. over primary path. */ + SCTP_CMD_SET_SK_ERR, /* Set sk_err */ + SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */ + SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */ + SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */ + SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ + SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */ + SCTP_CMD_SEND_MSG, /* Send the whole use message */ + SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */ + SCTP_CMD_LAST +} sctp_verb_t; + +#define SCTP_CMD_MAX (SCTP_CMD_LAST - 1) +#define SCTP_CMD_NUM_VERBS (SCTP_CMD_MAX + 1) + +/* How many commands can you put in an sctp_cmd_seq_t? + * This is a rather arbitrary number, ideally derived from a careful + * analysis of the state functions, but in reality just taken from + * thin air in the hopes othat we don't trigger a kernel panic. + */ +#define SCTP_MAX_NUM_COMMANDS 14 + +typedef union { + __s32 i32; + __u32 u32; + __be32 be32; + __u16 u16; + __u8 u8; + int error; + __be16 err; + sctp_state_t state; + sctp_event_timeout_t to; + unsigned long zero; + void *ptr; + struct sctp_chunk *chunk; + struct sctp_association *asoc; + struct sctp_transport *transport; + struct sctp_bind_addr *bp; + sctp_init_chunk_t *init; + struct sctp_ulpevent *ulpevent; + struct sctp_packet *packet; + sctp_sackhdr_t *sackh; + struct sctp_datamsg *msg; +} sctp_arg_t; + +/* We are simulating ML type constructors here. + * + * SCTP_ARG_CONSTRUCTOR(NAME, TYPE, ELT) builds a function called + * SCTP_NAME() which takes an argument of type TYPE and returns an + * sctp_arg_t. It does this by inserting the sole argument into the + * ELT union element of a local sctp_arg_t. + * + * E.g., SCTP_ARG_CONSTRUCTOR(I32, __s32, i32) builds SCTP_I32(arg), + * which takes an __s32 and returns a sctp_arg_t containing the + * __s32. So, after foo = SCTP_I32(arg), foo.i32 == arg. + */ +static inline sctp_arg_t SCTP_NULL(void) +{ + sctp_arg_t retval; retval.ptr = NULL; return retval; +} +static inline sctp_arg_t SCTP_NOFORCE(void) +{ + sctp_arg_t retval = {.zero = 0UL}; retval.i32 = 0; return retval; +} +static inline sctp_arg_t SCTP_FORCE(void) +{ + sctp_arg_t retval = {.zero = 0UL}; retval.i32 = 1; return retval; +} + +#define SCTP_ARG_CONSTRUCTOR(name, type, elt) \ +static inline sctp_arg_t \ +SCTP_## name (type arg) \ +{ sctp_arg_t retval = {.zero = 0UL}; retval.elt = arg; return retval; } + +SCTP_ARG_CONSTRUCTOR(I32, __s32, i32) +SCTP_ARG_CONSTRUCTOR(U32, __u32, u32) +SCTP_ARG_CONSTRUCTOR(BE32, __be32, be32) +SCTP_ARG_CONSTRUCTOR(U16, __u16, u16) +SCTP_ARG_CONSTRUCTOR(U8, __u8, u8) +SCTP_ARG_CONSTRUCTOR(ERROR, int, error) +SCTP_ARG_CONSTRUCTOR(PERR, __be16, err) /* protocol error */ +SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state) +SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to) +SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr) +SCTP_ARG_CONSTRUCTOR(CHUNK, struct sctp_chunk *, chunk) +SCTP_ARG_CONSTRUCTOR(ASOC, struct sctp_association *, asoc) +SCTP_ARG_CONSTRUCTOR(TRANSPORT, struct sctp_transport *, transport) +SCTP_ARG_CONSTRUCTOR(BA, struct sctp_bind_addr *, bp) +SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) +SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent) +SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet) +SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) +SCTP_ARG_CONSTRUCTOR(DATAMSG, struct sctp_datamsg *, msg) + +typedef struct { + sctp_arg_t obj; + sctp_verb_t verb; +} sctp_cmd_t; + +typedef struct { + sctp_cmd_t cmds[SCTP_MAX_NUM_COMMANDS]; + __u8 next_free_slot; + __u8 next_cmd; +} sctp_cmd_seq_t; + + +/* Initialize a block of memory as a command sequence. + * Return 0 if the initialization fails. + */ +int sctp_init_cmd_seq(sctp_cmd_seq_t *seq); + +/* Add a command to an sctp_cmd_seq_t. + * + * Use the SCTP_* constructors defined by SCTP_ARG_CONSTRUCTOR() above + * to wrap data which goes in the obj argument. + */ +void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj); + +/* Return the next command structure in an sctp_cmd_seq. + * Return NULL at the end of the sequence. + */ +sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq); + +#endif /* __net_sctp_command_h__ */ + diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h new file mode 100644 index 00000000..63908840 --- /dev/null +++ b/include/net/sctp/constants.h @@ -0,0 +1,458 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll <piggy@acm.org> + * Karl Knutson <karl@athena.chicago.il.us> + * Randall Stewart <randall@stewart.chicago.il.us> + * Ken Morneau <kmorneau@cisco.com> + * Qiaobing Xie <qxie1@motorola.com> + * Xingang Guo <xingang.guo@intel.com> + * Sridhar Samudrala <samudrala@us.ibm.com> + * Daisy Chang <daisyc@us.ibm.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_constants_h__ +#define __sctp_constants_h__ + +#include <linux/sctp.h> +#include <linux/ipv6.h> /* For ipv6hdr. */ +#include <net/sctp/user.h> +#include <net/tcp_states.h> /* For TCP states used in sctp_sock_state_t */ + +/* Value used for stream negotiation. */ +enum { SCTP_MAX_STREAM = 0xffff }; +enum { SCTP_DEFAULT_OUTSTREAMS = 10 }; +enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM }; + +/* Since CIDs are sparse, we need all four of the following + * symbols. CIDs are dense through SCTP_CID_BASE_MAX. + */ +#define SCTP_CID_BASE_MAX SCTP_CID_SHUTDOWN_COMPLETE +#define SCTP_CID_MAX SCTP_CID_ASCONF_ACK + +#define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1) + +#define SCTP_NUM_ADDIP_CHUNK_TYPES 2 + +#define SCTP_NUM_PRSCTP_CHUNK_TYPES 1 + +#define SCTP_NUM_AUTH_CHUNK_TYPES 1 + +#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNK_TYPES + \ + SCTP_NUM_ADDIP_CHUNK_TYPES +\ + SCTP_NUM_PRSCTP_CHUNK_TYPES +\ + SCTP_NUM_AUTH_CHUNK_TYPES) + +/* These are the different flavours of event. */ +typedef enum { + + SCTP_EVENT_T_CHUNK = 1, + SCTP_EVENT_T_TIMEOUT, + SCTP_EVENT_T_OTHER, + SCTP_EVENT_T_PRIMITIVE + +} sctp_event_t; + +#define SCTP_EVENT_T_MAX SCTP_EVENT_T_PRIMITIVE +#define SCTP_EVENT_T_NUM (SCTP_EVENT_T_MAX + 1) + +/* As a convenience for the state machine, we append SCTP_EVENT_* and + * SCTP_ULP_* to the list of possible chunks. + */ + +typedef enum { + SCTP_EVENT_TIMEOUT_NONE = 0, + SCTP_EVENT_TIMEOUT_T1_COOKIE, + SCTP_EVENT_TIMEOUT_T1_INIT, + SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, + SCTP_EVENT_TIMEOUT_T3_RTX, + SCTP_EVENT_TIMEOUT_T4_RTO, + SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD, + SCTP_EVENT_TIMEOUT_HEARTBEAT, + SCTP_EVENT_TIMEOUT_SACK, + SCTP_EVENT_TIMEOUT_AUTOCLOSE, +} sctp_event_timeout_t; + +#define SCTP_EVENT_TIMEOUT_MAX SCTP_EVENT_TIMEOUT_AUTOCLOSE +#define SCTP_NUM_TIMEOUT_TYPES (SCTP_EVENT_TIMEOUT_MAX + 1) + +typedef enum { + SCTP_EVENT_NO_PENDING_TSN = 0, + SCTP_EVENT_ICMP_PROTO_UNREACH, +} sctp_event_other_t; + +#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_ICMP_PROTO_UNREACH +#define SCTP_NUM_OTHER_TYPES (SCTP_EVENT_OTHER_MAX + 1) + +/* These are primitive requests from the ULP. */ +typedef enum { + SCTP_PRIMITIVE_ASSOCIATE = 0, + SCTP_PRIMITIVE_SHUTDOWN, + SCTP_PRIMITIVE_ABORT, + SCTP_PRIMITIVE_SEND, + SCTP_PRIMITIVE_REQUESTHEARTBEAT, + SCTP_PRIMITIVE_ASCONF, +} sctp_event_primitive_t; + +#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_ASCONF +#define SCTP_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1) + +/* We define here a utility type for manipulating subtypes. + * The subtype constructors all work like this: + * + * sctp_subtype_t foo = SCTP_ST_CHUNK(SCTP_CID_INIT); + */ + +typedef union { + sctp_cid_t chunk; + sctp_event_timeout_t timeout; + sctp_event_other_t other; + sctp_event_primitive_t primitive; +} sctp_subtype_t; + +#define SCTP_SUBTYPE_CONSTRUCTOR(_name, _type, _elt) \ +static inline sctp_subtype_t \ +SCTP_ST_## _name (_type _arg) \ +{ sctp_subtype_t _retval; _retval._elt = _arg; return _retval; } + +SCTP_SUBTYPE_CONSTRUCTOR(CHUNK, sctp_cid_t, chunk) +SCTP_SUBTYPE_CONSTRUCTOR(TIMEOUT, sctp_event_timeout_t, timeout) +SCTP_SUBTYPE_CONSTRUCTOR(OTHER, sctp_event_other_t, other) +SCTP_SUBTYPE_CONSTRUCTOR(PRIMITIVE, sctp_event_primitive_t, primitive) + + +#define sctp_chunk_is_control(a) (a->chunk_hdr->type != SCTP_CID_DATA) +#define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA) + +/* Calculate the actual data size in a data chunk */ +#define SCTP_DATA_SNDSIZE(c) ((int)((unsigned long)(c->chunk_end)\ + - (unsigned long)(c->chunk_hdr)\ + - sizeof(sctp_data_chunk_t))) + +#define SCTP_MAX_ERROR_CAUSE SCTP_ERROR_NONEXIST_IP +#define SCTP_NUM_ERROR_CAUSE 10 + +/* Internal error codes */ +typedef enum { + + SCTP_IERROR_NO_ERROR = 0, + SCTP_IERROR_BASE = 1000, + SCTP_IERROR_NO_COOKIE, + SCTP_IERROR_BAD_SIG, + SCTP_IERROR_STALE_COOKIE, + SCTP_IERROR_NOMEM, + SCTP_IERROR_MALFORMED, + SCTP_IERROR_BAD_TAG, + SCTP_IERROR_BIG_GAP, + SCTP_IERROR_DUP_TSN, + SCTP_IERROR_HIGH_TSN, + SCTP_IERROR_IGNORE_TSN, + SCTP_IERROR_NO_DATA, + SCTP_IERROR_BAD_STREAM, + SCTP_IERROR_BAD_PORTS, + SCTP_IERROR_AUTH_BAD_HMAC, + SCTP_IERROR_AUTH_BAD_KEYID, + SCTP_IERROR_PROTO_VIOLATION, + SCTP_IERROR_ERROR, + SCTP_IERROR_ABORT, +} sctp_ierror_t; + + + +/* SCTP state defines for internal state machine */ +typedef enum { + + SCTP_STATE_EMPTY = 0, + SCTP_STATE_CLOSED = 1, + SCTP_STATE_COOKIE_WAIT = 2, + SCTP_STATE_COOKIE_ECHOED = 3, + SCTP_STATE_ESTABLISHED = 4, + SCTP_STATE_SHUTDOWN_PENDING = 5, + SCTP_STATE_SHUTDOWN_SENT = 6, + SCTP_STATE_SHUTDOWN_RECEIVED = 7, + SCTP_STATE_SHUTDOWN_ACK_SENT = 8, + +} sctp_state_t; + +#define SCTP_STATE_MAX SCTP_STATE_SHUTDOWN_ACK_SENT +#define SCTP_STATE_NUM_STATES (SCTP_STATE_MAX + 1) + +/* These are values for sk->state. + * For a UDP-style SCTP socket, the states are defined as follows + * - A socket in SCTP_SS_CLOSED state indicates that it is not willing to + * accept new associations, but it can initiate the creation of new ones. + * - A socket in SCTP_SS_LISTENING state indicates that it is willing to + * accept new associations and can initiate the creation of new ones. + * - A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off + * socket with one association. + * For a TCP-style SCTP socket, the states are defined as follows + * - A socket in SCTP_SS_CLOSED state indicates that it is not willing to + * accept new associations, but it can initiate the creation of new ones. + * - A socket in SCTP_SS_LISTENING state indicates that it is willing to + * accept new associations, but cannot initiate the creation of new ones. + * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single + * association. + */ +typedef enum { + SCTP_SS_CLOSED = TCP_CLOSE, + SCTP_SS_LISTENING = TCP_LISTEN, + SCTP_SS_ESTABLISHING = TCP_SYN_SENT, + SCTP_SS_ESTABLISHED = TCP_ESTABLISHED, + SCTP_SS_CLOSING = TCP_CLOSING, +} sctp_sock_state_t; + +/* These functions map various type to printable names. */ +const char *sctp_cname(const sctp_subtype_t); /* chunk types */ +const char *sctp_oname(const sctp_subtype_t); /* other events */ +const char *sctp_tname(const sctp_subtype_t); /* timeouts */ +const char *sctp_pname(const sctp_subtype_t); /* primitives */ + +/* This is a table of printable names of sctp_state_t's. */ +extern const char *const sctp_state_tbl[]; +extern const char *const sctp_evttype_tbl[]; +extern const char *const sctp_status_tbl[]; + +/* Maximum chunk length considering padding requirements. */ +enum { SCTP_MAX_CHUNK_LEN = ((1<<16) - sizeof(__u32)) }; + +/* Encourage Cookie-Echo bundling by pre-fragmenting chunks a little + * harder (until reaching ESTABLISHED state). + */ +enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 }; + +/* Guess at how big to make the TSN mapping array. + * We guarantee that we can handle at least this big a gap between the + * cumulative ACK and the highest TSN. In practice, we can often + * handle up to twice this value. + * + * NEVER make this more than 32767 (2^15-1). The Gap Ack Blocks in a + * SACK (see section 3.3.4) are only 16 bits, so 2*SCTP_TSN_MAP_SIZE + * must be less than 65535 (2^16 - 1), or we will have overflow + * problems creating SACK's. + */ +#define SCTP_TSN_MAP_INITIAL BITS_PER_LONG +#define SCTP_TSN_MAP_INCREMENT SCTP_TSN_MAP_INITIAL +#define SCTP_TSN_MAP_SIZE 4096 +#define SCTP_TSN_MAX_GAP 65535 + +/* We will not record more than this many duplicate TSNs between two + * SACKs. The minimum PMTU is 576. Remove all the headers and there + * is enough room for 131 duplicate reports. Round down to the + * nearest power of 2. + */ +enum { SCTP_MIN_PMTU = 576 }; +enum { SCTP_MAX_DUP_TSNS = 16 }; +enum { SCTP_MAX_GABS = 16 }; + +/* Heartbeat interval - 30 secs */ +#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30*1000) + +/* Delayed sack timer - 200ms */ +#define SCTP_DEFAULT_TIMEOUT_SACK (200) + +/* RTO.Initial - 3 seconds + * RTO.Min - 1 second + * RTO.Max - 60 seconds + * RTO.Alpha - 1/8 + * RTO.Beta - 1/4 + */ +#define SCTP_RTO_INITIAL (3 * 1000) +#define SCTP_RTO_MIN (1 * 1000) +#define SCTP_RTO_MAX (60 * 1000) + +#define SCTP_RTO_ALPHA 3 /* 1/8 when converted to right shifts. */ +#define SCTP_RTO_BETA 2 /* 1/4 when converted to right shifts. */ + +/* Maximum number of new data packets that can be sent in a burst. */ +#define SCTP_DEFAULT_MAX_BURST 4 + +#define SCTP_CLOCK_GRANULARITY 1 /* 1 jiffy */ + +#define SCTP_DEF_MAX_INIT 6 +#define SCTP_DEF_MAX_SEND 10 + +#define SCTP_DEFAULT_COOKIE_LIFE (60 * 1000) /* 60 seconds */ + +#define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */ +#define SCTP_DEFAULT_MAXWINDOW 65535 /* default rwnd size */ +#define SCTP_DEFAULT_RWND_SHIFT 4 /* by default, update on 1/16 of + * rcvbuf, which is 1/8 of initial + * window + */ +#define SCTP_DEFAULT_MAXSEGMENT 1500 /* MTU size, this is the limit + * to which we will raise the P-MTU. + */ +#define SCTP_DEFAULT_MINSEGMENT 512 /* MTU size ... if no mtu disc */ +#define SCTP_HOW_MANY_SECRETS 2 /* How many secrets I keep */ +#define SCTP_HOW_LONG_COOKIE_LIVE 3600 /* How many seconds the current + * secret will live? + */ +#define SCTP_SECRET_SIZE 32 /* Number of octets in a 256 bits. */ + +#define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ + +#define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash + * functions simpler to write. + */ + +#if defined (CONFIG_SCTP_HMAC_MD5) +#define SCTP_COOKIE_HMAC_ALG "hmac(md5)" +#elif defined (CONFIG_SCTP_HMAC_SHA1) +#define SCTP_COOKIE_HMAC_ALG "hmac(sha1)" +#else +#define SCTP_COOKIE_HMAC_ALG NULL +#endif + +/* These return values describe the success or failure of a number of + * routines which form the lower interface to SCTP_outqueue. + */ +typedef enum { + SCTP_XMIT_OK, + SCTP_XMIT_PMTU_FULL, + SCTP_XMIT_RWND_FULL, + SCTP_XMIT_NAGLE_DELAY, +} sctp_xmit_t; + +/* These are the commands for manipulating transports. */ +typedef enum { + SCTP_TRANSPORT_UP, + SCTP_TRANSPORT_DOWN, +} sctp_transport_cmd_t; + +/* These are the address scopes defined mainly for IPv4 addresses + * based on draft of SCTP IPv4 scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>. + * These scopes are hopefully generic enough to be used on scoping both + * IPv4 and IPv6 addresses in SCTP. + * At this point, the IPv6 scopes will be mapped to these internal scopes + * as much as possible. + */ +typedef enum { + SCTP_SCOPE_GLOBAL, /* IPv4 global addresses */ + SCTP_SCOPE_PRIVATE, /* IPv4 private addresses */ + SCTP_SCOPE_LINK, /* IPv4 link local address */ + SCTP_SCOPE_LOOPBACK, /* IPv4 loopback address */ + SCTP_SCOPE_UNUSABLE, /* IPv4 unusable addresses */ +} sctp_scope_t; + +typedef enum { + SCTP_SCOPE_POLICY_DISABLE, /* Disable IPv4 address scoping */ + SCTP_SCOPE_POLICY_ENABLE, /* Enable IPv4 address scoping */ + SCTP_SCOPE_POLICY_PRIVATE, /* Follow draft but allow IPv4 private addresses */ + SCTP_SCOPE_POLICY_LINK, /* Follow draft but allow IPv4 link local addresses */ +} sctp_scope_policy_t; + +/* Based on IPv4 scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>, + * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 198.18.0.0/24, + * 192.88.99.0/24. + * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP + * addresses. + */ +#define IS_IPV4_UNUSABLE_ADDRESS(a) \ + ((htonl(INADDR_BROADCAST) == a) || \ + ipv4_is_multicast(a) || \ + ipv4_is_zeronet(a) || \ + ipv4_is_test_198(a) || \ + ipv4_is_anycast_6to4(a)) + +/* Flags used for the bind address copy functions. */ +#define SCTP_ADDR6_ALLOWED 0x00000001 /* IPv6 address is allowed by + local sock family */ +#define SCTP_ADDR4_PEERSUPP 0x00000002 /* IPv4 address is supported by + peer */ +#define SCTP_ADDR6_PEERSUPP 0x00000004 /* IPv6 address is supported by + peer */ + +/* Reasons to retransmit. */ +typedef enum { + SCTP_RTXR_T3_RTX, + SCTP_RTXR_FAST_RTX, + SCTP_RTXR_PMTUD, + SCTP_RTXR_T1_RTX, +} sctp_retransmit_reason_t; + +/* Reasons to lower cwnd. */ +typedef enum { + SCTP_LOWER_CWND_T3_RTX, + SCTP_LOWER_CWND_FAST_RTX, + SCTP_LOWER_CWND_ECNE, + SCTP_LOWER_CWND_INACTIVE, +} sctp_lower_cwnd_t; + + +/* SCTP-AUTH Necessary constants */ + +/* SCTP-AUTH, Section 3.3 + * + * The following Table 2 shows the currently defined values for HMAC + * identifiers. + * + * +-----------------+--------------------------+ + * | HMAC Identifier | Message Digest Algorithm | + * +-----------------+--------------------------+ + * | 0 | Reserved | + * | 1 | SHA-1 defined in [8] | + * | 2 | Reserved | + * | 3 | SHA-256 defined in [8] | + * +-----------------+--------------------------+ + */ +enum { + SCTP_AUTH_HMAC_ID_RESERVED_0, + SCTP_AUTH_HMAC_ID_SHA1, + SCTP_AUTH_HMAC_ID_RESERVED_2, +#if defined (CONFIG_CRYPTO_SHA256) || defined (CONFIG_CRYPTO_SHA256_MODULE) + SCTP_AUTH_HMAC_ID_SHA256, +#endif + __SCTP_AUTH_HMAC_MAX +}; + +#define SCTP_AUTH_HMAC_ID_MAX __SCTP_AUTH_HMAC_MAX - 1 +#define SCTP_AUTH_NUM_HMACS __SCTP_AUTH_HMAC_MAX +#define SCTP_SHA1_SIG_SIZE 20 +#define SCTP_SHA256_SIG_SIZE 32 + +/* SCTP-AUTH, Section 3.2 + * The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH chunks + * MUST NOT be listed in the CHUNKS parameter + */ +#define SCTP_NUM_NOAUTH_CHUNKS 4 +#define SCTP_AUTH_MAX_CHUNKS (SCTP_NUM_CHUNK_TYPES - SCTP_NUM_NOAUTH_CHUNKS) + +/* SCTP-AUTH Section 6.1 + * The RANDOM parameter MUST contain a 32 byte random number. + */ +#define SCTP_AUTH_RANDOM_LENGTH 32 + +#endif /* __sctp_constants_h__ */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h new file mode 100644 index 00000000..65946bc4 --- /dev/null +++ b/include/net/sctp/sctp.h @@ -0,0 +1,694 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001-2003 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * The base lksctp header. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll <piggy@acm.org> + * Xingang Guo <xingang.guo@intel.com> + * Jon Grimm <jgrimm@us.ibm.com> + * Daisy Chang <daisyc@us.ibm.com> + * Sridhar Samudrala <sri@us.ibm.com> + * Ardelle Fan <ardelle.fan@intel.com> + * Ryan Layer <rmlayer@us.ibm.com> + * Kevin Gao <kevin.gao@intel.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __net_sctp_h__ +#define __net_sctp_h__ + +/* Header Strategy. + * Start getting some control over the header file depencies: + * includes + * constants + * structs + * prototypes + * macros, externs, and inlines + * + * Move test_frame specific items out of the kernel headers + * and into the test frame headers. This is not perfect in any sense + * and will continue to evolve. + */ + +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/in.h> +#include <linux/tty.h> +#include <linux/proc_fs.h> +#include <linux/spinlock.h> +#include <linux/jiffies.h> +#include <linux/idr.h> + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#include <net/ipv6.h> +#include <net/ip6_route.h> +#endif + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <net/sock.h> +#include <net/snmp.h> +#include <net/sctp/structs.h> +#include <net/sctp/constants.h> + + +/* Set SCTP_DEBUG flag via config if not already set. */ +#ifndef SCTP_DEBUG +#ifdef CONFIG_SCTP_DBG_MSG +#define SCTP_DEBUG 1 +#else +#define SCTP_DEBUG 0 +#endif /* CONFIG_SCTP_DBG */ +#endif /* SCTP_DEBUG */ + +#ifdef CONFIG_IP_SCTP_MODULE +#define SCTP_PROTOSW_FLAG 0 +#else /* static! */ +#define SCTP_PROTOSW_FLAG INET_PROTOSW_PERMANENT +#endif + + +/* Certain internal static functions need to be exported when + * compiled into the test frame. + */ +#ifndef SCTP_STATIC +#define SCTP_STATIC static +#endif + +/* + * Function declarations. + */ + +/* + * sctp/protocol.c + */ +extern struct sock *sctp_get_ctl_sock(void); +extern void sctp_local_addr_free(struct rcu_head *head); +extern int sctp_copy_local_addr_list(struct sctp_bind_addr *, + sctp_scope_t, gfp_t gfp, + int flags); +extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); +extern int sctp_register_pf(struct sctp_pf *, sa_family_t); + +/* + * sctp/socket.c + */ +int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); +int sctp_inet_listen(struct socket *sock, int backlog); +void sctp_write_space(struct sock *sk); +void sctp_data_ready(struct sock *sk, int len); +unsigned int sctp_poll(struct file *file, struct socket *sock, + poll_table *wait); +void sctp_sock_rfree(struct sk_buff *skb); +void sctp_copy_sock(struct sock *newsk, struct sock *sk, + struct sctp_association *asoc); +extern struct percpu_counter sctp_sockets_allocated; + +/* + * sctp/primitive.c + */ +int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg); +int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg); +int sctp_primitive_ABORT(struct sctp_association *, void *arg); +int sctp_primitive_SEND(struct sctp_association *, void *arg); +int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg); +int sctp_primitive_ASCONF(struct sctp_association *, void *arg); + +/* + * sctp/input.c + */ +int sctp_rcv(struct sk_buff *skb); +void sctp_v4_err(struct sk_buff *skb, u32 info); +void sctp_hash_established(struct sctp_association *); +void sctp_unhash_established(struct sctp_association *); +void sctp_hash_endpoint(struct sctp_endpoint *); +void sctp_unhash_endpoint(struct sctp_endpoint *); +struct sock *sctp_err_lookup(int family, struct sk_buff *, + struct sctphdr *, struct sctp_association **, + struct sctp_transport **); +void sctp_err_finish(struct sock *, struct sctp_association *); +void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, + struct sctp_transport *t, __u32 pmtu); +void sctp_icmp_proto_unreachable(struct sock *sk, + struct sctp_association *asoc, + struct sctp_transport *t); +void sctp_backlog_migrate(struct sctp_association *assoc, + struct sock *oldsk, struct sock *newsk); + +/* + * sctp/proc.c + */ +int sctp_snmp_proc_init(void); +void sctp_snmp_proc_exit(void); +int sctp_eps_proc_init(void); +void sctp_eps_proc_exit(void); +int sctp_assocs_proc_init(void); +void sctp_assocs_proc_exit(void); +int sctp_remaddr_proc_init(void); +void sctp_remaddr_proc_exit(void); + + +/* + * Module global variables + */ + + /* + * sctp/protocol.c + */ +extern struct kmem_cache *sctp_chunk_cachep __read_mostly; +extern struct kmem_cache *sctp_bucket_cachep __read_mostly; + +/* + * Section: Macros, externs, and inlines + */ + + +#ifdef TEST_FRAME +#include <test_frame.h> +#else + +/* spin lock wrappers. */ +#define sctp_spin_lock_irqsave(lock, flags) spin_lock_irqsave(lock, flags) +#define sctp_spin_unlock_irqrestore(lock, flags) \ + spin_unlock_irqrestore(lock, flags) +#define sctp_local_bh_disable() local_bh_disable() +#define sctp_local_bh_enable() local_bh_enable() +#define sctp_spin_lock(lock) spin_lock(lock) +#define sctp_spin_unlock(lock) spin_unlock(lock) +#define sctp_write_lock(lock) write_lock(lock) +#define sctp_write_unlock(lock) write_unlock(lock) +#define sctp_read_lock(lock) read_lock(lock) +#define sctp_read_unlock(lock) read_unlock(lock) + +/* sock lock wrappers. */ +#define sctp_lock_sock(sk) lock_sock(sk) +#define sctp_release_sock(sk) release_sock(sk) +#define sctp_bh_lock_sock(sk) bh_lock_sock(sk) +#define sctp_bh_unlock_sock(sk) bh_unlock_sock(sk) + +/* SCTP SNMP MIB stats handlers */ +DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics); +#define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field) +#define SCTP_INC_STATS_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field) +#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field) +#define SCTP_DEC_STATS(field) SNMP_DEC_STATS(sctp_statistics, field) + +#endif /* !TEST_FRAME */ + +/* sctp mib definitions */ +enum { + SCTP_MIB_NUM = 0, + SCTP_MIB_CURRESTAB, /* CurrEstab */ + SCTP_MIB_ACTIVEESTABS, /* ActiveEstabs */ + SCTP_MIB_PASSIVEESTABS, /* PassiveEstabs */ + SCTP_MIB_ABORTEDS, /* Aborteds */ + SCTP_MIB_SHUTDOWNS, /* Shutdowns */ + SCTP_MIB_OUTOFBLUES, /* OutOfBlues */ + SCTP_MIB_CHECKSUMERRORS, /* ChecksumErrors */ + SCTP_MIB_OUTCTRLCHUNKS, /* OutCtrlChunks */ + SCTP_MIB_OUTORDERCHUNKS, /* OutOrderChunks */ + SCTP_MIB_OUTUNORDERCHUNKS, /* OutUnorderChunks */ + SCTP_MIB_INCTRLCHUNKS, /* InCtrlChunks */ + SCTP_MIB_INORDERCHUNKS, /* InOrderChunks */ + SCTP_MIB_INUNORDERCHUNKS, /* InUnorderChunks */ + SCTP_MIB_FRAGUSRMSGS, /* FragUsrMsgs */ + SCTP_MIB_REASMUSRMSGS, /* ReasmUsrMsgs */ + SCTP_MIB_OUTSCTPPACKS, /* OutSCTPPacks */ + SCTP_MIB_INSCTPPACKS, /* InSCTPPacks */ + SCTP_MIB_T1_INIT_EXPIREDS, + SCTP_MIB_T1_COOKIE_EXPIREDS, + SCTP_MIB_T2_SHUTDOWN_EXPIREDS, + SCTP_MIB_T3_RTX_EXPIREDS, + SCTP_MIB_T4_RTO_EXPIREDS, + SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS, + SCTP_MIB_DELAY_SACK_EXPIREDS, + SCTP_MIB_AUTOCLOSE_EXPIREDS, + SCTP_MIB_T1_RETRANSMITS, + SCTP_MIB_T3_RETRANSMITS, + SCTP_MIB_PMTUD_RETRANSMITS, + SCTP_MIB_FAST_RETRANSMITS, + SCTP_MIB_IN_PKT_SOFTIRQ, + SCTP_MIB_IN_PKT_BACKLOG, + SCTP_MIB_IN_PKT_DISCARDS, + SCTP_MIB_IN_DATA_CHUNK_DISCARDS, + __SCTP_MIB_MAX +}; + +#define SCTP_MIB_MAX __SCTP_MIB_MAX +struct sctp_mib { + unsigned long mibs[SCTP_MIB_MAX]; +}; + + +/* Print debugging messages. */ +#if SCTP_DEBUG +extern int sctp_debug_flag; +#define SCTP_DEBUG_PRINTK(whatever...) \ + ((void) (sctp_debug_flag && printk(KERN_DEBUG whatever))) +#define SCTP_DEBUG_PRINTK_IPADDR(lead, trail, leadparm, saddr, otherparms...) \ + if (sctp_debug_flag) { \ + if (saddr->sa.sa_family == AF_INET6) { \ + printk(KERN_DEBUG \ + lead "%pI6" trail, \ + leadparm, \ + &saddr->v6.sin6_addr, \ + otherparms); \ + } else { \ + printk(KERN_DEBUG \ + lead "%pI4" trail, \ + leadparm, \ + &saddr->v4.sin_addr.s_addr, \ + otherparms); \ + } \ + } +#define SCTP_ENABLE_DEBUG { sctp_debug_flag = 1; } +#define SCTP_DISABLE_DEBUG { sctp_debug_flag = 0; } + +#define SCTP_ASSERT(expr, str, func) \ + if (!(expr)) { \ + SCTP_DEBUG_PRINTK("Assertion Failed: %s(%s) at %s:%s:%d\n", \ + str, (#expr), __FILE__, __func__, __LINE__); \ + func; \ + } + +#else /* SCTP_DEBUG */ + +#define SCTP_DEBUG_PRINTK(whatever...) +#define SCTP_DEBUG_PRINTK_IPADDR(whatever...) +#define SCTP_ENABLE_DEBUG +#define SCTP_DISABLE_DEBUG +#define SCTP_ASSERT(expr, str, func) + +#endif /* SCTP_DEBUG */ + + +/* + * Macros for keeping a global reference of object allocations. + */ +#ifdef CONFIG_SCTP_DBG_OBJCNT + +extern atomic_t sctp_dbg_objcnt_sock; +extern atomic_t sctp_dbg_objcnt_ep; +extern atomic_t sctp_dbg_objcnt_assoc; +extern atomic_t sctp_dbg_objcnt_transport; +extern atomic_t sctp_dbg_objcnt_chunk; +extern atomic_t sctp_dbg_objcnt_bind_addr; +extern atomic_t sctp_dbg_objcnt_bind_bucket; +extern atomic_t sctp_dbg_objcnt_addr; +extern atomic_t sctp_dbg_objcnt_ssnmap; +extern atomic_t sctp_dbg_objcnt_datamsg; +extern atomic_t sctp_dbg_objcnt_keys; + +/* Macros to atomically increment/decrement objcnt counters. */ +#define SCTP_DBG_OBJCNT_INC(name) \ +atomic_inc(&sctp_dbg_objcnt_## name) +#define SCTP_DBG_OBJCNT_DEC(name) \ +atomic_dec(&sctp_dbg_objcnt_## name) +#define SCTP_DBG_OBJCNT(name) \ +atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0) + +/* Macro to help create new entries in in the global array of + * objcnt counters. + */ +#define SCTP_DBG_OBJCNT_ENTRY(name) \ +{.label= #name, .counter= &sctp_dbg_objcnt_## name} + +void sctp_dbg_objcnt_init(void); +void sctp_dbg_objcnt_exit(void); + +#else + +#define SCTP_DBG_OBJCNT_INC(name) +#define SCTP_DBG_OBJCNT_DEC(name) + +static inline void sctp_dbg_objcnt_init(void) { return; } +static inline void sctp_dbg_objcnt_exit(void) { return; } + +#endif /* CONFIG_SCTP_DBG_OBJCOUNT */ + +#if defined CONFIG_SYSCTL +void sctp_sysctl_register(void); +void sctp_sysctl_unregister(void); +#else +static inline void sctp_sysctl_register(void) { return; } +static inline void sctp_sysctl_unregister(void) { return; } +#endif + +/* Size of Supported Address Parameter for 'x' address types. */ +#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16)) + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +void sctp_v6_pf_init(void); +void sctp_v6_pf_exit(void); +int sctp_v6_protosw_init(void); +void sctp_v6_protosw_exit(void); +int sctp_v6_add_protocol(void); +void sctp_v6_del_protocol(void); + +#else /* #ifdef defined(CONFIG_IPV6) */ + +static inline void sctp_v6_pf_init(void) { return; } +static inline void sctp_v6_pf_exit(void) { return; } +static inline int sctp_v6_protosw_init(void) { return 0; } +static inline void sctp_v6_protosw_exit(void) { return; } +static inline int sctp_v6_add_protocol(void) { return 0; } +static inline void sctp_v6_del_protocol(void) { return; } + +#endif /* #if defined(CONFIG_IPV6) */ + + +/* Map an association to an assoc_id. */ +static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc) +{ + return (asoc?asoc->assoc_id:0); +} + +/* Look up the association by its id. */ +struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); + + +/* A macro to walk a list of skbs. */ +#define sctp_skb_for_each(pos, head, tmp) \ + skb_queue_walk_safe(head, pos, tmp) + +/* A helper to append an entire skb list (list) to another (head). */ +static inline void sctp_skb_list_tail(struct sk_buff_head *list, + struct sk_buff_head *head) +{ + unsigned long flags; + + sctp_spin_lock_irqsave(&head->lock, flags); + sctp_spin_lock(&list->lock); + + skb_queue_splice_tail_init(list, head); + + sctp_spin_unlock(&list->lock); + sctp_spin_unlock_irqrestore(&head->lock, flags); +} + +/** + * sctp_list_dequeue - remove from the head of the queue + * @list: list to dequeue from + * + * Remove the head of the list. The head item is + * returned or %NULL if the list is empty. + */ + +static inline struct list_head *sctp_list_dequeue(struct list_head *list) +{ + struct list_head *result = NULL; + + if (list->next != list) { + result = list->next; + list->next = result->next; + list->next->prev = list; + INIT_LIST_HEAD(result); + } + return result; +} + +/* SCTP version of skb_set_owner_r. We need this one because + * of the way we have to do receive buffer accounting on bundled + * chunks. + */ +static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) +{ + struct sctp_ulpevent *event = sctp_skb2event(skb); + + skb_orphan(skb); + skb->sk = sk; + skb->destructor = sctp_sock_rfree; + atomic_add(event->rmem_len, &sk->sk_rmem_alloc); + /* + * This mimics the behavior of skb_set_owner_r + */ + sk->sk_forward_alloc -= event->rmem_len; +} + +/* Tests if the list has one and only one entry. */ +static inline int sctp_list_single_entry(struct list_head *head) +{ + return ((head->next != head) && (head->next == head->prev)); +} + +/* Generate a random jitter in the range of -50% ~ +50% of input RTO. */ +static inline __s32 sctp_jitter(__u32 rto) +{ + static __u32 sctp_rand; + __s32 ret; + + /* Avoid divide by zero. */ + if (!rto) + rto = 1; + + sctp_rand += jiffies; + sctp_rand ^= (sctp_rand << 12); + sctp_rand ^= (sctp_rand >> 20); + + /* Choose random number from 0 to rto, then move to -50% ~ +50% + * of rto. + */ + ret = sctp_rand % rto - (rto >> 1); + return ret; +} + +/* Break down data chunks at this point. */ +static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu) +{ + struct sctp_sock *sp = sctp_sk(asoc->base.sk); + int frag = pmtu; + + frag -= sp->pf->af->net_header_len; + frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk); + + if (asoc->user_frag) + frag = min_t(int, frag, asoc->user_frag); + + frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN); + + return frag; +} + +static inline void sctp_assoc_pending_pmtu(struct sctp_association *asoc) +{ + + sctp_assoc_sync_pmtu(asoc); + asoc->pmtu_pending = 0; +} + +/* Walk through a list of TLV parameters. Don't trust the + * individual parameter lengths and instead depend on + * the chunk length to indicate when to stop. Make sure + * there is room for a param header too. + */ +#define sctp_walk_params(pos, chunk, member)\ +_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member) + +#define _sctp_walk_params(pos, chunk, end, member)\ +for (pos.v = chunk->member;\ + pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\ + pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\ + ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\ + pos.v += WORD_ROUND(ntohs(pos.p->length))) + +#define sctp_walk_errors(err, chunk_hdr)\ +_sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length)) + +#define _sctp_walk_errors(err, chunk_hdr, end)\ +for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \ + sizeof(sctp_chunkhdr_t));\ + (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\ + (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\ + ntohs(err->length) >= sizeof(sctp_errhdr_t); \ + err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length)))) + +#define sctp_walk_fwdtsn(pos, chunk)\ +_sctp_walk_fwdtsn((pos), (chunk), ntohs((chunk)->chunk_hdr->length) - sizeof(struct sctp_fwdtsn_chunk)) + +#define _sctp_walk_fwdtsn(pos, chunk, end)\ +for (pos = chunk->subh.fwdtsn_hdr->skip;\ + (void *)pos <= (void *)chunk->subh.fwdtsn_hdr->skip + end - sizeof(struct sctp_fwdtsn_skip);\ + pos++) + +/* Round an int up to the next multiple of 4. */ +#define WORD_ROUND(s) (((s)+3)&~3) + +/* Make a new instance of type. */ +#define t_new(type, flags) (type *)kzalloc(sizeof(type), flags) + +/* Compare two timevals. */ +#define tv_lt(s, t) \ + (s.tv_sec < t.tv_sec || (s.tv_sec == t.tv_sec && s.tv_usec < t.tv_usec)) + +/* Add tv1 to tv2. */ +#define TIMEVAL_ADD(tv1, tv2) \ +({ \ + suseconds_t usecs = (tv2).tv_usec + (tv1).tv_usec; \ + time_t secs = (tv2).tv_sec + (tv1).tv_sec; \ +\ + if (usecs >= 1000000) { \ + usecs -= 1000000; \ + secs++; \ + } \ + (tv2).tv_sec = secs; \ + (tv2).tv_usec = usecs; \ +}) + +/* External references. */ + +extern struct proto sctp_prot; +extern struct proto sctpv6_prot; +extern struct proc_dir_entry *proc_net_sctp; +void sctp_put_port(struct sock *sk); + +extern struct idr sctp_assocs_id; +extern spinlock_t sctp_assocs_id_lock; + +/* Static inline functions. */ + +/* Convert from an IP version number to an Address Family symbol. */ +static inline int ipver2af(__u8 ipver) +{ + switch (ipver) { + case 4: + return AF_INET; + case 6: + return AF_INET6; + default: + return 0; + }; +} + +/* Convert from an address parameter type to an address family. */ +static inline int param_type2af(__be16 type) +{ + switch (type) { + case SCTP_PARAM_IPV4_ADDRESS: + return AF_INET; + case SCTP_PARAM_IPV6_ADDRESS: + return AF_INET6; + default: + return 0; + }; +} + +/* Perform some sanity checks. */ +static inline int sctp_sanity_check(void) +{ + SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= + sizeof(((struct sk_buff *)0)->cb), + "SCTP: ulpevent does not fit in skb!\n", return 0); + + return 1; +} + +/* Warning: The following hash functions assume a power of two 'size'. */ +/* This is the hash function for the SCTP port hash table. */ +static inline int sctp_phashfn(__u16 lport) +{ + return (lport & (sctp_port_hashsize - 1)); +} + +/* This is the hash function for the endpoint hash table. */ +static inline int sctp_ep_hashfn(__u16 lport) +{ + return (lport & (sctp_ep_hashsize - 1)); +} + +/* This is the hash function for the association hash table. */ +static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) +{ + int h = (lport << 16) + rport; + h ^= h>>8; + return (h & (sctp_assoc_hashsize - 1)); +} + +/* This is the hash function for the association hash table. This is + * not used yet, but could be used as a better hash function when + * we have a vtag. + */ +static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) +{ + int h = (lport << 16) + rport; + h ^= vtag; + return (h & (sctp_assoc_hashsize-1)); +} + +#define sctp_for_each_hentry(epb, node, head) \ + hlist_for_each_entry(epb, node, head, node) + +/* Is a socket of this style? */ +#define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) +static inline int __sctp_style(const struct sock *sk, sctp_socket_type_t style) +{ + return sctp_sk(sk)->type == style; +} + +/* Is the association in this state? */ +#define sctp_state(asoc, state) __sctp_state((asoc), (SCTP_STATE_##state)) +static inline int __sctp_state(const struct sctp_association *asoc, + sctp_state_t state) +{ + return asoc->state == state; +} + +/* Is the socket in this state? */ +#define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state)) +static inline int __sctp_sstate(const struct sock *sk, sctp_sock_state_t state) +{ + return sk->sk_state == state; +} + +/* Map v4-mapped v6 address back to v4 address */ +static inline void sctp_v6_map_v4(union sctp_addr *addr) +{ + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = addr->v6.sin6_port; + addr->v4.sin_addr.s_addr = addr->v6.sin6_addr.s6_addr32[3]; +} + +/* Map v4 address to v4-mapped v6 address */ +static inline void sctp_v4_map_v6(union sctp_addr *addr) +{ + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = addr->v4.sin_port; + addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + addr->v6.sin6_addr.s6_addr32[0] = 0; + addr->v6.sin6_addr.s6_addr32[1] = 0; + addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff); +} + +#endif /* __net_sctp_h__ */ diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h new file mode 100644 index 00000000..4088c89a --- /dev/null +++ b/include/net/sctp/sm.h @@ -0,0 +1,449 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * These are definitions needed by the state machine. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email addresses: + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll <piggy@acm.org> + * Karl Knutson <karl@athena.chicago.il.us> + * Xingang Guo <xingang.guo@intel.com> + * Jon Grimm <jgrimm@us.ibm.com> + * Dajiang Zhang <dajiang.zhang@nokia.com> + * Sridhar Samudrala <sri@us.ibm.com> + * Daisy Chang <daisyc@us.ibm.com> + * Ardelle Fan <ardelle.fan@intel.com> + * Kevin Gao <kevin.gao@intel.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include <linux/types.h> +#include <linux/compiler.h> +#include <linux/slab.h> +#include <linux/in.h> +#include <net/sctp/command.h> +#include <net/sctp/sctp.h> + +#ifndef __sctp_sm_h__ +#define __sctp_sm_h__ + +/* + * Possible values for the disposition are: + */ +typedef enum { + SCTP_DISPOSITION_DISCARD, /* No further processing. */ + SCTP_DISPOSITION_CONSUME, /* Process return values normally. */ + SCTP_DISPOSITION_NOMEM, /* We ran out of memory--recover. */ + SCTP_DISPOSITION_DELETE_TCB, /* Close the association. */ + SCTP_DISPOSITION_ABORT, /* Close the association NOW. */ + SCTP_DISPOSITION_VIOLATION, /* The peer is misbehaving. */ + SCTP_DISPOSITION_NOT_IMPL, /* This entry is not implemented. */ + SCTP_DISPOSITION_ERROR, /* This is plain old user error. */ + SCTP_DISPOSITION_BUG, /* This is a bug. */ +} sctp_disposition_t; + +typedef struct { + int name; + int action; +} sctp_sm_command_t; + +typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *, + const struct sctp_association *, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *); +typedef void (sctp_timer_event_t) (unsigned long); +typedef struct { + sctp_state_fn_t *fn; + const char *name; +} sctp_sm_table_entry_t; + +/* A naming convention of "sctp_sf_xxx" applies to all the state functions + * currently in use. + */ + +/* Prototypes for generic state functions. */ +sctp_state_fn_t sctp_sf_not_impl; +sctp_state_fn_t sctp_sf_bug; + +/* Prototypes for gener timer state functions. */ +sctp_state_fn_t sctp_sf_timer_ignore; + +/* Prototypes for chunk state functions. */ +sctp_state_fn_t sctp_sf_do_9_1_abort; +sctp_state_fn_t sctp_sf_cookie_wait_abort; +sctp_state_fn_t sctp_sf_cookie_echoed_abort; +sctp_state_fn_t sctp_sf_shutdown_pending_abort; +sctp_state_fn_t sctp_sf_shutdown_sent_abort; +sctp_state_fn_t sctp_sf_shutdown_ack_sent_abort; +sctp_state_fn_t sctp_sf_do_5_1B_init; +sctp_state_fn_t sctp_sf_do_5_1C_ack; +sctp_state_fn_t sctp_sf_do_5_1D_ce; +sctp_state_fn_t sctp_sf_do_5_1E_ca; +sctp_state_fn_t sctp_sf_do_4_C; +sctp_state_fn_t sctp_sf_eat_data_6_2; +sctp_state_fn_t sctp_sf_eat_data_fast_4_4; +sctp_state_fn_t sctp_sf_eat_sack_6_2; +sctp_state_fn_t sctp_sf_operr_notify; +sctp_state_fn_t sctp_sf_t1_init_timer_expire; +sctp_state_fn_t sctp_sf_t1_cookie_timer_expire; +sctp_state_fn_t sctp_sf_t2_timer_expire; +sctp_state_fn_t sctp_sf_t4_timer_expire; +sctp_state_fn_t sctp_sf_t5_timer_expire; +sctp_state_fn_t sctp_sf_sendbeat_8_3; +sctp_state_fn_t sctp_sf_beat_8_3; +sctp_state_fn_t sctp_sf_backbeat_8_3; +sctp_state_fn_t sctp_sf_do_9_2_final; +sctp_state_fn_t sctp_sf_do_9_2_shutdown; +sctp_state_fn_t sctp_sf_do_9_2_shut_ctsn; +sctp_state_fn_t sctp_sf_do_ecn_cwr; +sctp_state_fn_t sctp_sf_do_ecne; +sctp_state_fn_t sctp_sf_ootb; +sctp_state_fn_t sctp_sf_pdiscard; +sctp_state_fn_t sctp_sf_violation; +sctp_state_fn_t sctp_sf_discard_chunk; +sctp_state_fn_t sctp_sf_do_5_2_1_siminit; +sctp_state_fn_t sctp_sf_do_5_2_2_dupinit; +sctp_state_fn_t sctp_sf_do_5_2_3_initack; +sctp_state_fn_t sctp_sf_do_5_2_4_dupcook; +sctp_state_fn_t sctp_sf_unk_chunk; +sctp_state_fn_t sctp_sf_do_8_5_1_E_sa; +sctp_state_fn_t sctp_sf_cookie_echoed_err; +sctp_state_fn_t sctp_sf_do_asconf; +sctp_state_fn_t sctp_sf_do_asconf_ack; +sctp_state_fn_t sctp_sf_do_9_2_reshutack; +sctp_state_fn_t sctp_sf_eat_fwd_tsn; +sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast; +sctp_state_fn_t sctp_sf_eat_auth; + +/* Prototypes for primitive event state functions. */ +sctp_state_fn_t sctp_sf_do_prm_asoc; +sctp_state_fn_t sctp_sf_do_prm_send; +sctp_state_fn_t sctp_sf_do_9_2_prm_shutdown; +sctp_state_fn_t sctp_sf_cookie_wait_prm_shutdown; +sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown; +sctp_state_fn_t sctp_sf_do_9_1_prm_abort; +sctp_state_fn_t sctp_sf_cookie_wait_prm_abort; +sctp_state_fn_t sctp_sf_cookie_echoed_prm_abort; +sctp_state_fn_t sctp_sf_shutdown_pending_prm_abort; +sctp_state_fn_t sctp_sf_shutdown_sent_prm_abort; +sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort; +sctp_state_fn_t sctp_sf_error_closed; +sctp_state_fn_t sctp_sf_error_shutdown; +sctp_state_fn_t sctp_sf_ignore_primitive; +sctp_state_fn_t sctp_sf_do_prm_requestheartbeat; +sctp_state_fn_t sctp_sf_do_prm_asconf; + +/* Prototypes for other event state functions. */ +sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; +sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack; +sctp_state_fn_t sctp_sf_ignore_other; +sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort; + +/* Prototypes for timeout event state functions. */ +sctp_state_fn_t sctp_sf_do_6_3_3_rtx; +sctp_state_fn_t sctp_sf_do_6_2_sack; +sctp_state_fn_t sctp_sf_autoclose_timer_expire; + +/* Prototypes for utility support functions. */ +__u8 sctp_get_chunk_type(struct sctp_chunk *chunk); +const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t, + sctp_state_t, + sctp_subtype_t); +int sctp_chunk_iif(const struct sctp_chunk *); +struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *, + struct sctp_chunk *, + gfp_t gfp); +__u32 sctp_generate_verification_tag(void); +void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); + +/* Prototypes for chunk-building functions. */ +struct sctp_chunk *sctp_make_init(const struct sctp_association *, + const struct sctp_bind_addr *, + gfp_t gfp, int vparam_len); +struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *, + const struct sctp_chunk *, + const gfp_t gfp, + const int unkparam_len); +struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cwr(const struct sctp_association *, + const __u32 lowest_tsn, + const struct sctp_chunk *); +struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *, + const struct sctp_sndrcvinfo *sinfo, + int len, const __u8 flags, + __u16 ssn); +struct sctp_chunk *sctp_make_ecne(const struct sctp_association *, + const __u32); +struct sctp_chunk *sctp_make_sack(const struct sctp_association *); +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, + const struct sctp_chunk *chunk); +struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, + const struct sctp_chunk *); +void sctp_init_cause(struct sctp_chunk *, __be16 cause, size_t); +struct sctp_chunk *sctp_make_abort(const struct sctp_association *, + const struct sctp_chunk *, + const size_t hint); +struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *, + const struct sctp_chunk *, + __u32 tsn); +struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *, + const struct msghdr *, size_t msg_len); +struct sctp_chunk *sctp_make_abort_violation(const struct sctp_association *, + const struct sctp_chunk *, + const __u8 *, + const size_t ); +struct sctp_chunk *sctp_make_violation_paramlen(const struct sctp_association *, + const struct sctp_chunk *, + struct sctp_paramhdr *); +struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *, + const struct sctp_transport *, + const void *payload, + const size_t paylen); +struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *, + const struct sctp_chunk *, + const void *payload, + const size_t paylen); +struct sctp_chunk *sctp_make_op_error(const struct sctp_association *, + const struct sctp_chunk *chunk, + __be16 cause_code, + const void *payload, + size_t paylen, + size_t reserve_tail); + +struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, + union sctp_addr *, + struct sockaddr *, + int, __be16); +struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, + union sctp_addr *addr); +int sctp_verify_asconf(const struct sctp_association *asoc, + struct sctp_paramhdr *param_hdr, void *chunk_end, + struct sctp_paramhdr **errp); +struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, + struct sctp_chunk *asconf); +int sctp_process_asconf_ack(struct sctp_association *asoc, + struct sctp_chunk *asconf_ack); +struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, + __u32 new_cum_tsn, size_t nstreams, + struct sctp_fwdtsn_skip *skiplist); +struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc); + +void sctp_chunk_assign_tsn(struct sctp_chunk *); +void sctp_chunk_assign_ssn(struct sctp_chunk *); + +/* Prototypes for statetable processing. */ + +int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + struct sctp_endpoint *, + struct sctp_association *asoc, + void *event_arg, + gfp_t gfp); + +/* 2nd level prototypes */ +void sctp_generate_t3_rtx_event(unsigned long peer); +void sctp_generate_heartbeat_event(unsigned long peer); +void sctp_generate_proto_unreach_event(unsigned long peer); + +void sctp_ootb_pkt_free(struct sctp_packet *); + +struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *, + const struct sctp_association *, + struct sctp_chunk *, + gfp_t gfp, int *err, + struct sctp_chunk **err_chk_p); +int sctp_addip_addr_config(struct sctp_association *, sctp_param_t, + struct sockaddr_storage*, int); + +/* 3rd level prototypes */ +__u32 sctp_generate_tag(const struct sctp_endpoint *); +__u32 sctp_generate_tsn(const struct sctp_endpoint *); + +/* Extern declarations for major data structures. */ +extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES]; + + +/* Get the size of a DATA chunk payload. */ +static inline __u16 sctp_data_size(struct sctp_chunk *chunk) +{ + __u16 size; + + size = ntohs(chunk->chunk_hdr->length); + size -= sizeof(sctp_data_chunk_t); + + return size; +} + +/* Compare two TSNs */ + +/* RFC 1982 - Serial Number Arithmetic + * + * 2. Comparison + * Then, s1 is said to be equal to s2 if and only if i1 is equal to i2, + * in all other cases, s1 is not equal to s2. + * + * s1 is said to be less than s2 if, and only if, s1 is not equal to s2, + * and + * + * (i1 < i2 and i2 - i1 < 2^(SERIAL_BITS - 1)) or + * (i1 > i2 and i1 - i2 > 2^(SERIAL_BITS - 1)) + * + * s1 is said to be greater than s2 if, and only if, s1 is not equal to + * s2, and + * + * (i1 < i2 and i2 - i1 > 2^(SERIAL_BITS - 1)) or + * (i1 > i2 and i1 - i2 < 2^(SERIAL_BITS - 1)) + */ + +/* + * RFC 2960 + * 1.6 Serial Number Arithmetic + * + * Comparisons and arithmetic on TSNs in this document SHOULD use Serial + * Number Arithmetic as defined in [RFC1982] where SERIAL_BITS = 32. + */ + +enum { + TSN_SIGN_BIT = (1<<31) +}; + +static inline int TSN_lt(__u32 s, __u32 t) +{ + return (((s) - (t)) & TSN_SIGN_BIT); +} + +static inline int TSN_lte(__u32 s, __u32 t) +{ + return (((s) == (t)) || (((s) - (t)) & TSN_SIGN_BIT)); +} + +/* Compare two SSNs */ + +/* + * RFC 2960 + * 1.6 Serial Number Arithmetic + * + * Comparisons and arithmetic on Stream Sequence Numbers in this document + * SHOULD use Serial Number Arithmetic as defined in [RFC1982] where + * SERIAL_BITS = 16. + */ +enum { + SSN_SIGN_BIT = (1<<15) +}; + +static inline int SSN_lt(__u16 s, __u16 t) +{ + return (((s) - (t)) & SSN_SIGN_BIT); +} + +static inline int SSN_lte(__u16 s, __u16 t) +{ + return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT)); +} + +/* + * ADDIP 3.1.1 + * The valid range of Serial Number is from 0 to 4294967295 (2**32 - 1). Serial + * Numbers wrap back to 0 after reaching 4294967295. + */ +enum { + ADDIP_SERIAL_SIGN_BIT = (1<<31) +}; + +static inline int ADDIP_SERIAL_gte(__u16 s, __u16 t) +{ + return (((s) == (t)) || (((t) - (s)) & ADDIP_SERIAL_SIGN_BIT)); +} + +/* Check VTAG of the packet matches the sender's own tag. */ +static inline int +sctp_vtag_verify(const struct sctp_chunk *chunk, + const struct sctp_association *asoc) +{ + /* RFC 2960 Sec 8.5 When receiving an SCTP packet, the endpoint + * MUST ensure that the value in the Verification Tag field of + * the received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) == asoc->c.my_vtag) + return 1; + + return 0; +} + +/* Check VTAG of the packet matches the sender's own tag and the T bit is + * not set, OR its peer's tag and the T bit is set in the Chunk Flags. + */ +static inline int +sctp_vtag_verify_either(const struct sctp_chunk *chunk, + const struct sctp_association *asoc) +{ + /* RFC 2960 Section 8.5.1, sctpimpguide Section 2.41 + * + * B) The receiver of a ABORT MUST accept the packet + * if the Verification Tag field of the packet matches its own tag + * and the T bit is not set + * OR + * it is set to its peer's tag and the T bit is set in the Chunk + * Flags. + * Otherwise, the receiver MUST silently discard the packet + * and take no further action. + * + * C) The receiver of a SHUTDOWN COMPLETE shall accept the packet + * if the Verification Tag field of the packet matches its own tag + * and the T bit is not set + * OR + * it is set to its peer's tag and the T bit is set in the Chunk + * Flags. + * Otherwise, the receiver MUST silently discard the packet + * and take no further action. An endpoint MUST ignore the + * SHUTDOWN COMPLETE if it is not in the SHUTDOWN-ACK-SENT state. + */ + if ((!sctp_test_T_bit(chunk) && + (ntohl(chunk->sctp_hdr->vtag) == asoc->c.my_vtag)) || + (sctp_test_T_bit(chunk) && asoc->c.peer_vtag && + (ntohl(chunk->sctp_hdr->vtag) == asoc->c.peer_vtag))) { + return 1; + } + + return 0; +} + +#endif /* __sctp_sm_h__ */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h new file mode 100644 index 00000000..f9e74736 --- /dev/null +++ b/include/net/sctp/structs.h @@ -0,0 +1,2019 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email addresses: + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randall Stewart <randall@sctp.chicago.il.us> + * Ken Morneau <kmorneau@cisco.com> + * Qiaobing Xie <qxie1@email.mot.com> + * La Monte H.P. Yarroll <piggy@acm.org> + * Karl Knutson <karl@athena.chicago.il.us> + * Jon Grimm <jgrimm@us.ibm.com> + * Xingang Guo <xingang.guo@intel.com> + * Hui Huang <hui.huang@nokia.com> + * Sridhar Samudrala <sri@us.ibm.com> + * Daisy Chang <daisyc@us.ibm.com> + * Dajiang Zhang <dajiang.zhang@nokia.com> + * Ardelle Fan <ardelle.fan@intel.com> + * Ryan Layer <rmlayer@us.ibm.com> + * Anup Pemmaiah <pemmaiah@cc.usu.edu> + * Kevin Gao <kevin.gao@intel.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_structs_h__ +#define __sctp_structs_h__ + +#include <linux/time.h> /* We get struct timespec. */ +#include <linux/socket.h> /* linux/in.h needs this!! */ +#include <linux/in.h> /* We get struct sockaddr_in. */ +#include <linux/in6.h> /* We get struct in6_addr */ +#include <linux/ipv6.h> +#include <asm/param.h> /* We get MAXHOSTNAMELEN. */ +#include <asm/atomic.h> /* This gets us atomic counters. */ +#include <linux/skbuff.h> /* We need sk_buff_head. */ +#include <linux/workqueue.h> /* We need tq_struct. */ +#include <linux/sctp.h> /* We need sctp* header structs. */ +#include <net/sctp/auth.h> /* We need auth specific structs */ + +/* A convenience structure for handling sockaddr structures. + * We should wean ourselves off this. + */ +union sctp_addr { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + struct sockaddr sa; +}; + +/* Forward declarations for data structures. */ +struct sctp_globals; +struct sctp_endpoint; +struct sctp_association; +struct sctp_transport; +struct sctp_packet; +struct sctp_chunk; +struct sctp_inq; +struct sctp_outq; +struct sctp_bind_addr; +struct sctp_ulpq; +struct sctp_ep_common; +struct sctp_ssnmap; +struct crypto_hash; + + +#include <net/sctp/tsnmap.h> +#include <net/sctp/ulpevent.h> +#include <net/sctp/ulpqueue.h> + +/* Structures useful for managing bind/connect. */ + +struct sctp_bind_bucket { + unsigned short port; + unsigned short fastreuse; + struct hlist_node node; + struct hlist_head owner; +}; + +struct sctp_bind_hashbucket { + spinlock_t lock; + struct hlist_head chain; +}; + +/* Used for hashing all associations. */ +struct sctp_hashbucket { + rwlock_t lock; + struct hlist_head chain; +} __attribute__((__aligned__(8))); + + +/* The SCTP globals structure. */ +extern struct sctp_globals { + /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values + * + * The following protocol parameters are RECOMMENDED: + * + * RTO.Initial - 3 seconds + * RTO.Min - 1 second + * RTO.Max - 60 seconds + * RTO.Alpha - 1/8 (3 when converted to right shifts.) + * RTO.Beta - 1/4 (2 when converted to right shifts.) + */ + unsigned int rto_initial; + unsigned int rto_min; + unsigned int rto_max; + + /* Note: rto_alpha and rto_beta are really defined as inverse + * powers of two to facilitate integer operations. + */ + int rto_alpha; + int rto_beta; + + /* Max.Burst - 4 */ + int max_burst; + + /* Whether Cookie Preservative is enabled(1) or not(0) */ + int cookie_preserve_enable; + + /* Valid.Cookie.Life - 60 seconds */ + unsigned int valid_cookie_life; + + /* Delayed SACK timeout 200ms default*/ + unsigned int sack_timeout; + + /* HB.interval - 30 seconds */ + unsigned int hb_interval; + + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ + int max_retrans_association; + int max_retrans_path; + int max_retrans_init; + + /* + * Policy for preforming sctp/socket accounting + * 0 - do socket level accounting, all assocs share sk_sndbuf + * 1 - do sctp accounting, each asoc may use sk_sndbuf bytes + */ + int sndbuf_policy; + + /* + * Policy for preforming sctp/socket accounting + * 0 - do socket level accounting, all assocs share sk_rcvbuf + * 1 - do sctp accounting, each asoc may use sk_rcvbuf bytes + */ + int rcvbuf_policy; + + /* The following variables are implementation specific. */ + + /* Default initialization values to be applied to new associations. */ + __u16 max_instreams; + __u16 max_outstreams; + + /* This is a list of groups of functions for each address + * family that we support. + */ + struct list_head address_families; + + /* This is the hash of all endpoints. */ + int ep_hashsize; + struct sctp_hashbucket *ep_hashtable; + + /* This is the hash of all associations. */ + int assoc_hashsize; + struct sctp_hashbucket *assoc_hashtable; + + /* This is the sctp port control hash. */ + int port_hashsize; + struct sctp_bind_hashbucket *port_hashtable; + + /* This is the global local address list. + * We actively maintain this complete list of addresses on + * the system by catching address add/delete events. + * + * It is a list of sctp_sockaddr_entry. + */ + struct list_head local_addr_list; + + /* Lock that protects the local_addr_list writers */ + spinlock_t addr_list_lock; + + /* Flag to indicate if addip is enabled. */ + int addip_enable; + int addip_noauth_enable; + + /* Flag to indicate if PR-SCTP is enabled. */ + int prsctp_enable; + + /* Flag to idicate if SCTP-AUTH is enabled */ + int auth_enable; + + /* + * Policy to control SCTP IPv4 address scoping + * 0 - Disable IPv4 address scoping + * 1 - Enable IPv4 address scoping + * 2 - Selectively allow only IPv4 private addresses + * 3 - Selectively allow only IPv4 link local address + */ + int ipv4_scope_policy; + + /* Flag to indicate whether computing and verifying checksum + * is disabled. */ + int checksum_disable; + + /* Threshold for rwnd update SACKS. Receive buffer shifted this many + * bits is an indicator of when to send and window update SACK. + */ + int rwnd_update_shift; +} sctp_globals; + +#define sctp_rto_initial (sctp_globals.rto_initial) +#define sctp_rto_min (sctp_globals.rto_min) +#define sctp_rto_max (sctp_globals.rto_max) +#define sctp_rto_alpha (sctp_globals.rto_alpha) +#define sctp_rto_beta (sctp_globals.rto_beta) +#define sctp_max_burst (sctp_globals.max_burst) +#define sctp_valid_cookie_life (sctp_globals.valid_cookie_life) +#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable) +#define sctp_max_retrans_association (sctp_globals.max_retrans_association) +#define sctp_sndbuf_policy (sctp_globals.sndbuf_policy) +#define sctp_rcvbuf_policy (sctp_globals.rcvbuf_policy) +#define sctp_max_retrans_path (sctp_globals.max_retrans_path) +#define sctp_max_retrans_init (sctp_globals.max_retrans_init) +#define sctp_sack_timeout (sctp_globals.sack_timeout) +#define sctp_hb_interval (sctp_globals.hb_interval) +#define sctp_max_instreams (sctp_globals.max_instreams) +#define sctp_max_outstreams (sctp_globals.max_outstreams) +#define sctp_address_families (sctp_globals.address_families) +#define sctp_ep_hashsize (sctp_globals.ep_hashsize) +#define sctp_ep_hashtable (sctp_globals.ep_hashtable) +#define sctp_assoc_hashsize (sctp_globals.assoc_hashsize) +#define sctp_assoc_hashtable (sctp_globals.assoc_hashtable) +#define sctp_port_hashsize (sctp_globals.port_hashsize) +#define sctp_port_rover (sctp_globals.port_rover) +#define sctp_port_alloc_lock (sctp_globals.port_alloc_lock) +#define sctp_port_hashtable (sctp_globals.port_hashtable) +#define sctp_local_addr_list (sctp_globals.local_addr_list) +#define sctp_local_addr_lock (sctp_globals.addr_list_lock) +#define sctp_scope_policy (sctp_globals.ipv4_scope_policy) +#define sctp_addip_enable (sctp_globals.addip_enable) +#define sctp_addip_noauth (sctp_globals.addip_noauth_enable) +#define sctp_prsctp_enable (sctp_globals.prsctp_enable) +#define sctp_auth_enable (sctp_globals.auth_enable) +#define sctp_checksum_disable (sctp_globals.checksum_disable) +#define sctp_rwnd_upd_shift (sctp_globals.rwnd_update_shift) + +/* SCTP Socket type: UDP or TCP style. */ +typedef enum { + SCTP_SOCKET_UDP = 0, + SCTP_SOCKET_UDP_HIGH_BANDWIDTH, + SCTP_SOCKET_TCP +} sctp_socket_type_t; + +/* Per socket SCTP information. */ +struct sctp_sock { + /* inet_sock has to be the first member of sctp_sock */ + struct inet_sock inet; + /* What kind of a socket is this? */ + sctp_socket_type_t type; + + /* PF_ family specific functions. */ + struct sctp_pf *pf; + + /* Access to HMAC transform. */ + struct crypto_hash *hmac; + + /* What is our base endpointer? */ + struct sctp_endpoint *ep; + + struct sctp_bind_bucket *bind_hash; + /* Various Socket Options. */ + __u16 default_stream; + __u32 default_ppid; + __u16 default_flags; + __u32 default_context; + __u32 default_timetolive; + __u32 default_rcv_context; + int max_burst; + + /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to + * the destination address every heartbeat interval. This value + * will be inherited by all new associations. + */ + __u32 hbinterval; + + /* This is the max_retrans value for new associations. */ + __u16 pathmaxrxt; + + /* The initial Path MTU to use for new associations. */ + __u32 pathmtu; + + /* The default SACK delay timeout for new associations. */ + __u32 sackdelay; + __u32 sackfreq; + + /* Flags controlling Heartbeat, SACK delay, and Path MTU Discovery. */ + __u32 param_flags; + + struct sctp_initmsg initmsg; + struct sctp_rtoinfo rtoinfo; + struct sctp_paddrparams paddrparam; + struct sctp_event_subscribe subscribe; + struct sctp_assocparams assocparams; + int user_frag; + __u32 autoclose; + __u8 nodelay; + __u8 disable_fragments; + __u8 v4mapped; + __u8 frag_interleave; + __u32 adaptation_ind; + __u32 pd_point; + + atomic_t pd_mode; + /* Receive to here while partial delivery is in effect. */ + struct sk_buff_head pd_lobby; +}; + +static inline struct sctp_sock *sctp_sk(const struct sock *sk) +{ + return (struct sctp_sock *)sk; +} + +static inline struct sock *sctp_opt2sk(const struct sctp_sock *sp) +{ + return (struct sock *)sp; +} + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +struct sctp6_sock { + struct sctp_sock sctp; + struct ipv6_pinfo inet6; +}; +#endif /* CONFIG_IPV6 */ + + +/* This is our APPLICATION-SPECIFIC state cookie. + * THIS IS NOT DICTATED BY THE SPECIFICATION. + */ +/* These are the parts of an association which we send in the cookie. + * Most of these are straight out of: + * RFC2960 12.2 Parameters necessary per association (i.e. the TCB) + * + */ + +struct sctp_cookie { + + /* My : Tag expected in every inbound packet and sent + * Verification: in the INIT or INIT ACK chunk. + * Tag : + */ + __u32 my_vtag; + + /* Peer's : Tag expected in every outbound packet except + * Verification: in the INIT chunk. + * Tag : + */ + __u32 peer_vtag; + + /* The rest of these are not from the spec, but really need to + * be in the cookie. + */ + + /* My Tie Tag : Assist in discovering a restarting association. */ + __u32 my_ttag; + + /* Peer's Tie Tag: Assist in discovering a restarting association. */ + __u32 peer_ttag; + + /* When does this cookie expire? */ + struct timeval expiration; + + /* Number of inbound/outbound streams which are set + * and negotiated during the INIT process. + */ + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; + + /* This is the first sequence number I used. */ + __u32 initial_tsn; + + /* This holds the originating address of the INIT packet. */ + union sctp_addr peer_addr; + + /* IG Section 2.35.3 + * Include the source port of the INIT-ACK + */ + __u16 my_port; + + __u8 prsctp_capable; + + /* Padding for future use */ + __u8 padding; + + __u32 adaptation_ind; + + __u8 auth_random[sizeof(sctp_paramhdr_t) + SCTP_AUTH_RANDOM_LENGTH]; + __u8 auth_hmacs[SCTP_AUTH_NUM_HMACS + 2]; + __u8 auth_chunks[sizeof(sctp_paramhdr_t) + SCTP_AUTH_MAX_CHUNKS]; + + /* This is a shim for my peer's INIT packet, followed by + * a copy of the raw address list of the association. + * The length of the raw address list is saved in the + * raw_addr_list_len field, which will be used at the time when + * the association TCB is re-constructed from the cookie. + */ + __u32 raw_addr_list_len; + struct sctp_init_chunk peer_init[0]; +}; + + +/* The format of our cookie that we send to our peer. */ +struct sctp_signed_cookie { + __u8 signature[SCTP_SECRET_SIZE]; + __u32 __pad; /* force sctp_cookie alignment to 64 bits */ + struct sctp_cookie c; +} __packed; + +/* This is another convenience type to allocate memory for address + * params for the maximum size and pass such structures around + * internally. + */ +union sctp_addr_param { + struct sctp_paramhdr p; + struct sctp_ipv4addr_param v4; + struct sctp_ipv6addr_param v6; +}; + +/* A convenience type to allow walking through the various + * parameters and avoid casting all over the place. + */ +union sctp_params { + void *v; + struct sctp_paramhdr *p; + struct sctp_cookie_preserve_param *life; + struct sctp_hostname_param *dns; + struct sctp_cookie_param *cookie; + struct sctp_supported_addrs_param *sat; + struct sctp_ipv4addr_param *v4; + struct sctp_ipv6addr_param *v6; + union sctp_addr_param *addr; + struct sctp_adaptation_ind_param *aind; + struct sctp_supported_ext_param *ext; + struct sctp_random_param *random; + struct sctp_chunks_param *chunks; + struct sctp_hmac_algo_param *hmac_algo; + struct sctp_addip_param *addip; +}; + +/* RFC 2960. Section 3.3.5 Heartbeat. + * Heartbeat Information: variable length + * The Sender-specific Heartbeat Info field should normally include + * information about the sender's current time when this HEARTBEAT + * chunk is sent and the destination transport address to which this + * HEARTBEAT is sent (see Section 8.3). + */ +typedef struct sctp_sender_hb_info { + struct sctp_paramhdr param_hdr; + union sctp_addr daddr; + unsigned long sent_at; + __u64 hb_nonce; +} __packed sctp_sender_hb_info_t; + +/* + * RFC 2960 1.3.2 Sequenced Delivery within Streams + * + * The term "stream" is used in SCTP to refer to a sequence of user + * messages that are to be delivered to the upper-layer protocol in + * order with respect to other messages within the same stream. This is + * in contrast to its usage in TCP, where it refers to a sequence of + * bytes (in this document a byte is assumed to be eight bits). + * ... + * + * This is the structure we use to track both our outbound and inbound + * SSN, or Stream Sequence Numbers. + */ + +struct sctp_stream { + __u16 *ssn; + unsigned int len; +}; + +struct sctp_ssnmap { + struct sctp_stream in; + struct sctp_stream out; + int malloced; +}; + +struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, + gfp_t gfp); +void sctp_ssnmap_free(struct sctp_ssnmap *map); +void sctp_ssnmap_clear(struct sctp_ssnmap *map); + +/* What is the current SSN number for this stream? */ +static inline __u16 sctp_ssn_peek(struct sctp_stream *stream, __u16 id) +{ + return stream->ssn[id]; +} + +/* Return the next SSN number for this stream. */ +static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id) +{ + return stream->ssn[id]++; +} + +/* Skip over this ssn and all below. */ +static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id, + __u16 ssn) +{ + stream->ssn[id] = ssn+1; +} + +/* + * Pointers to address related SCTP functions. + * (i.e. things that depend on the address family.) + */ +struct sctp_af { + int (*sctp_xmit) (struct sk_buff *skb, + struct sctp_transport *); + int (*setsockopt) (struct sock *sk, + int level, + int optname, + char __user *optval, + unsigned int optlen); + int (*getsockopt) (struct sock *sk, + int level, + int optname, + char __user *optval, + int __user *optlen); + int (*compat_setsockopt) (struct sock *sk, + int level, + int optname, + char __user *optval, + unsigned int optlen); + int (*compat_getsockopt) (struct sock *sk, + int level, + int optname, + char __user *optval, + int __user *optlen); + struct dst_entry *(*get_dst) (struct sctp_association *asoc, + union sctp_addr *daddr, + union sctp_addr *saddr); + void (*get_saddr) (struct sctp_sock *sk, + struct sctp_association *asoc, + struct dst_entry *dst, + union sctp_addr *daddr, + union sctp_addr *saddr); + void (*copy_addrlist) (struct list_head *, + struct net_device *); + void (*dst_saddr) (union sctp_addr *saddr, + struct dst_entry *dst, + __be16 port); + int (*cmp_addr) (const union sctp_addr *addr1, + const union sctp_addr *addr2); + void (*addr_copy) (union sctp_addr *dst, + union sctp_addr *src); + void (*from_skb) (union sctp_addr *, + struct sk_buff *skb, + int saddr); + void (*from_sk) (union sctp_addr *, + struct sock *sk); + void (*to_sk_saddr) (union sctp_addr *, + struct sock *sk); + void (*to_sk_daddr) (union sctp_addr *, + struct sock *sk); + void (*from_addr_param) (union sctp_addr *, + union sctp_addr_param *, + __be16 port, int iif); + int (*to_addr_param) (const union sctp_addr *, + union sctp_addr_param *); + int (*addr_valid) (union sctp_addr *, + struct sctp_sock *, + const struct sk_buff *); + sctp_scope_t (*scope) (union sctp_addr *); + void (*inaddr_any) (union sctp_addr *, __be16); + int (*is_any) (const union sctp_addr *); + int (*available) (union sctp_addr *, + struct sctp_sock *); + int (*skb_iif) (const struct sk_buff *sk); + int (*is_ce) (const struct sk_buff *sk); + void (*seq_dump_addr)(struct seq_file *seq, + union sctp_addr *addr); + void (*ecn_capable)(struct sock *sk); + __u16 net_header_len; + int sockaddr_len; + sa_family_t sa_family; + struct list_head list; +}; + +struct sctp_af *sctp_get_af_specific(sa_family_t); +int sctp_register_af(struct sctp_af *); + +/* Protocol family functions. */ +struct sctp_pf { + void (*event_msgname)(struct sctp_ulpevent *, char *, int *); + void (*skb_msgname) (struct sk_buff *, char *, int *); + int (*af_supported) (sa_family_t, struct sctp_sock *); + int (*cmp_addr) (const union sctp_addr *, + const union sctp_addr *, + struct sctp_sock *); + int (*bind_verify) (struct sctp_sock *, union sctp_addr *); + int (*send_verify) (struct sctp_sock *, union sctp_addr *); + int (*supported_addrs)(const struct sctp_sock *, __be16 *); + struct sock *(*create_accept_sk) (struct sock *sk, + struct sctp_association *asoc); + void (*addr_v4map) (struct sctp_sock *, union sctp_addr *); + struct sctp_af *af; +}; + + +/* Structure to track chunk fragments that have been acked, but peer + * fragments of the same message have not. + */ +struct sctp_datamsg { + /* Chunks waiting to be submitted to lower layer. */ + struct list_head chunks; + /* Reference counting. */ + atomic_t refcnt; + /* When is this message no longer interesting to the peer? */ + unsigned long expires_at; + /* Did the messenge fail to send? */ + int send_error; + u8 send_failed:1, + can_abandon:1, /* can chunks from this message can be abandoned. */ + can_delay; /* should this message be Nagle delayed */ +}; + +struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, + struct sctp_sndrcvinfo *, + struct msghdr *, int len); +void sctp_datamsg_free(struct sctp_datamsg *); +void sctp_datamsg_put(struct sctp_datamsg *); +void sctp_chunk_fail(struct sctp_chunk *, int error); +int sctp_chunk_abandoned(struct sctp_chunk *); + +/* RFC2960 1.4 Key Terms + * + * o Chunk: A unit of information within an SCTP packet, consisting of + * a chunk header and chunk-specific content. + * + * As a matter of convenience, we remember the SCTP common header for + * each chunk as well as a few other header pointers... + */ +struct sctp_chunk { + struct list_head list; + + atomic_t refcnt; + + /* This is our link to the per-transport transmitted list. */ + struct list_head transmitted_list; + + /* This field is used by chunks that hold fragmented data. + * For the first fragment this is the list that holds the rest of + * fragments. For the remaining fragments, this is the link to the + * frag_list maintained in the first fragment. + */ + struct list_head frag_list; + + /* This points to the sk_buff containing the actual data. */ + struct sk_buff *skb; + + /* These are the SCTP headers by reverse order in a packet. + * Note that some of these may happen more than once. In that + * case, we point at the "current" one, whatever that means + * for that level of header. + */ + + /* We point this at the FIRST TLV parameter to chunk_hdr. */ + union sctp_params param_hdr; + union { + __u8 *v; + struct sctp_datahdr *data_hdr; + struct sctp_inithdr *init_hdr; + struct sctp_sackhdr *sack_hdr; + struct sctp_heartbeathdr *hb_hdr; + struct sctp_sender_hb_info *hbs_hdr; + struct sctp_shutdownhdr *shutdown_hdr; + struct sctp_signed_cookie *cookie_hdr; + struct sctp_ecnehdr *ecne_hdr; + struct sctp_cwrhdr *ecn_cwr_hdr; + struct sctp_errhdr *err_hdr; + struct sctp_addiphdr *addip_hdr; + struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_authhdr *auth_hdr; + } subh; + + __u8 *chunk_end; + + struct sctp_chunkhdr *chunk_hdr; + struct sctphdr *sctp_hdr; + + /* This needs to be recoverable for SCTP_SEND_FAILED events. */ + struct sctp_sndrcvinfo sinfo; + + /* Which association does this belong to? */ + struct sctp_association *asoc; + + /* What endpoint received this chunk? */ + struct sctp_ep_common *rcvr; + + /* We fill this in if we are calculating RTT. */ + unsigned long sent_at; + + /* What is the origin IP address for this chunk? */ + union sctp_addr source; + /* Destination address for this chunk. */ + union sctp_addr dest; + + /* For outbound message, track all fragments for SEND_FAILED. */ + struct sctp_datamsg *msg; + + /* For an inbound chunk, this tells us where it came from. + * For an outbound chunk, it tells us where we'd like it to + * go. It is NULL if we have no preference. + */ + struct sctp_transport *transport; + + /* SCTP-AUTH: For the special case inbound processing of COOKIE-ECHO + * we need save a pointer to the AUTH chunk, since the SCTP-AUTH + * spec violates the principle premis that all chunks are processed + * in order. + */ + struct sk_buff *auth_chunk; + +#define SCTP_CAN_FRTX 0x0 +#define SCTP_NEED_FRTX 0x1 +#define SCTP_DONT_FRTX 0x2 + __u16 rtt_in_progress:1, /* This chunk used for RTT calc? */ + has_tsn:1, /* Does this chunk have a TSN yet? */ + has_ssn:1, /* Does this chunk have a SSN yet? */ + singleton:1, /* Only chunk in the packet? */ + end_of_packet:1, /* Last chunk in the packet? */ + ecn_ce_done:1, /* Have we processed the ECN CE bit? */ + pdiscard:1, /* Discard the whole packet now? */ + tsn_gap_acked:1, /* Is this chunk acked by a GAP ACK? */ + data_accepted:1, /* At least 1 chunk accepted */ + auth:1, /* IN: was auth'ed | OUT: needs auth */ + has_asconf:1, /* IN: have seen an asconf before */ + tsn_missing_report:2, /* Data chunk missing counter. */ + fast_retransmit:2; /* Is this chunk fast retransmitted? */ +}; + +void sctp_chunk_hold(struct sctp_chunk *); +void sctp_chunk_put(struct sctp_chunk *); +int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, + struct iovec *data); +void sctp_chunk_free(struct sctp_chunk *); +void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); +void *sctp_addto_chunk_fixed(struct sctp_chunk *, int len, const void *data); +struct sctp_chunk *sctp_chunkify(struct sk_buff *, + const struct sctp_association *, + struct sock *); +void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *, + union sctp_addr *); +const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); + +enum { + SCTP_ADDR_NEW, /* new address added to assoc/ep */ + SCTP_ADDR_SRC, /* address can be used as source */ + SCTP_ADDR_DEL, /* address about to be deleted */ +}; + +/* This is a structure for holding either an IPv6 or an IPv4 address. */ +struct sctp_sockaddr_entry { + struct list_head list; + struct rcu_head rcu; + union sctp_addr a; + __u8 state; + __u8 valid; +}; + +typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *); + +/* This structure holds lists of chunks as we are assembling for + * transmission. + */ +struct sctp_packet { + /* These are the SCTP header values (host order) for the packet. */ + __u16 source_port; + __u16 destination_port; + __u32 vtag; + + /* This contains the payload chunks. */ + struct list_head chunk_list; + + /* This is the overhead of the sctp and ip headers. */ + size_t overhead; + /* This is the total size of all chunks INCLUDING padding. */ + size_t size; + + /* The packet is destined for this transport address. + * The function we finally use to pass down to the next lower + * layer lives in the transport structure. + */ + struct sctp_transport *transport; + + /* pointer to the auth chunk for this packet */ + struct sctp_chunk *auth; + + u8 has_cookie_echo:1, /* This packet contains a COOKIE-ECHO chunk. */ + has_sack:1, /* This packet contains a SACK chunk. */ + has_auth:1, /* This packet contains an AUTH chunk */ + has_data:1, /* This packet contains at least 1 DATA chunk */ + ipfragok:1, /* So let ip fragment this packet */ + malloced:1; /* Is it malloced? */ +}; + +struct sctp_packet *sctp_packet_init(struct sctp_packet *, + struct sctp_transport *, + __u16 sport, __u16 dport); +struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int); +sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *, + struct sctp_chunk *, int); +sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *, + struct sctp_chunk *); +int sctp_packet_transmit(struct sctp_packet *); +void sctp_packet_free(struct sctp_packet *); + +static inline int sctp_packet_empty(struct sctp_packet *packet) +{ + return (packet->size == packet->overhead); +} + +/* This represents a remote transport address. + * For local transport addresses, we just use union sctp_addr. + * + * RFC2960 Section 1.4 Key Terms + * + * o Transport address: A Transport Address is traditionally defined + * by Network Layer address, Transport Layer protocol and Transport + * Layer port number. In the case of SCTP running over IP, a + * transport address is defined by the combination of an IP address + * and an SCTP port number (where SCTP is the Transport protocol). + * + * RFC2960 Section 7.1 SCTP Differences from TCP Congestion control + * + * o The sender keeps a separate congestion control parameter set for + * each of the destination addresses it can send to (not each + * source-destination pair but for each destination). The parameters + * should decay if the address is not used for a long enough time + * period. + * + */ +struct sctp_transport { + /* A list of transports. */ + struct list_head transports; + + /* Reference counting. */ + atomic_t refcnt; + __u32 dead:1, + /* RTO-Pending : A flag used to track if one of the DATA + * chunks sent to this address is currently being + * used to compute a RTT. If this flag is 0, + * the next DATA chunk sent to this destination + * should be used to compute a RTT and this flag + * should be set. Every time the RTT + * calculation completes (i.e. the DATA chunk + * is SACK'd) clear this flag. + */ + rto_pending:1, + + /* + * hb_sent : a flag that signals that we have a pending + * heartbeat. + */ + hb_sent:1, + + /* Is the Path MTU update pending on this tranport */ + pmtu_pending:1, + + /* Is this structure kfree()able? */ + malloced:1; + + + /* This is the peer's IP address and port. */ + union sctp_addr ipaddr; + + /* These are the functions we call to handle LLP stuff. */ + struct sctp_af *af_specific; + + /* Which association do we belong to? */ + struct sctp_association *asoc; + + /* RFC2960 + * + * 12.3 Per Transport Address Data + * + * For each destination transport address in the peer's + * address list derived from the INIT or INIT ACK chunk, a + * number of data elements needs to be maintained including: + */ + /* RTO : The current retransmission timeout value. */ + unsigned long rto; + + __u32 rtt; /* This is the most recent RTT. */ + + /* RTTVAR : The current RTT variation. */ + __u32 rttvar; + + /* SRTT : The current smoothed round trip time. */ + __u32 srtt; + + /* + * These are the congestion stats. + */ + /* cwnd : The current congestion window. */ + __u32 cwnd; /* This is the actual cwnd. */ + + /* ssthresh : The current slow start threshold value. */ + __u32 ssthresh; + + /* partial : The tracking method for increase of cwnd when in + * bytes acked : congestion avoidance mode (see Section 6.2.2) + */ + __u32 partial_bytes_acked; + + /* Data that has been sent, but not acknowledged. */ + __u32 flight_size; + + __u32 burst_limited; /* Holds old cwnd when max.burst is applied */ + + /* Destination */ + struct dst_entry *dst; + /* Source address. */ + union sctp_addr saddr; + + /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to + * the destination address every heartbeat interval. + */ + unsigned long hbinterval; + + /* SACK delay timeout */ + unsigned long sackdelay; + __u32 sackfreq; + + /* When was the last time (in jiffies) that we heard from this + * transport? We use this to pick new active and retran paths. + */ + unsigned long last_time_heard; + + /* Last time(in jiffies) when cwnd is reduced due to the congestion + * indication based on ECNE chunk. + */ + unsigned long last_time_ecne_reduced; + + /* This is the max_retrans value for the transport and will + * be initialized from the assocs value. This can be changed + * using SCTP_SET_PEER_ADDR_PARAMS socket option. + */ + __u16 pathmaxrxt; + + /* PMTU : The current known path MTU. */ + __u32 pathmtu; + + /* Flags controlling Heartbeat, SACK delay, and Path MTU Discovery. */ + __u32 param_flags; + + /* The number of times INIT has been sent on this transport. */ + int init_sent_count; + + /* state : The current state of this destination, + * : i.e. SCTP_ACTIVE, SCTP_INACTIVE, SCTP_UNKNOWN. + */ + int state; + + /* These are the error stats for this destination. */ + + /* Error count : The current error count for this destination. */ + unsigned short error_count; + + /* Per : A timer used by each destination. + * Destination : + * Timer : + * + * [Everywhere else in the text this is called T3-rtx. -ed] + */ + struct timer_list T3_rtx_timer; + + /* Heartbeat timer is per destination. */ + struct timer_list hb_timer; + + /* Timer to handle ICMP proto unreachable envets */ + struct timer_list proto_unreach_timer; + + /* Since we're using per-destination retransmission timers + * (see above), we're also using per-destination "transmitted" + * queues. This probably ought to be a private struct + * accessible only within the outqueue, but it's not, yet. + */ + struct list_head transmitted; + + /* We build bundle-able packets for this transport here. */ + struct sctp_packet packet; + + /* This is the list of transports that have chunks to send. */ + struct list_head send_ready; + + /* State information saved for SFR_CACC algorithm. The key + * idea in SFR_CACC is to maintain state at the sender on a + * per-destination basis when a changeover happens. + * char changeover_active; + * char cycling_changeover; + * __u32 next_tsn_at_change; + * char cacc_saw_newack; + */ + struct { + /* An unsigned integer, which stores the next TSN to be + * used by the sender, at the moment of changeover. + */ + __u32 next_tsn_at_change; + + /* A flag which indicates the occurrence of a changeover */ + char changeover_active; + + /* A flag which indicates whether the change of primary is + * the first switch to this destination address during an + * active switch. + */ + char cycling_changeover; + + /* A temporary flag, which is used during the processing of + * a SACK to estimate the causative TSN(s)'s group. + */ + char cacc_saw_newack; + } cacc; + + /* 64-bit random number sent with heartbeat. */ + __u64 hb_nonce; +}; + +struct sctp_transport *sctp_transport_new(const union sctp_addr *, + gfp_t); +void sctp_transport_set_owner(struct sctp_transport *, + struct sctp_association *); +void sctp_transport_route(struct sctp_transport *, union sctp_addr *, + struct sctp_sock *); +void sctp_transport_pmtu(struct sctp_transport *); +void sctp_transport_free(struct sctp_transport *); +void sctp_transport_reset_timers(struct sctp_transport *); +void sctp_transport_hold(struct sctp_transport *); +void sctp_transport_put(struct sctp_transport *); +void sctp_transport_update_rto(struct sctp_transport *, __u32); +void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32); +void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t); +void sctp_transport_burst_limited(struct sctp_transport *); +void sctp_transport_burst_reset(struct sctp_transport *); +unsigned long sctp_transport_timeout(struct sctp_transport *); +void sctp_transport_reset(struct sctp_transport *); +void sctp_transport_update_pmtu(struct sctp_transport *, u32); + + +/* This is the structure we use to queue packets as they come into + * SCTP. We write packets to it and read chunks from it. + */ +struct sctp_inq { + /* This is actually a queue of sctp_chunk each + * containing a partially decoded packet. + */ + struct list_head in_chunk_list; + /* This is the packet which is currently off the in queue and is + * being worked on through the inbound chunk processing. + */ + struct sctp_chunk *in_progress; + + /* This is the delayed task to finish delivering inbound + * messages. + */ + struct work_struct immediate; + + int malloced; /* Is this structure kfree()able? */ +}; + +void sctp_inq_init(struct sctp_inq *); +void sctp_inq_free(struct sctp_inq *); +void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); +struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); +struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *); +void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); + +/* This is the structure we use to hold outbound chunks. You push + * chunks in and they automatically pop out the other end as bundled + * packets (it calls (*output_handler)()). + * + * This structure covers sections 6.3, 6.4, 6.7, 6.8, 6.10, 7., 8.1, + * and 8.2 of the v13 draft. + * + * It handles retransmissions. The connection to the timeout portion + * of the state machine is through sctp_..._timeout() and timeout_handler. + * + * If you feed it SACKs, it will eat them. + * + * If you give it big chunks, it will fragment them. + * + * It assigns TSN's to data chunks. This happens at the last possible + * instant before transmission. + * + * When free()'d, it empties itself out via output_handler(). + */ +struct sctp_outq { + struct sctp_association *asoc; + + /* Data pending that has never been transmitted. */ + struct list_head out_chunk_list; + + unsigned out_qlen; /* Total length of queued data chunks. */ + + /* Error of send failed, may used in SCTP_SEND_FAILED event. */ + unsigned error; + + /* These are control chunks we want to send. */ + struct list_head control_chunk_list; + + /* These are chunks that have been sacked but are above the + * CTSN, or cumulative tsn ack point. + */ + struct list_head sacked; + + /* Put chunks on this list to schedule them for + * retransmission. + */ + struct list_head retransmit; + + /* Put chunks on this list to save them for FWD TSN processing as + * they were abandoned. + */ + struct list_head abandoned; + + /* How many unackd bytes do we have in-flight? */ + __u32 outstanding_bytes; + + /* Are we doing fast-rtx on this queue */ + char fast_rtx; + + /* Corked? */ + char cork; + + /* Is this structure empty? */ + char empty; + + /* Are we kfree()able? */ + char malloced; +}; + +void sctp_outq_init(struct sctp_association *, struct sctp_outq *); +void sctp_outq_teardown(struct sctp_outq *); +void sctp_outq_free(struct sctp_outq*); +int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk); +int sctp_outq_sack(struct sctp_outq *, struct sctp_sackhdr *); +int sctp_outq_is_empty(const struct sctp_outq *); +void sctp_outq_restart(struct sctp_outq *); + +void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, + sctp_retransmit_reason_t); +void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); +int sctp_outq_uncork(struct sctp_outq *); +/* Uncork and flush an outqueue. */ +static inline void sctp_outq_cork(struct sctp_outq *q) +{ + q->cork = 1; +} + +/* These bind address data fields common between endpoints and associations */ +struct sctp_bind_addr { + + /* RFC 2960 12.1 Parameters necessary for the SCTP instance + * + * SCTP Port: The local SCTP port number the endpoint is + * bound to. + */ + __u16 port; + + /* RFC 2960 12.1 Parameters necessary for the SCTP instance + * + * Address List: The list of IP addresses that this instance + * has bound. This information is passed to one's + * peer(s) in INIT and INIT ACK chunks. + */ + struct list_head address_list; + + int malloced; /* Are we kfree()able? */ +}; + +void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port); +void sctp_bind_addr_free(struct sctp_bind_addr *); +int sctp_bind_addr_copy(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, + sctp_scope_t scope, gfp_t gfp, + int flags); +int sctp_bind_addr_dup(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, + gfp_t gfp); +int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, + __u8 addr_state, gfp_t gfp); +int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); +int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, + struct sctp_sock *); +int sctp_bind_addr_conflict(struct sctp_bind_addr *, const union sctp_addr *, + struct sctp_sock *, struct sctp_sock *); +int sctp_bind_addr_state(const struct sctp_bind_addr *bp, + const union sctp_addr *addr); +union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, + const union sctp_addr *addrs, + int addrcnt, + struct sctp_sock *opt); +union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, + int *addrs_len, + gfp_t gfp); +int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len, + __u16 port, gfp_t gfp); + +sctp_scope_t sctp_scope(const union sctp_addr *); +int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope); +int sctp_is_any(struct sock *sk, const union sctp_addr *addr); +int sctp_addr_is_valid(const union sctp_addr *addr); + + +/* What type of endpoint? */ +typedef enum { + SCTP_EP_TYPE_SOCKET, + SCTP_EP_TYPE_ASSOCIATION, +} sctp_endpoint_type_t; + +/* + * A common base class to bridge the implmentation view of a + * socket (usually listening) endpoint versus an association's + * local endpoint. + * This common structure is useful for several purposes: + * 1) Common interface for lookup routines. + * a) Subfunctions work for either endpoint or association + * b) Single interface to lookup allows hiding the lookup lock rather + * than acquiring it externally. + * 2) Common interface for the inbound chunk handling/state machine. + * 3) Common object handling routines for reference counting, etc. + * 4) Disentangle association lookup from endpoint lookup, where we + * do not have to find our endpoint to find our association. + * + */ + +struct sctp_ep_common { + /* Fields to help us manage our entries in the hash tables. */ + struct hlist_node node; + int hashent; + + /* Runtime type information. What kind of endpoint is this? */ + sctp_endpoint_type_t type; + + /* Some fields to help us manage this object. + * refcnt - Reference count access to this object. + * dead - Do not attempt to use this object. + * malloced - Do we need to kfree this object? + */ + atomic_t refcnt; + char dead; + char malloced; + + /* What socket does this endpoint belong to? */ + struct sock *sk; + + /* This is where we receive inbound chunks. */ + struct sctp_inq inqueue; + + /* This substructure includes the defining parameters of the + * endpoint: + * bind_addr.port is our shared port number. + * bind_addr.address_list is our set of local IP addresses. + */ + struct sctp_bind_addr bind_addr; +}; + + +/* RFC Section 1.4 Key Terms + * + * o SCTP endpoint: The logical sender/receiver of SCTP packets. On a + * multi-homed host, an SCTP endpoint is represented to its peers as a + * combination of a set of eligible destination transport addresses to + * which SCTP packets can be sent and a set of eligible source + * transport addresses from which SCTP packets can be received. + * All transport addresses used by an SCTP endpoint must use the + * same port number, but can use multiple IP addresses. A transport + * address used by an SCTP endpoint must not be used by another + * SCTP endpoint. In other words, a transport address is unique + * to an SCTP endpoint. + * + * From an implementation perspective, each socket has one of these. + * A TCP-style socket will have exactly one association on one of + * these. An UDP-style socket will have multiple associations hanging + * off one of these. + */ + +struct sctp_endpoint { + /* Common substructure for endpoint and association. */ + struct sctp_ep_common base; + + /* Associations: A list of current associations and mappings + * to the data consumers for each association. This + * may be in the form of a hash table or other + * implementation dependent structure. The data + * consumers may be process identification + * information such as file descriptors, named pipe + * pointer, or table pointers dependent on how SCTP + * is implemented. + */ + /* This is really a list of struct sctp_association entries. */ + struct list_head asocs; + + /* Secret Key: A secret key used by this endpoint to compute + * the MAC. This SHOULD be a cryptographic quality + * random number with a sufficient length. + * Discussion in [RFC1750] can be helpful in + * selection of the key. + */ + __u8 secret_key[SCTP_HOW_MANY_SECRETS][SCTP_SECRET_SIZE]; + int current_key; + int last_key; + int key_changed_at; + + /* digest: This is a digest of the sctp cookie. This field is + * only used on the receive path when we try to validate + * that the cookie has not been tampered with. We put + * this here so we pre-allocate this once and can re-use + * on every receive. + */ + __u8 *digest; + + /* sendbuf acct. policy. */ + __u32 sndbuf_policy; + + /* rcvbuf acct. policy. */ + __u32 rcvbuf_policy; + + /* SCTP AUTH: array of the HMACs that will be allocated + * we need this per association so that we don't serialize + */ + struct crypto_hash **auth_hmacs; + + /* SCTP-AUTH: hmacs for the endpoint encoded into parameter */ + struct sctp_hmac_algo_param *auth_hmacs_list; + + /* SCTP-AUTH: chunks to authenticate encoded into parameter */ + struct sctp_chunks_param *auth_chunk_list; + + /* SCTP-AUTH: endpoint shared keys */ + struct list_head endpoint_shared_keys; + __u16 active_key_id; +}; + +/* Recover the outter endpoint structure. */ +static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base) +{ + struct sctp_endpoint *ep; + + ep = container_of(base, struct sctp_endpoint, base); + return ep; +} + +/* These are function signatures for manipulating endpoints. */ +struct sctp_endpoint *sctp_endpoint_new(struct sock *, gfp_t); +void sctp_endpoint_free(struct sctp_endpoint *); +void sctp_endpoint_put(struct sctp_endpoint *); +void sctp_endpoint_hold(struct sctp_endpoint *); +void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *); +struct sctp_association *sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, + const union sctp_addr *paddr, + struct sctp_transport **); +int sctp_endpoint_is_peeled_off(struct sctp_endpoint *, + const union sctp_addr *); +struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *, + const union sctp_addr *); +int sctp_has_association(const union sctp_addr *laddr, + const union sctp_addr *paddr); + +int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t, + sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk, + struct sctp_chunk **err_chunk); +int sctp_process_init(struct sctp_association *, sctp_cid_t cid, + const union sctp_addr *peer, + sctp_init_chunk_t *init, gfp_t gfp); +__u32 sctp_generate_tag(const struct sctp_endpoint *); +__u32 sctp_generate_tsn(const struct sctp_endpoint *); + +struct sctp_inithdr_host { + __u32 init_tag; + __u32 a_rwnd; + __u16 num_outbound_streams; + __u16 num_inbound_streams; + __u32 initial_tsn; +}; + +/* RFC2960 + * + * 12. Recommended Transmission Control Block (TCB) Parameters + * + * This section details a recommended set of parameters that should + * be contained within the TCB for an implementation. This section is + * for illustrative purposes and should not be deemed as requirements + * on an implementation or as an exhaustive list of all parameters + * inside an SCTP TCB. Each implementation may need its own additional + * parameters for optimization. + */ + + +/* Here we have information about each individual association. */ +struct sctp_association { + + /* A base structure common to endpoint and association. + * In this context, it represents the associations's view + * of the local endpoint of the association. + */ + struct sctp_ep_common base; + + /* Associations on the same socket. */ + struct list_head asocs; + + /* association id. */ + sctp_assoc_t assoc_id; + + /* This is our parent endpoint. */ + struct sctp_endpoint *ep; + + /* These are those association elements needed in the cookie. */ + struct sctp_cookie c; + + /* This is all information about our peer. */ + struct { + /* rwnd + * + * Peer Rwnd : Current calculated value of the peer's rwnd. + */ + __u32 rwnd; + + /* transport_addr_list + * + * Peer : A list of SCTP transport addresses that the + * Transport : peer is bound to. This information is derived + * Address : from the INIT or INIT ACK and is used to + * List : associate an inbound packet with a given + * : association. Normally this information is + * : hashed or keyed for quick lookup and access + * : of the TCB. + * : The list is also initialized with the list + * : of addresses passed with the sctp_connectx() + * : call. + * + * It is a list of SCTP_transport's. + */ + struct list_head transport_addr_list; + + /* transport_count + * + * Peer : A count of the number of peer addresses + * Transport : in the Peer Transport Address List. + * Address : + * Count : + */ + __u16 transport_count; + + /* port + * The transport layer port number. + */ + __u16 port; + + /* primary_path + * + * Primary : This is the current primary destination + * Path : transport address of the peer endpoint. It + * : may also specify a source transport address + * : on this endpoint. + * + * All of these paths live on transport_addr_list. + * + * At the bakeoffs, we discovered that the intent of + * primaryPath is that it only changes when the ULP + * asks to have it changed. We add the activePath to + * designate the connection we are currently using to + * transmit new data and most control chunks. + */ + struct sctp_transport *primary_path; + + /* Cache the primary path address here, when we + * need a an address for msg_name. + */ + union sctp_addr primary_addr; + + /* active_path + * The path that we are currently using to + * transmit new data and most control chunks. + */ + struct sctp_transport *active_path; + + /* retran_path + * + * RFC2960 6.4 Multi-homed SCTP Endpoints + * ... + * Furthermore, when its peer is multi-homed, an + * endpoint SHOULD try to retransmit a chunk to an + * active destination transport address that is + * different from the last destination address to + * which the DATA chunk was sent. + */ + struct sctp_transport *retran_path; + + /* Pointer to last transport I have sent on. */ + struct sctp_transport *last_sent_to; + + /* This is the last transport I have received DATA on. */ + struct sctp_transport *last_data_from; + + /* + * Mapping An array of bits or bytes indicating which out of + * Array order TSN's have been received (relative to the + * Last Rcvd TSN). If no gaps exist, i.e. no out of + * order packets have been received, this array + * will be set to all zero. This structure may be + * in the form of a circular buffer or bit array. + * + * Last Rcvd : This is the last TSN received in + * TSN : sequence. This value is set initially by + * : taking the peer's Initial TSN, received in + * : the INIT or INIT ACK chunk, and subtracting + * : one from it. + * + * Throughout most of the specification this is called the + * "Cumulative TSN ACK Point". In this case, we + * ignore the advice in 12.2 in favour of the term + * used in the bulk of the text. This value is hidden + * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn(). + */ + struct sctp_tsnmap tsn_map; + + /* Ack State : This flag indicates if the next received + * : packet is to be responded to with a + * : SACK. This is initializedto 0. When a packet + * : is received it is incremented. If this value + * : reaches 2 or more, a SACK is sent and the + * : value is reset to 0. Note: This is used only + * : when no DATA chunks are received out of + * : order. When DATA chunks are out of order, + * : SACK's are not delayed (see Section 6). + */ + __u8 sack_needed; /* Do we need to sack the peer? */ + __u32 sack_cnt; + + /* These are capabilities which our peer advertised. */ + __u8 ecn_capable:1, /* Can peer do ECN? */ + ipv4_address:1, /* Peer understands IPv4 addresses? */ + ipv6_address:1, /* Peer understands IPv6 addresses? */ + hostname_address:1, /* Peer understands DNS addresses? */ + asconf_capable:1, /* Does peer support ADDIP? */ + prsctp_capable:1, /* Can peer do PR-SCTP? */ + auth_capable:1; /* Is peer doing SCTP-AUTH? */ + + __u32 adaptation_ind; /* Adaptation Code point. */ + + /* This mask is used to disable sending the ASCONF chunk + * with specified parameter to peer. + */ + __be16 addip_disabled_mask; + + struct sctp_inithdr_host i; + int cookie_len; + void *cookie; + + /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. + * C1) ... "Peer-Serial-Number'. This value MUST be initialized to the + * Initial TSN Value minus 1 + */ + __u32 addip_serial; + + /* SCTP-AUTH: We need to know pears random number, hmac list + * and authenticated chunk list. All that is part of the + * cookie and these are just pointers to those locations + */ + sctp_random_param_t *peer_random; + sctp_chunks_param_t *peer_chunks; + sctp_hmac_algo_param_t *peer_hmacs; + } peer; + + /* State : A state variable indicating what state the + * : association is in, i.e. COOKIE-WAIT, + * : COOKIE-ECHOED, ESTABLISHED, SHUTDOWN-PENDING, + * : SHUTDOWN-SENT, SHUTDOWN-RECEIVED, SHUTDOWN-ACK-SENT. + * + * Note: No "CLOSED" state is illustrated since if a + * association is "CLOSED" its TCB SHOULD be removed. + * + * In this implementation we DO have a CLOSED + * state which is used during initiation and shutdown. + * + * State takes values from SCTP_STATE_*. + */ + sctp_state_t state; + + /* The cookie life I award for any cookie. */ + struct timeval cookie_life; + + /* Overall : The overall association error count. + * Error Count : [Clear this any time I get something.] + */ + int overall_error_count; + + /* These are the association's initial, max, and min RTO values. + * These values will be initialized by system defaults, but can + * be modified via the SCTP_RTOINFO socket option. + */ + unsigned long rto_initial; + unsigned long rto_max; + unsigned long rto_min; + + /* Maximum number of new data packets that can be sent in a burst. */ + int max_burst; + + /* This is the max_retrans value for the association. This value will + * be initialized initialized from system defaults, but can be + * modified by the SCTP_ASSOCINFO socket option. + */ + int max_retrans; + + /* Maximum number of times the endpoint will retransmit INIT */ + __u16 max_init_attempts; + + /* How many times have we resent an INIT? */ + __u16 init_retries; + + /* The largest timeout or RTO value to use in attempting an INIT */ + unsigned long max_init_timeo; + + /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to + * the destination address every heartbeat interval. This value + * will be inherited by all new transports. + */ + unsigned long hbinterval; + + /* This is the max_retrans value for new transports in the + * association. + */ + __u16 pathmaxrxt; + + /* Flag that path mtu update is pending */ + __u8 pmtu_pending; + + /* Association : The smallest PMTU discovered for all of the + * PMTU : peer's transport addresses. + */ + __u32 pathmtu; + + /* Flags controlling Heartbeat, SACK delay, and Path MTU Discovery. */ + __u32 param_flags; + + /* SACK delay timeout */ + unsigned long sackdelay; + __u32 sackfreq; + + + unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES]; + struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; + + /* Transport to which SHUTDOWN chunk was last sent. */ + struct sctp_transport *shutdown_last_sent_to; + + /* How many times have we resent a SHUTDOWN */ + int shutdown_retries; + + /* Transport to which INIT chunk was last sent. */ + struct sctp_transport *init_last_sent_to; + + /* Next TSN : The next TSN number to be assigned to a new + * : DATA chunk. This is sent in the INIT or INIT + * : ACK chunk to the peer and incremented each + * : time a DATA chunk is assigned a TSN + * : (normally just prior to transmit or during + * : fragmentation). + */ + __u32 next_tsn; + + /* + * Last Rcvd : This is the last TSN received in sequence. This value + * TSN : is set initially by taking the peer's Initial TSN, + * : received in the INIT or INIT ACK chunk, and + * : subtracting one from it. + * + * Most of RFC 2960 refers to this as the Cumulative TSN Ack Point. + */ + + __u32 ctsn_ack_point; + + /* PR-SCTP Advanced.Peer.Ack.Point */ + __u32 adv_peer_ack_point; + + /* Highest TSN that is acknowledged by incoming SACKs. */ + __u32 highest_sacked; + + /* TSN marking the fast recovery exit point */ + __u32 fast_recovery_exit; + + /* Flag to track the current fast recovery state */ + __u8 fast_recovery; + + /* The number of unacknowledged data chunks. Reported through + * the SCTP_STATUS sockopt. + */ + __u16 unack_data; + + /* The total number of data chunks that we've had to retransmit + * as the result of a T3 timer expiration + */ + __u32 rtx_data_chunks; + + /* This is the association's receive buffer space. This value is used + * to set a_rwnd field in an INIT or a SACK chunk. + */ + __u32 rwnd; + + /* This is the last advertised value of rwnd over a SACK chunk. */ + __u32 a_rwnd; + + /* Number of bytes by which the rwnd has slopped. The rwnd is allowed + * to slop over a maximum of the association's frag_point. + */ + __u32 rwnd_over; + + /* Keeps treack of rwnd pressure. This happens when we have + * a window, but not recevie buffer (i.e small packets). This one + * is releases slowly (1 PMTU at a time ). + */ + __u32 rwnd_press; + + /* This is the sndbuf size in use for the association. + * This corresponds to the sndbuf size for the association, + * as specified in the sk->sndbuf. + */ + int sndbuf_used; + + /* This is the amount of memory that this association has allocated + * in the receive path at any given time. + */ + atomic_t rmem_alloc; + + /* This is the wait queue head for send requests waiting on + * the association sndbuf space. + */ + wait_queue_head_t wait; + + /* The message size at which SCTP fragmentation will occur. */ + __u32 frag_point; + __u32 user_frag; + + /* Counter used to count INIT errors. */ + int init_err_counter; + + /* Count the number of INIT cycles (for doubling timeout). */ + int init_cycle; + + /* Default send parameters. */ + __u16 default_stream; + __u16 default_flags; + __u32 default_ppid; + __u32 default_context; + __u32 default_timetolive; + + /* Default receive parameters */ + __u32 default_rcv_context; + + /* This tracks outbound ssn for a given stream. */ + struct sctp_ssnmap *ssnmap; + + /* All outbound chunks go through this structure. */ + struct sctp_outq outqueue; + + /* A smart pipe that will handle reordering and fragmentation, + * as well as handle passing events up to the ULP. + */ + struct sctp_ulpq ulpq; + + /* Last TSN that caused an ECNE Chunk to be sent. */ + __u32 last_ecne_tsn; + + /* Last TSN that caused a CWR Chunk to be sent. */ + __u32 last_cwr_tsn; + + /* How many duplicated TSNs have we seen? */ + int numduptsns; + + /* Number of seconds of idle time before an association is closed. + * In the association context, this is really used as a boolean + * since the real timeout is stored in the timeouts array + */ + __u32 autoclose; + + /* These are to support + * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses + * and Enforcement of Flow and Message Limits" + * <draft-ietf-tsvwg-addip-sctp-02.txt> + * or "ADDIP" for short. + */ + + + + /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks + * + * R1) One and only one ASCONF Chunk MAY be in transit and + * unacknowledged at any one time. If a sender, after sending + * an ASCONF chunk, decides it needs to transfer another + * ASCONF Chunk, it MUST wait until the ASCONF-ACK Chunk + * returns from the previous ASCONF Chunk before sending a + * subsequent ASCONF. Note this restriction binds each side, + * so at any time two ASCONF may be in-transit on any given + * association (one sent from each endpoint). + * + * [This is our one-and-only-one ASCONF in flight. If we do + * not have an ASCONF in flight, this is NULL.] + */ + struct sctp_chunk *addip_last_asconf; + + /* ADDIP Section 5.2 Upon reception of an ASCONF Chunk. + * + * This is needed to implement itmes E1 - E4 of the updated + * spec. Here is the justification: + * + * Since the peer may bundle multiple ASCONF chunks toward us, + * we now need the ability to cache multiple ACKs. The section + * describes in detail how they are cached and cleaned up. + */ + struct list_head asconf_ack_list; + + /* These ASCONF chunks are waiting to be sent. + * + * These chunaks can't be pushed to outqueue until receiving + * ASCONF_ACK for the previous ASCONF indicated by + * addip_last_asconf, so as to guarantee that only one ASCONF + * is in flight at any time. + * + * ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks + * + * In defining the ASCONF Chunk transfer procedures, it is + * essential that these transfers MUST NOT cause congestion + * within the network. To achieve this, we place these + * restrictions on the transfer of ASCONF Chunks: + * + * R1) One and only one ASCONF Chunk MAY be in transit and + * unacknowledged at any one time. If a sender, after sending + * an ASCONF chunk, decides it needs to transfer another + * ASCONF Chunk, it MUST wait until the ASCONF-ACK Chunk + * returns from the previous ASCONF Chunk before sending a + * subsequent ASCONF. Note this restriction binds each side, + * so at any time two ASCONF may be in-transit on any given + * association (one sent from each endpoint). + * + * + * [I really think this is EXACTLY the sort of intelligence + * which already resides in sctp_outq. Please move this + * queue and its supporting logic down there. --piggy] + */ + struct list_head addip_chunk_list; + + /* ADDIP Section 4.1 ASCONF Chunk Procedures + * + * A2) A serial number should be assigned to the Chunk. The + * serial number SHOULD be a monotonically increasing + * number. The serial number SHOULD be initialized at + * the start of the association to the same value as the + * Initial TSN and every time a new ASCONF chunk is created + * it is incremented by one after assigning the serial number + * to the newly created chunk. + * + * ADDIP + * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) + * + * Serial Number : 32 bits (unsigned integer) + * + * This value represents a Serial Number for the ASCONF + * Chunk. The valid range of Serial Number is from 0 to + * 4294967295 (2^32 - 1). Serial Numbers wrap back to 0 + * after reaching 4294967295. + */ + __u32 addip_serial; + + /* SCTP AUTH: list of the endpoint shared keys. These + * keys are provided out of band by the user applicaton + * and can't change during the lifetime of the association + */ + struct list_head endpoint_shared_keys; + + /* SCTP AUTH: + * The current generated assocaition shared key (secret) + */ + struct sctp_auth_bytes *asoc_shared_key; + + /* SCTP AUTH: hmac id of the first peer requested algorithm + * that we support. + */ + __u16 default_hmac_id; + + __u16 active_key_id; + + __u8 need_ecne:1, /* Need to send an ECNE Chunk? */ + temp:1; /* Is it a temporary association? */ +}; + + +/* An eyecatcher for determining if we are really looking at an + * association data structure. + */ +enum { + SCTP_ASSOC_EYECATCHER = 0xa550c123, +}; + +/* Recover the outter association structure. */ +static inline struct sctp_association *sctp_assoc(struct sctp_ep_common *base) +{ + struct sctp_association *asoc; + + asoc = container_of(base, struct sctp_association, base); + return asoc; +} + +/* These are function signatures for manipulating associations. */ + + +struct sctp_association * +sctp_association_new(const struct sctp_endpoint *, const struct sock *, + sctp_scope_t scope, gfp_t gfp); +void sctp_association_free(struct sctp_association *); +void sctp_association_put(struct sctp_association *); +void sctp_association_hold(struct sctp_association *); + +struct sctp_transport *sctp_assoc_choose_alter_transport( + struct sctp_association *, struct sctp_transport *); +void sctp_assoc_update_retran_path(struct sctp_association *); +struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *, + const union sctp_addr *); +int sctp_assoc_lookup_laddr(struct sctp_association *asoc, + const union sctp_addr *laddr); +struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *, + const union sctp_addr *address, + const gfp_t gfp, + const int peer_state); +void sctp_assoc_del_peer(struct sctp_association *asoc, + const union sctp_addr *addr); +void sctp_assoc_rm_peer(struct sctp_association *asoc, + struct sctp_transport *peer); +void sctp_assoc_control_transport(struct sctp_association *, + struct sctp_transport *, + sctp_transport_cmd_t, sctp_sn_error_t); +struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *, __u32); +struct sctp_transport *sctp_assoc_is_match(struct sctp_association *, + const union sctp_addr *, + const union sctp_addr *); +void sctp_assoc_migrate(struct sctp_association *, struct sock *); +void sctp_assoc_update(struct sctp_association *old, + struct sctp_association *new); + +__u32 sctp_association_get_next_tsn(struct sctp_association *); + +void sctp_assoc_sync_pmtu(struct sctp_association *); +void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned); +void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned); +void sctp_assoc_set_primary(struct sctp_association *, + struct sctp_transport *); +void sctp_assoc_del_nonprimary_peers(struct sctp_association *, + struct sctp_transport *); +int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *, + sctp_scope_t, gfp_t); +int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *, + struct sctp_cookie*, + gfp_t gfp); +int sctp_assoc_set_id(struct sctp_association *, gfp_t); +void sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc); +struct sctp_chunk *sctp_assoc_lookup_asconf_ack( + const struct sctp_association *asoc, + __be32 serial); + + +int sctp_cmp_addr_exact(const union sctp_addr *ss1, + const union sctp_addr *ss2); +struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc); + +/* A convenience structure to parse out SCTP specific CMSGs. */ +typedef struct sctp_cmsgs { + struct sctp_initmsg *init; + struct sctp_sndrcvinfo *info; +} sctp_cmsgs_t; + +/* Structure for tracking memory objects */ +typedef struct { + char *label; + atomic_t *counter; +} sctp_dbg_objcnt_entry_t; + +#endif /* __sctp_structs_h__ */ diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h new file mode 100644 index 00000000..4aabc5a9 --- /dev/null +++ b/include/net/sctp/tsnmap.h @@ -0,0 +1,178 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * These are the definitions needed for the tsnmap type. The tsnmap is used + * to track out of order TSNs received. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm <jgrimm@us.ibm.com> + * La Monte H.P. Yarroll <piggy@acm.org> + * Karl Knutson <karl@athena.chicago.il.us> + * Sridhar Samudrala <sri@us.ibm.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +#include <net/sctp/constants.h> + +#ifndef __sctp_tsnmap_h__ +#define __sctp_tsnmap_h__ + +/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB) + * Mapping An array of bits or bytes indicating which out of + * Array order TSN's have been received (relative to the + * Last Rcvd TSN). If no gaps exist, i.e. no out of + * order packets have been received, this array + * will be set to all zero. This structure may be + * in the form of a circular buffer or bit array. + */ +struct sctp_tsnmap { + /* This array counts the number of chunks with each TSN. + * It points at one of the two buffers with which we will + * ping-pong between. + */ + unsigned long *tsn_map; + + /* This is the TSN at tsn_map[0]. */ + __u32 base_tsn; + + /* Last Rcvd : This is the last TSN received in + * TSN : sequence. This value is set initially by + * : taking the peer's Initial TSN, received in + * : the INIT or INIT ACK chunk, and subtracting + * : one from it. + * + * Throughout most of the specification this is called the + * "Cumulative TSN ACK Point". In this case, we + * ignore the advice in 12.2 in favour of the term + * used in the bulk of the text. + */ + __u32 cumulative_tsn_ack_point; + + /* This is the highest TSN we've marked. */ + __u32 max_tsn_seen; + + /* This is the minimum number of TSNs we can track. This corresponds + * to the size of tsn_map. Note: the overflow_map allows us to + * potentially track more than this quantity. + */ + __u16 len; + + /* Data chunks pending receipt. used by SCTP_STATUS sockopt */ + __u16 pending_data; + + /* Record duplicate TSNs here. We clear this after + * every SACK. Store up to SCTP_MAX_DUP_TSNS worth of + * information. + */ + __u16 num_dup_tsns; + __be32 dup_tsns[SCTP_MAX_DUP_TSNS]; +}; + +struct sctp_tsnmap_iter { + __u32 start; +}; + +/* Initialize a block of memory as a tsnmap. */ +struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *, __u16 len, + __u32 initial_tsn, gfp_t gfp); + +void sctp_tsnmap_free(struct sctp_tsnmap *map); + +/* Test the tracking state of this TSN. + * Returns: + * 0 if the TSN has not yet been seen + * >0 if the TSN has been seen (duplicate) + * <0 if the TSN is invalid (too large to track) + */ +int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn); + +/* Mark this TSN as seen. */ +int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn); + +/* Mark this TSN and all lower as seen. */ +void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn); + +/* Retrieve the Cumulative TSN ACK Point. */ +static inline __u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map) +{ + return map->cumulative_tsn_ack_point; +} + +/* Retrieve the highest TSN we've seen. */ +static inline __u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map) +{ + return map->max_tsn_seen; +} + +/* How many duplicate TSNs are stored? */ +static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map) +{ + return map->num_dup_tsns; +} + +/* Return pointer to duplicate tsn array as needed by SACK. */ +static inline __be32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map) +{ + map->num_dup_tsns = 0; + return map->dup_tsns; +} + +/* How many gap ack blocks do we have recorded? */ +__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map, + struct sctp_gap_ack_block *gabs); + +/* Refresh the count on pending data. */ +__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map); + +/* Is there a gap in the TSN map? */ +static inline int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map) +{ + return (map->cumulative_tsn_ack_point != map->max_tsn_seen); +} + +/* Mark a duplicate TSN. Note: limit the storage of duplicate TSN + * information. + */ +static inline void sctp_tsnmap_mark_dup(struct sctp_tsnmap *map, __u32 tsn) +{ + if (map->num_dup_tsns < SCTP_MAX_DUP_TSNS) + map->dup_tsns[map->num_dup_tsns++] = htonl(tsn); +} + +/* Renege a TSN that was seen. */ +void sctp_tsnmap_renege(struct sctp_tsnmap *, __u32 tsn); + +/* Is there a gap in the TSN map? */ +int sctp_tsnmap_has_gap(const struct sctp_tsnmap *); + +#endif /* __sctp_tsnmap_h__ */ diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h new file mode 100644 index 00000000..7ea12e8e --- /dev/null +++ b/include/net/sctp/ulpevent.h @@ -0,0 +1,168 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * These are the definitions needed for the sctp_ulpevent type. The + * sctp_ulpevent type is used to carry information from the state machine + * upwards to the ULP. + * + * This file is part of the SCTP kernel implementation + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm <jgrimm@us.ibm.com> + * La Monte H.P. Yarroll <piggy@acm.org> + * Karl Knutson <karl@athena.chicago.il.us> + * Sridhar Samudrala <sri@us.ibm.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_ulpevent_h__ +#define __sctp_ulpevent_h__ + +/* A structure to carry information to the ULP (e.g. Sockets API) */ +/* Warning: This sits inside an skb.cb[] area. Be very careful of + * growing this structure as it is at the maximum limit now. + */ +struct sctp_ulpevent { + struct sctp_association *asoc; + __u16 stream; + __u16 ssn; + __u16 flags; + __u32 ppid; + __u32 tsn; + __u32 cumtsn; + int msg_flags; + int iif; + unsigned int rmem_len; +}; + +/* Retrieve the skb this event sits inside of. */ +static inline struct sk_buff *sctp_event2skb(const struct sctp_ulpevent *ev) +{ + return container_of((void *)ev, struct sk_buff, cb); +} + +/* Retrieve & cast the event sitting inside the skb. */ +static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb) +{ + return (struct sctp_ulpevent *)skb->cb; +} + +void sctp_ulpevent_free(struct sctp_ulpevent *); +int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); +void sctp_queue_purge_ulpevents(struct sk_buff_head *list); + +struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( + const struct sctp_association *asoc, + __u16 flags, + __u16 state, + __u16 error, + __u16 outbound, + __u16 inbound, + struct sctp_chunk *chunk, + gfp_t gfp); + +struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( + const struct sctp_association *asoc, + const struct sockaddr_storage *aaddr, + int flags, + int state, + int error, + gfp_t gfp); + +struct sctp_ulpevent *sctp_ulpevent_make_remote_error( + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + __u16 flags, + gfp_t gfp); +struct sctp_ulpevent *sctp_ulpevent_make_send_failed( + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + __u16 flags, + __u32 error, + gfp_t gfp); + +struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( + const struct sctp_association *asoc, + __u16 flags, + gfp_t gfp); + +struct sctp_ulpevent *sctp_ulpevent_make_pdapi( + const struct sctp_association *asoc, + __u32 indication, gfp_t gfp); + +struct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication( + const struct sctp_association *asoc, gfp_t gfp); + +struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, + struct sctp_chunk *chunk, + gfp_t gfp); + +struct sctp_ulpevent *sctp_ulpevent_make_authkey( + const struct sctp_association *asoc, __u16 key_id, + __u32 indication, gfp_t gfp); + +void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, + struct msghdr *); +__u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); + +/* Is this event type enabled? */ +static inline int sctp_ulpevent_type_enabled(__u16 sn_type, + struct sctp_event_subscribe *mask) +{ + char *amask = (char *) mask; + return amask[sn_type - SCTP_SN_TYPE_BASE]; +} + +/* Given an event subscription, is this event enabled? */ +static inline int sctp_ulpevent_is_enabled(const struct sctp_ulpevent *event, + struct sctp_event_subscribe *mask) +{ + __u16 sn_type; + int enabled = 1; + + if (sctp_ulpevent_is_notification(event)) { + sn_type = sctp_ulpevent_get_notification_type(event); + enabled = sctp_ulpevent_type_enabled(sn_type, mask); + } + return enabled; +} + +#endif /* __sctp_ulpevent_h__ */ + + + + + + + diff --git a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h new file mode 100644 index 00000000..2e5ee0d8 --- /dev/null +++ b/include/net/sctp/ulpqueue.h @@ -0,0 +1,94 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * These are the definitions needed for the sctp_ulpq type. The + * sctp_ulpq is the interface between the Upper Layer Protocol, or ULP, + * and the core SCTP state machine. This is the component which handles + * reassembly and ordering. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email addresses: + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm <jgrimm@us.ibm.com> + * La Monte H.P. Yarroll <piggy@acm.org> + * Sridhar Samudrala <sri@us.ibm.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_ulpqueue_h__ +#define __sctp_ulpqueue_h__ + +/* A structure to carry information to the ULP (e.g. Sockets API) */ +struct sctp_ulpq { + char malloced; + char pd_mode; + struct sctp_association *asoc; + struct sk_buff_head reasm; + struct sk_buff_head lobby; +}; + +/* Prototypes. */ +struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, + struct sctp_association *); +void sctp_ulpq_flush(struct sctp_ulpq *ulpq); +void sctp_ulpq_free(struct sctp_ulpq *); + +/* Add a new DATA chunk for processing. */ +int sctp_ulpq_tail_data(struct sctp_ulpq *, struct sctp_chunk *, gfp_t); + +/* Add a new event for propagation to the ULP. */ +int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev); + +/* Renege previously received chunks. */ +void sctp_ulpq_renege(struct sctp_ulpq *, struct sctp_chunk *, gfp_t); + +/* Perform partial delivery. */ +void sctp_ulpq_partial_delivery(struct sctp_ulpq *, struct sctp_chunk *, gfp_t); + +/* Abort the partial delivery. */ +void sctp_ulpq_abort_pd(struct sctp_ulpq *, gfp_t); + +/* Clear the partial data delivery condition on this socket. */ +int sctp_clear_pd(struct sock *sk, struct sctp_association *asoc); + +/* Skip over an SSN. */ +void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn); + +void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *, __u32); +#endif /* __sctp_ulpqueue_h__ */ + + + + + + + diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h new file mode 100644 index 00000000..2b2769c5 --- /dev/null +++ b/include/net/sctp/user.h @@ -0,0 +1,711 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2002 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * This header represents the structures and constants needed to support + * the SCTP Extension to the Sockets API. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers <lksctp-developers@lists.sourceforge.net> + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll <piggy@acm.org> + * R. Stewart <randall@sctp.chicago.il.us> + * K. Morneau <kmorneau@cisco.com> + * Q. Xie <qxie1@email.mot.com> + * Karl Knutson <karl@athena.chicago.il.us> + * Jon Grimm <jgrimm@us.ibm.com> + * Daisy Chang <daisyc@us.ibm.com> + * Ryan Layer <rmlayer@us.ibm.com> + * Ardelle Fan <ardelle.fan@intel.com> + * Sridhar Samudrala <sri@us.ibm.com> + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __net_sctp_user_h__ +#define __net_sctp_user_h__ + +#include <linux/types.h> +#include <linux/socket.h> + +typedef __s32 sctp_assoc_t; + +/* The following symbols come from the Sockets API Extensions for + * SCTP <draft-ietf-tsvwg-sctpsocket-07.txt>. + */ +#define SCTP_RTOINFO 0 +#define SCTP_ASSOCINFO 1 +#define SCTP_INITMSG 2 +#define SCTP_NODELAY 3 /* Get/set nodelay option. */ +#define SCTP_AUTOCLOSE 4 +#define SCTP_SET_PEER_PRIMARY_ADDR 5 +#define SCTP_PRIMARY_ADDR 6 +#define SCTP_ADAPTATION_LAYER 7 +#define SCTP_DISABLE_FRAGMENTS 8 +#define SCTP_PEER_ADDR_PARAMS 9 +#define SCTP_DEFAULT_SEND_PARAM 10 +#define SCTP_EVENTS 11 +#define SCTP_I_WANT_MAPPED_V4_ADDR 12 /* Turn on/off mapped v4 addresses */ +#define SCTP_MAXSEG 13 /* Get/set maximum fragment. */ +#define SCTP_STATUS 14 +#define SCTP_GET_PEER_ADDR_INFO 15 +#define SCTP_DELAYED_ACK_TIME 16 +#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME +#define SCTP_CONTEXT 17 +#define SCTP_FRAGMENT_INTERLEAVE 18 +#define SCTP_PARTIAL_DELIVERY_POINT 19 /* Set/Get partial delivery point */ +#define SCTP_MAX_BURST 20 /* Set/Get max burst */ +#define SCTP_AUTH_CHUNK 21 /* Set only: add a chunk type to authenticate */ +#define SCTP_HMAC_IDENT 22 +#define SCTP_AUTH_KEY 23 +#define SCTP_AUTH_ACTIVE_KEY 24 +#define SCTP_AUTH_DELETE_KEY 25 +#define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */ +#define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */ +#define SCTP_GET_ASSOC_NUMBER 28 /* Read only */ + +/* Internal Socket Options. Some of the sctp library functions are + * implemented using these socket options. + */ +#define SCTP_SOCKOPT_BINDX_ADD 100 /* BINDX requests for adding addrs */ +#define SCTP_SOCKOPT_BINDX_REM 101 /* BINDX requests for removing addrs. */ +#define SCTP_SOCKOPT_PEELOFF 102 /* peel off association. */ +/* Options 104-106 are deprecated and removed. Do not use this space */ +#define SCTP_SOCKOPT_CONNECTX_OLD 107 /* CONNECTX old requests. */ +#define SCTP_GET_PEER_ADDRS 108 /* Get all peer addresss. */ +#define SCTP_GET_LOCAL_ADDRS 109 /* Get all local addresss. */ +#define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ +#define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ + +/* + * 5.2.1 SCTP Initiation Structure (SCTP_INIT) + * + * This cmsghdr structure provides information for initializing new + * SCTP associations with sendmsg(). The SCTP_INITMSG socket option + * uses this same data structure. This structure is not used for + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg + * + */ +struct sctp_initmsg { + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; + __u16 sinit_max_attempts; + __u16 sinit_max_init_timeo; +}; + +/* + * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * This cmsghdr structure specifies SCTP options for sendmsg() and + * describes SCTP header information about a received message through + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo + * + */ +struct sctp_sndrcvinfo { + __u16 sinfo_stream; + __u16 sinfo_ssn; + __u16 sinfo_flags; + __u32 sinfo_ppid; + __u32 sinfo_context; + __u32 sinfo_timetolive; + __u32 sinfo_tsn; + __u32 sinfo_cumtsn; + sctp_assoc_t sinfo_assoc_id; +}; + +/* + * sinfo_flags: 16 bits (unsigned integer) + * + * This field may contain any of the following flags and is composed of + * a bitwise OR of these values. + */ + +enum sctp_sinfo_flags { + SCTP_UNORDERED = 1, /* Send/receive message unordered. */ + SCTP_ADDR_OVER = 2, /* Override the primary destination. */ + SCTP_ABORT=4, /* Send an ABORT message to the peer. */ + SCTP_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */ + SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */ +}; + + +/* These are cmsg_types. */ +typedef enum sctp_cmsg_type { + SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ + SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ +} sctp_cmsg_t; + + +/* + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * Communication notifications inform the ULP that an SCTP association + * has either begun or ended. The identifier for a new association is + * provided by this notificaion. The notification information has the + * following format: + * + */ +struct sctp_assoc_change { + __u16 sac_type; + __u16 sac_flags; + __u32 sac_length; + __u16 sac_state; + __u16 sac_error; + __u16 sac_outbound_streams; + __u16 sac_inbound_streams; + sctp_assoc_t sac_assoc_id; + __u8 sac_info[0]; +}; + +/* + * sac_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the association. They include: + * + * Note: The following state names deviate from the API draft as + * the names clash too easily with other kernel symbols. + */ +enum sctp_sac_state { + SCTP_COMM_UP, + SCTP_COMM_LOST, + SCTP_RESTART, + SCTP_SHUTDOWN_COMP, + SCTP_CANT_STR_ASSOC, +}; + +/* + * 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * When a destination address on a multi-homed peer encounters a change + * an interface details event is sent. The information has the + * following structure: + */ +struct sctp_paddr_change { + __u16 spc_type; + __u16 spc_flags; + __u32 spc_length; + struct sockaddr_storage spc_aaddr; + int spc_state; + int spc_error; + sctp_assoc_t spc_assoc_id; +} __attribute__((packed, aligned(4))); + +/* + * spc_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the address. They include: + */ +enum sctp_spc_state { + SCTP_ADDR_AVAILABLE, + SCTP_ADDR_UNREACHABLE, + SCTP_ADDR_REMOVED, + SCTP_ADDR_ADDED, + SCTP_ADDR_MADE_PRIM, + SCTP_ADDR_CONFIRMED, +}; + + +/* + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * A remote peer may send an Operational Error message to its peer. + * This message indicates a variety of error conditions on an + * association. The entire error TLV as it appears on the wire is + * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP + * specification [SCTP] and any extensions for a list of possible + * error formats. SCTP error TLVs have the format: + */ +struct sctp_remote_error { + __u16 sre_type; + __u16 sre_flags; + __u32 sre_length; + __u16 sre_error; + sctp_assoc_t sre_assoc_id; + __u8 sre_data[0]; +}; + + +/* + * 5.3.1.4 SCTP_SEND_FAILED + * + * If SCTP cannot deliver a message it may return the message as a + * notification. + */ +struct sctp_send_failed { + __u16 ssf_type; + __u16 ssf_flags; + __u32 ssf_length; + __u32 ssf_error; + struct sctp_sndrcvinfo ssf_info; + sctp_assoc_t ssf_assoc_id; + __u8 ssf_data[0]; +}; + +/* + * ssf_flags: 16 bits (unsigned integer) + * + * The flag value will take one of the following values + * + * SCTP_DATA_UNSENT - Indicates that the data was never put on + * the wire. + * + * SCTP_DATA_SENT - Indicates that the data was put on the wire. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. + */ +enum sctp_ssf_flags { + SCTP_DATA_UNSENT, + SCTP_DATA_SENT, +}; + +/* + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * When a peer sends a SHUTDOWN, SCTP delivers this notification to + * inform the application that it should cease sending data. + */ +struct sctp_shutdown_event { + __u16 sse_type; + __u16 sse_flags; + __u32 sse_length; + sctp_assoc_t sse_assoc_id; +}; + +/* + * 5.3.1.6 SCTP_ADAPTATION_INDICATION + * + * When a peer sends a Adaptation Layer Indication parameter , SCTP + * delivers this notification to inform the application + * that of the peers requested adaptation layer. + */ +struct sctp_adaptation_event { + __u16 sai_type; + __u16 sai_flags; + __u32 sai_length; + __u32 sai_adaptation_ind; + sctp_assoc_t sai_assoc_id; +}; + +/* + * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT + * + * When a receiver is engaged in a partial delivery of a + * message this notification will be used to indicate + * various events. + */ +struct sctp_pdapi_event { + __u16 pdapi_type; + __u16 pdapi_flags; + __u32 pdapi_length; + __u32 pdapi_indication; + sctp_assoc_t pdapi_assoc_id; +}; + +enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; + +struct sctp_authkey_event { + __u16 auth_type; + __u16 auth_flags; + __u32 auth_length; + __u16 auth_keynumber; + __u16 auth_altkeynumber; + __u32 auth_indication; + sctp_assoc_t auth_assoc_id; +}; + +enum { SCTP_AUTH_NEWKEY = 0, }; + + +/* + * Described in Section 7.3 + * Ancillary Data and Notification Interest Options + */ +struct sctp_event_subscribe { + __u8 sctp_data_io_event; + __u8 sctp_association_event; + __u8 sctp_address_event; + __u8 sctp_send_failure_event; + __u8 sctp_peer_error_event; + __u8 sctp_shutdown_event; + __u8 sctp_partial_delivery_event; + __u8 sctp_adaptation_layer_event; + __u8 sctp_authentication_event; +}; + +/* + * 5.3.1 SCTP Notification Structure + * + * The notification structure is defined as the union of all + * notification types. + * + */ +union sctp_notification { + struct { + __u16 sn_type; /* Notification type. */ + __u16 sn_flags; + __u32 sn_length; + } sn_header; + struct sctp_assoc_change sn_assoc_change; + struct sctp_paddr_change sn_paddr_change; + struct sctp_remote_error sn_remote_error; + struct sctp_send_failed sn_send_failed; + struct sctp_shutdown_event sn_shutdown_event; + struct sctp_adaptation_event sn_adaptation_event; + struct sctp_pdapi_event sn_pdapi_event; + struct sctp_authkey_event sn_authkey_event; +}; + +/* Section 5.3.1 + * All standard values for sn_type flags are greater than 2^15. + * Values from 2^15 and down are reserved. + */ + +enum sctp_sn_type { + SCTP_SN_TYPE_BASE = (1<<15), + SCTP_ASSOC_CHANGE, + SCTP_PEER_ADDR_CHANGE, + SCTP_SEND_FAILED, + SCTP_REMOTE_ERROR, + SCTP_SHUTDOWN_EVENT, + SCTP_PARTIAL_DELIVERY_EVENT, + SCTP_ADAPTATION_INDICATION, + SCTP_AUTHENTICATION_INDICATION, +}; + +/* Notification error codes used to fill up the error fields in some + * notifications. + * SCTP_PEER_ADDRESS_CHAGE : spc_error + * SCTP_ASSOC_CHANGE : sac_error + * These names should be potentially included in the draft 04 of the SCTP + * sockets API specification. + */ +typedef enum sctp_sn_error { + SCTP_FAILED_THRESHOLD, + SCTP_RECEIVED_SACK, + SCTP_HEARTBEAT_SUCCESS, + SCTP_RESPONSE_TO_USER_REQ, + SCTP_INTERNAL_ERROR, + SCTP_SHUTDOWN_GUARD_EXPIRES, + SCTP_PEER_FAULTY, +} sctp_sn_error_t; + +/* + * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) + * + * The protocol parameters used to initialize and bound retransmission + * timeout (RTO) are tunable. See [SCTP] for more information on how + * these parameters are used in RTO calculation. + */ +struct sctp_rtoinfo { + sctp_assoc_t srto_assoc_id; + __u32 srto_initial; + __u32 srto_max; + __u32 srto_min; +}; + +/* + * 7.1.2 Association Parameters (SCTP_ASSOCINFO) + * + * This option is used to both examine and set various association and + * endpoint parameters. + */ +struct sctp_assocparams { + sctp_assoc_t sasoc_assoc_id; + __u16 sasoc_asocmaxrxt; + __u16 sasoc_number_peer_destinations; + __u32 sasoc_peer_rwnd; + __u32 sasoc_local_rwnd; + __u32 sasoc_cookie_life; +}; + +/* + * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * + * Requests that the peer mark the enclosed address as the association + * primary. The enclosed address must be one of the association's + * locally bound addresses. The following structure is used to make a + * set primary request: + */ +struct sctp_setpeerprim { + sctp_assoc_t sspp_assoc_id; + struct sockaddr_storage sspp_addr; +} __attribute__((packed, aligned(4))); + +/* + * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) + * + * Requests that the local SCTP stack use the enclosed peer address as + * the association primary. The enclosed address must be one of the + * association peer's addresses. The following structure is used to + * make a set peer primary request: + */ +struct sctp_prim { + sctp_assoc_t ssp_assoc_id; + struct sockaddr_storage ssp_addr; +} __attribute__((packed, aligned(4))); + +/* + * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) + * + * Requests that the local endpoint set the specified Adaptation Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +struct sctp_setadaptation { + __u32 ssb_adaptation_ind; +}; + +/* + * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + */ +enum sctp_spp_flags { + SPP_HB_ENABLE = 1<<0, /*Enable heartbeats*/ + SPP_HB_DISABLE = 1<<1, /*Disable heartbeats*/ + SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE, + SPP_HB_DEMAND = 1<<2, /*Send heartbeat immediately*/ + SPP_PMTUD_ENABLE = 1<<3, /*Enable PMTU discovery*/ + SPP_PMTUD_DISABLE = 1<<4, /*Disable PMTU discovery*/ + SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE, + SPP_SACKDELAY_ENABLE = 1<<5, /*Enable SACK*/ + SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/ + SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE, + SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */ +}; + +struct sctp_paddrparams { + sctp_assoc_t spp_assoc_id; + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; + __u32 spp_pathmtu; + __u32 spp_sackdelay; + __u32 spp_flags; +} __attribute__((packed, aligned(4))); + +/* + * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) + * + * This set option adds a chunk type that the user is requesting to be + * received only in an authenticated way. Changes to the list of chunks + * will only effect future associations on the socket. + */ +struct sctp_authchunk { + __u8 sauth_chunk; +}; + +/* + * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) + * + * This option gets or sets the list of HMAC algorithms that the local + * endpoint requires the peer to use. +*/ +struct sctp_hmacalgo { + __u32 shmac_num_idents; + __u16 shmac_idents[]; +}; + +/* + * 7.1.20. Set a shared key (SCTP_AUTH_KEY) + * + * This option will set a shared secret key which is used to build an + * association shared key. + */ +struct sctp_authkey { + sctp_assoc_t sca_assoc_id; + __u16 sca_keynumber; + __u16 sca_keylength; + __u8 sca_key[]; +}; + +/* + * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) + * + * This option will get or set the active shared key to be used to build + * the association shared key. + */ + +struct sctp_authkeyid { + sctp_assoc_t scact_assoc_id; + __u16 scact_keynumber; +}; + + +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) + * + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. + */ +struct sctp_sack_info { + sctp_assoc_t sack_assoc_id; + uint32_t sack_delay; + uint32_t sack_freq; +}; + +struct sctp_assoc_value { + sctp_assoc_t assoc_id; + uint32_t assoc_value; +}; + +/* + * 7.2.2 Peer Address Information + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. The following structure is used to access this + * information: + */ +struct sctp_paddrinfo { + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; +} __attribute__((packed, aligned(4))); + +/* Peer addresses's state. */ +/* UNKNOWN: Peer address passed by the upper layer in sendmsg or connect[x] + * calls. + * UNCONFIRMED: Peer address received in INIT/INIT-ACK address parameters. + * Not yet confirmed by a heartbeat and not available for data + * transfers. + * ACTIVE : Peer address confirmed, active and available for data transfers. + * INACTIVE: Peer address inactive and not available for data transfers. + */ +enum sctp_spinfo_state { + SCTP_INACTIVE, + SCTP_ACTIVE, + SCTP_UNCONFIRMED, + SCTP_UNKNOWN = 0xffff /* Value used for transport state unknown */ +}; + +/* + * 7.2.1 Association Status (SCTP_STATUS) + * + * Applications can retrieve current status information about an + * association, including association state, peer receiver window size, + * number of unacked data chunks, and number of data chunks pending + * receipt. This information is read-only. The following structure is + * used to access this information: + */ +struct sctp_status { + sctp_assoc_t sstat_assoc_id; + __s32 sstat_state; + __u32 sstat_rwnd; + __u16 sstat_unackdata; + __u16 sstat_penddata; + __u16 sstat_instrms; + __u16 sstat_outstrms; + __u32 sstat_fragmentation_point; + struct sctp_paddrinfo sstat_primary; +}; + +/* + * 7.2.3. Get the list of chunks the peer requires to be authenticated + * (SCTP_PEER_AUTH_CHUNKS) + * + * This option gets a list of chunks for a specified association that + * the peer requires to be received authenticated only. + */ +struct sctp_authchunks { + sctp_assoc_t gauth_assoc_id; + __u32 gauth_number_of_chunks; + uint8_t gauth_chunks[]; +}; + +/* + * 8.3, 8.5 get all peer/local addresses in an association. + * This parameter struct is used by SCTP_GET_PEER_ADDRS and + * SCTP_GET_LOCAL_ADDRS socket options used internally to implement + * sctp_getpaddrs() and sctp_getladdrs() API. + */ +struct sctp_getaddrs_old { + sctp_assoc_t assoc_id; + int addr_num; + struct sockaddr __user *addrs; +}; +struct sctp_getaddrs { + sctp_assoc_t assoc_id; /*input*/ + __u32 addr_num; /*output*/ + __u8 addrs[0]; /*output, variable size*/ +}; + +/* These are bit fields for msghdr->msg_flags. See section 5.1. */ +/* On user space Linux, these live in <bits/socket.h> as an enum. */ +enum sctp_msg_flags { + MSG_NOTIFICATION = 0x8000, +#define MSG_NOTIFICATION MSG_NOTIFICATION +}; + +/* + * 8.1 sctp_bindx() + * + * The flags parameter is formed from the bitwise OR of zero or more of the + * following currently defined flags: + */ +#define SCTP_BINDX_ADD_ADDR 0x01 +#define SCTP_BINDX_REM_ADDR 0x02 + +/* This is the structure that is passed as an argument(optval) to + * getsockopt(SCTP_SOCKOPT_PEELOFF). + */ +typedef struct { + sctp_assoc_t associd; + int sd; +} sctp_peeloff_arg_t; + +#endif /* __net_sctp_user_h__ */ diff --git a/include/net/slhc_vj.h b/include/net/slhc_vj.h new file mode 100644 index 00000000..8716d594 --- /dev/null +++ b/include/net/slhc_vj.h @@ -0,0 +1,183 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens@ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson@um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * 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, + * acknowledgment, 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". + */ + + +#include <linux/ip.h> +#include <linux/tcp.h> + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_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 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "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 { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +/* In slhc.c: */ +struct slcompress *slhc_init(int rslots, int tslots); +void slhc_free(struct slcompress *comp); + +int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_toss(struct slcompress *comp); + +#endif /* _SLHC_H */ diff --git a/include/net/snmp.h b/include/net/snmp.h new file mode 100644 index 00000000..a0e61806 --- /dev/null +++ b/include/net/snmp.h @@ -0,0 +1,225 @@ +/* + * + * SNMP MIB entries for the IP subsystem. + * + * Alan Cox <gw4pts@gw4pts.ampr.org> + * + * We don't chose to implement SNMP in the kernel (this would + * be silly as SNMP is a pain in the backside in places). We do + * however need to collect the MIB statistics and export them + * out of /proc (eventually) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#ifndef _SNMP_H +#define _SNMP_H + +#include <linux/cache.h> +#include <linux/snmp.h> +#include <linux/smp.h> + +/* + * Mibs are stored in array of unsigned long. + */ +/* + * struct snmp_mib{} + * - list of entries for particular API (such as /proc/net/snmp) + * - name of entries. + */ +struct snmp_mib { + const char *name; + int entry; +}; + +#define SNMP_MIB_ITEM(_name,_entry) { \ + .name = _name, \ + .entry = _entry, \ +} + +#define SNMP_MIB_SENTINEL { \ + .name = NULL, \ + .entry = 0, \ +} + +/* + * We use unsigned longs for most mibs but u64 for ipstats. + */ +#include <linux/u64_stats_sync.h> + +/* IPstats */ +#define IPSTATS_MIB_MAX __IPSTATS_MIB_MAX +struct ipstats_mib { + /* mibs[] must be first field of struct ipstats_mib */ + u64 mibs[IPSTATS_MIB_MAX]; + struct u64_stats_sync syncp; +}; + +/* ICMP */ +#define ICMP_MIB_DUMMY __ICMP_MIB_MAX +#define ICMP_MIB_MAX (__ICMP_MIB_MAX + 1) + +struct icmp_mib { + unsigned long mibs[ICMP_MIB_MAX]; +}; + +#define ICMPMSG_MIB_MAX __ICMPMSG_MIB_MAX +struct icmpmsg_mib { + unsigned long mibs[ICMPMSG_MIB_MAX]; +}; + +/* ICMP6 (IPv6-ICMP) */ +#define ICMP6_MIB_MAX __ICMP6_MIB_MAX +struct icmpv6_mib { + unsigned long mibs[ICMP6_MIB_MAX]; +}; + +#define ICMP6MSG_MIB_MAX __ICMP6MSG_MIB_MAX +struct icmpv6msg_mib { + unsigned long mibs[ICMP6MSG_MIB_MAX]; +}; + + +/* TCP */ +#define TCP_MIB_MAX __TCP_MIB_MAX +struct tcp_mib { + unsigned long mibs[TCP_MIB_MAX]; +}; + +/* UDP */ +#define UDP_MIB_MAX __UDP_MIB_MAX +struct udp_mib { + unsigned long mibs[UDP_MIB_MAX]; +}; + +/* Linux */ +#define LINUX_MIB_MAX __LINUX_MIB_MAX +struct linux_mib { + unsigned long mibs[LINUX_MIB_MAX]; +}; + +/* Linux Xfrm */ +#define LINUX_MIB_XFRMMAX __LINUX_MIB_XFRMMAX +struct linux_xfrm_mib { + unsigned long mibs[LINUX_MIB_XFRMMAX]; +}; + +/* + * FIXME: On x86 and some other CPUs the split into user and softirq parts + * is not needed because addl $1,memory is atomic against interrupts (but + * atomic_inc would be overkill because of the lock cycles). Wants new + * nonlocked_atomic_inc() primitives -AK + */ +#define DEFINE_SNMP_STAT(type, name) \ + __typeof__(type) __percpu *name[2] +#define DECLARE_SNMP_STAT(type, name) \ + extern __typeof__(type) __percpu *name[2] + +#define SNMP_STAT_BHPTR(name) (name[0]) +#define SNMP_STAT_USRPTR(name) (name[1]) + +#define SNMP_INC_STATS_BH(mib, field) \ + __this_cpu_inc(mib[0]->mibs[field]) +#define SNMP_INC_STATS_USER(mib, field) \ + this_cpu_inc(mib[1]->mibs[field]) +#define SNMP_INC_STATS(mib, field) \ + this_cpu_inc(mib[!in_softirq()]->mibs[field]) +#define SNMP_DEC_STATS(mib, field) \ + this_cpu_dec(mib[!in_softirq()]->mibs[field]) +#define SNMP_ADD_STATS_BH(mib, field, addend) \ + __this_cpu_add(mib[0]->mibs[field], addend) +#define SNMP_ADD_STATS_USER(mib, field, addend) \ + this_cpu_add(mib[1]->mibs[field], addend) +#define SNMP_ADD_STATS(mib, field, addend) \ + this_cpu_add(mib[!in_softirq()]->mibs[field], addend) +/* + * Use "__typeof__(*mib[0]) *ptr" instead of "__typeof__(mib[0]) ptr" + * to make @ptr a non-percpu pointer. + */ +#define SNMP_UPD_PO_STATS(mib, basefield, addend) \ + do { \ + __typeof__(*mib[0]) *ptr; \ + preempt_disable(); \ + ptr = this_cpu_ptr((mib)[!in_softirq()]); \ + ptr->mibs[basefield##PKTS]++; \ + ptr->mibs[basefield##OCTETS] += addend;\ + preempt_enable(); \ + } while (0) +#define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \ + do { \ + __typeof__(*mib[0]) *ptr = \ + __this_cpu_ptr((mib)[!in_softirq()]); \ + ptr->mibs[basefield##PKTS]++; \ + ptr->mibs[basefield##OCTETS] += addend;\ + } while (0) + + +#if BITS_PER_LONG==32 + +#define SNMP_ADD_STATS64_BH(mib, field, addend) \ + do { \ + __typeof__(*mib[0]) *ptr = __this_cpu_ptr((mib)[0]); \ + u64_stats_update_begin(&ptr->syncp); \ + ptr->mibs[field] += addend; \ + u64_stats_update_end(&ptr->syncp); \ + } while (0) +#define SNMP_ADD_STATS64_USER(mib, field, addend) \ + do { \ + __typeof__(*mib[0]) *ptr; \ + preempt_disable(); \ + ptr = __this_cpu_ptr((mib)[1]); \ + u64_stats_update_begin(&ptr->syncp); \ + ptr->mibs[field] += addend; \ + u64_stats_update_end(&ptr->syncp); \ + preempt_enable(); \ + } while (0) +#define SNMP_ADD_STATS64(mib, field, addend) \ + do { \ + __typeof__(*mib[0]) *ptr; \ + preempt_disable(); \ + ptr = __this_cpu_ptr((mib)[!in_softirq()]); \ + u64_stats_update_begin(&ptr->syncp); \ + ptr->mibs[field] += addend; \ + u64_stats_update_end(&ptr->syncp); \ + preempt_enable(); \ + } while (0) +#define SNMP_INC_STATS64_BH(mib, field) SNMP_ADD_STATS64_BH(mib, field, 1) +#define SNMP_INC_STATS64_USER(mib, field) SNMP_ADD_STATS64_USER(mib, field, 1) +#define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1) +#define SNMP_UPD_PO_STATS64(mib, basefield, addend) \ + do { \ + __typeof__(*mib[0]) *ptr; \ + preempt_disable(); \ + ptr = __this_cpu_ptr((mib)[!in_softirq()]); \ + u64_stats_update_begin(&ptr->syncp); \ + ptr->mibs[basefield##PKTS]++; \ + ptr->mibs[basefield##OCTETS] += addend; \ + u64_stats_update_end(&ptr->syncp); \ + preempt_enable(); \ + } while (0) +#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \ + do { \ + __typeof__(*mib[0]) *ptr; \ + ptr = __this_cpu_ptr((mib)[!in_softirq()]); \ + u64_stats_update_begin(&ptr->syncp); \ + ptr->mibs[basefield##PKTS]++; \ + ptr->mibs[basefield##OCTETS] += addend; \ + u64_stats_update_end(&ptr->syncp); \ + } while (0) +#else +#define SNMP_INC_STATS64_BH(mib, field) SNMP_INC_STATS_BH(mib, field) +#define SNMP_INC_STATS64_USER(mib, field) SNMP_INC_STATS_USER(mib, field) +#define SNMP_INC_STATS64(mib, field) SNMP_INC_STATS(mib, field) +#define SNMP_DEC_STATS64(mib, field) SNMP_DEC_STATS(mib, field) +#define SNMP_ADD_STATS64_BH(mib, field, addend) SNMP_ADD_STATS_BH(mib, field, addend) +#define SNMP_ADD_STATS64_USER(mib, field, addend) SNMP_ADD_STATS_USER(mib, field, addend) +#define SNMP_ADD_STATS64(mib, field, addend) SNMP_ADD_STATS(mib, field, addend) +#define SNMP_UPD_PO_STATS64(mib, basefield, addend) SNMP_UPD_PO_STATS(mib, basefield, addend) +#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) SNMP_UPD_PO_STATS_BH(mib, basefield, addend) +#endif + +#endif diff --git a/include/net/sock.h b/include/net/sock.h new file mode 100644 index 00000000..6892a5e8 --- /dev/null +++ b/include/net/sock.h @@ -0,0 +1,1773 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the AF_INET socket handler. + * + * Version: @(#)sock.h 1.0.4 05/13/93 + * + * Authors: Ross Biro + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Corey Minyard <wf-rch!minyard@relay.EU.net> + * Florian La Roche <flla@stud.uni-sb.de> + * + * Fixes: + * Alan Cox : Volatiles in skbuff pointers. See + * skbuff comments. May be overdone, + * better to prove they can be removed + * than the reverse. + * Alan Cox : Added a zapped field for tcp to note + * a socket is reset and must stay shut up + * Alan Cox : New fields for options + * Pauline Middelink : identd support + * Alan Cox : Eliminate low level recv/recvfrom + * David S. Miller : New socket lookup architecture. + * Steve Whitehouse: Default routines for sock_ops + * Arnaldo C. Melo : removed net_pinfo, tp_pinfo and made + * protinfo be just a void pointer, as the + * protocol specific parts were moved to + * respective headers and ipv4/v6, etc now + * use private slabcaches for its socks + * Pedro Hortas : New flags field for socket options + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _SOCK_H +#define _SOCK_H + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/list_nulls.h> +#include <linux/timer.h> +#include <linux/cache.h> +#include <linux/module.h> +#include <linux/lockdep.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> /* struct sk_buff */ +#include <linux/mm.h> +#include <linux/security.h> +#include <linux/slab.h> + +#include <linux/filter.h> +#include <linux/rculist_nulls.h> +#include <linux/poll.h> + +#include <asm/atomic.h> +#include <net/dst.h> +#include <net/checksum.h> + +/* + * This structure really needs to be cleaned up. + * Most of it is for TCP, and not used by any of + * the other protocols. + */ + +/* Define this to get the SOCK_DBG debugging facility. */ +#define SOCK_DEBUGGING +#ifdef SOCK_DEBUGGING +#define SOCK_DEBUG(sk, msg...) do { if ((sk) && sock_flag((sk), SOCK_DBG)) \ + printk(KERN_DEBUG msg); } while (0) +#else +/* Validate arguments and do nothing */ +static inline void __attribute__ ((format (printf, 2, 3))) +SOCK_DEBUG(struct sock *sk, const char *msg, ...) +{ +} +#endif + +/* This is the per-socket lock. The spinlock provides a synchronization + * between user contexts and software interrupt processing, whereas the + * mini-semaphore synchronizes multiple users amongst themselves. + */ +typedef struct { + spinlock_t slock; + int owned; + wait_queue_head_t wq; + /* + * We express the mutex-alike socket_lock semantics + * to the lock validator by explicitly managing + * the slock as a lock variant (in addition to + * the slock itself): + */ +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif +} socket_lock_t; + +struct sock; +struct proto; +struct net; + +/** + * struct sock_common - minimal network layer representation of sockets + * @skc_node: main hash linkage for various protocol lookup tables + * @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol + * @skc_refcnt: reference count + * @skc_tx_queue_mapping: tx queue number for this connection + * @skc_hash: hash value used with various protocol lookup tables + * @skc_u16hashes: two u16 hash values used by UDP lookup tables + * @skc_family: network address family + * @skc_state: Connection state + * @skc_reuse: %SO_REUSEADDR setting + * @skc_bound_dev_if: bound device index if != 0 + * @skc_bind_node: bind hash linkage for various protocol lookup tables + * @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol + * @skc_prot: protocol handlers inside a network family + * @skc_net: reference to the network namespace of this socket + * + * This is the minimal network layer representation of sockets, the header + * for struct sock and struct inet_timewait_sock. + */ +struct sock_common { + /* + * first fields are not copied in sock_copy() + */ + union { + struct hlist_node skc_node; + struct hlist_nulls_node skc_nulls_node; + }; + atomic_t skc_refcnt; + int skc_tx_queue_mapping; + + union { + unsigned int skc_hash; + __u16 skc_u16hashes[2]; + }; + unsigned short skc_family; + volatile unsigned char skc_state; + unsigned char skc_reuse; + int skc_bound_dev_if; + union { + struct hlist_node skc_bind_node; + struct hlist_nulls_node skc_portaddr_node; + }; + struct proto *skc_prot; +#ifdef CONFIG_NET_NS + struct net *skc_net; +#endif +}; + +/** + * struct sock - network layer representation of sockets + * @__sk_common: shared layout with inet_timewait_sock + * @sk_shutdown: mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN + * @sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings + * @sk_lock: synchronizer + * @sk_rcvbuf: size of receive buffer in bytes + * @sk_wq: sock wait queue and async head + * @sk_dst_cache: destination cache + * @sk_dst_lock: destination cache lock + * @sk_policy: flow policy + * @sk_rmem_alloc: receive queue bytes committed + * @sk_receive_queue: incoming packets + * @sk_wmem_alloc: transmit queue bytes committed + * @sk_write_queue: Packet sending queue + * @sk_async_wait_queue: DMA copied packets + * @sk_omem_alloc: "o" is "option" or "other" + * @sk_wmem_queued: persistent queue size + * @sk_forward_alloc: space allocated forward + * @sk_allocation: allocation mode + * @sk_sndbuf: size of send buffer in bytes + * @sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, + * %SO_OOBINLINE settings, %SO_TIMESTAMPING settings + * @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets + * @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO) + * @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK) + * @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4) + * @sk_gso_max_size: Maximum GSO segment size to build + * @sk_lingertime: %SO_LINGER l_linger setting + * @sk_backlog: always used with the per-socket spinlock held + * @sk_callback_lock: used with the callbacks in the end of this struct + * @sk_error_queue: rarely used + * @sk_prot_creator: sk_prot of original sock creator (see ipv6_setsockopt, + * IPV6_ADDRFORM for instance) + * @sk_err: last error + * @sk_err_soft: errors that don't cause failure but are the cause of a + * persistent failure not just 'timed out' + * @sk_drops: raw/udp drops counter + * @sk_ack_backlog: current listen backlog + * @sk_max_ack_backlog: listen backlog set in listen() + * @sk_priority: %SO_PRIORITY setting + * @sk_type: socket type (%SOCK_STREAM, etc) + * @sk_protocol: which protocol this socket belongs in this network family + * @sk_peer_pid: &struct pid for this socket's peer + * @sk_peer_cred: %SO_PEERCRED setting + * @sk_rcvlowat: %SO_RCVLOWAT setting + * @sk_rcvtimeo: %SO_RCVTIMEO setting + * @sk_sndtimeo: %SO_SNDTIMEO setting + * @sk_rxhash: flow hash received from netif layer + * @sk_filter: socket filtering instructions + * @sk_protinfo: private area, net family specific, when not using slab + * @sk_timer: sock cleanup timer + * @sk_stamp: time stamp of last packet received + * @sk_socket: Identd and reporting IO signals + * @sk_user_data: RPC layer private data + * @sk_sndmsg_page: cached page for sendmsg + * @sk_sndmsg_off: cached offset for sendmsg + * @sk_send_head: front of stuff to transmit + * @sk_security: used by security modules + * @sk_mark: generic packet mark + * @sk_classid: this socket's cgroup classid + * @sk_write_pending: a write to stream socket waits to start + * @sk_state_change: callback to indicate change in the state of the sock + * @sk_data_ready: callback to indicate there is data to be processed + * @sk_write_space: callback to indicate there is bf sending space available + * @sk_error_report: callback to indicate errors (e.g. %MSG_ERRQUEUE) + * @sk_backlog_rcv: callback to process the backlog + * @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0 + */ +struct sock { + /* + * Now struct inet_timewait_sock also uses sock_common, so please just + * don't add nothing before this first member (__sk_common) --acme + */ + struct sock_common __sk_common; +#define sk_node __sk_common.skc_node +#define sk_nulls_node __sk_common.skc_nulls_node +#define sk_refcnt __sk_common.skc_refcnt +#define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping + +#define sk_copy_start __sk_common.skc_hash +#define sk_hash __sk_common.skc_hash +#define sk_family __sk_common.skc_family +#define sk_state __sk_common.skc_state +#define sk_reuse __sk_common.skc_reuse +#define sk_bound_dev_if __sk_common.skc_bound_dev_if +#define sk_bind_node __sk_common.skc_bind_node +#define sk_prot __sk_common.skc_prot +#define sk_net __sk_common.skc_net + kmemcheck_bitfield_begin(flags); + unsigned int sk_shutdown : 2, + sk_no_check : 2, + sk_userlocks : 4, + sk_protocol : 8, + sk_type : 16; + kmemcheck_bitfield_end(flags); + int sk_rcvbuf; + socket_lock_t sk_lock; + /* + * The backlog queue is special, it is always used with + * the per-socket spinlock held and requires low latency + * access. Therefore we special case it's implementation. + */ + struct { + struct sk_buff *head; + struct sk_buff *tail; + int len; + } sk_backlog; + struct socket_wq *sk_wq; + struct dst_entry *sk_dst_cache; +#ifdef CONFIG_XFRM + struct xfrm_policy *sk_policy[2]; +#endif + spinlock_t sk_dst_lock; + atomic_t sk_rmem_alloc; + atomic_t sk_wmem_alloc; + atomic_t sk_omem_alloc; + int sk_sndbuf; + struct sk_buff_head sk_receive_queue; + struct sk_buff_head sk_write_queue; +#ifdef CONFIG_NET_DMA + struct sk_buff_head sk_async_wait_queue; +#endif + int sk_wmem_queued; + int sk_forward_alloc; + gfp_t sk_allocation; + int sk_route_caps; + int sk_route_nocaps; + int sk_gso_type; + unsigned int sk_gso_max_size; + int sk_rcvlowat; +#ifdef CONFIG_RPS + __u32 sk_rxhash; +#endif + unsigned long sk_flags; + unsigned long sk_lingertime; + struct sk_buff_head sk_error_queue; + struct proto *sk_prot_creator; + rwlock_t sk_callback_lock; + int sk_err, + sk_err_soft; + atomic_t sk_drops; + unsigned short sk_ack_backlog; + unsigned short sk_max_ack_backlog; + __u32 sk_priority; + struct pid *sk_peer_pid; + const struct cred *sk_peer_cred; + long sk_rcvtimeo; + long sk_sndtimeo; + struct sk_filter *sk_filter; + void *sk_protinfo; + struct timer_list sk_timer; + ktime_t sk_stamp; + struct socket *sk_socket; + void *sk_user_data; + struct page *sk_sndmsg_page; + struct sk_buff *sk_send_head; + __u32 sk_sndmsg_off; + int sk_write_pending; +#ifdef CONFIG_SECURITY + void *sk_security; +#endif + __u32 sk_mark; + u32 sk_classid; + void (*sk_state_change)(struct sock *sk); + void (*sk_data_ready)(struct sock *sk, int bytes); + void (*sk_write_space)(struct sock *sk); + void (*sk_error_report)(struct sock *sk); + int (*sk_backlog_rcv)(struct sock *sk, + struct sk_buff *skb); + void (*sk_destruct)(struct sock *sk); +}; + +/* + * Hashed lists helper routines + */ +static inline struct sock *sk_entry(const struct hlist_node *node) +{ + return hlist_entry(node, struct sock, sk_node); +} + +static inline struct sock *__sk_head(const struct hlist_head *head) +{ + return hlist_entry(head->first, struct sock, sk_node); +} + +static inline struct sock *sk_head(const struct hlist_head *head) +{ + return hlist_empty(head) ? NULL : __sk_head(head); +} + +static inline struct sock *__sk_nulls_head(const struct hlist_nulls_head *head) +{ + return hlist_nulls_entry(head->first, struct sock, sk_nulls_node); +} + +static inline struct sock *sk_nulls_head(const struct hlist_nulls_head *head) +{ + return hlist_nulls_empty(head) ? NULL : __sk_nulls_head(head); +} + +static inline struct sock *sk_next(const struct sock *sk) +{ + return sk->sk_node.next ? + hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL; +} + +static inline struct sock *sk_nulls_next(const struct sock *sk) +{ + return (!is_a_nulls(sk->sk_nulls_node.next)) ? + hlist_nulls_entry(sk->sk_nulls_node.next, + struct sock, sk_nulls_node) : + NULL; +} + +static inline int sk_unhashed(const struct sock *sk) +{ + return hlist_unhashed(&sk->sk_node); +} + +static inline int sk_hashed(const struct sock *sk) +{ + return !sk_unhashed(sk); +} + +static __inline__ void sk_node_init(struct hlist_node *node) +{ + node->pprev = NULL; +} + +static __inline__ void sk_nulls_node_init(struct hlist_nulls_node *node) +{ + node->pprev = NULL; +} + +static __inline__ void __sk_del_node(struct sock *sk) +{ + __hlist_del(&sk->sk_node); +} + +/* NB: equivalent to hlist_del_init_rcu */ +static __inline__ int __sk_del_node_init(struct sock *sk) +{ + if (sk_hashed(sk)) { + __sk_del_node(sk); + sk_node_init(&sk->sk_node); + return 1; + } + return 0; +} + +/* Grab socket reference count. This operation is valid only + when sk is ALREADY grabbed f.e. it is found in hash table + or a list and the lookup is made under lock preventing hash table + modifications. + */ + +static inline void sock_hold(struct sock *sk) +{ + atomic_inc(&sk->sk_refcnt); +} + +/* Ungrab socket in the context, which assumes that socket refcnt + cannot hit zero, f.e. it is true in context of any socketcall. + */ +static inline void __sock_put(struct sock *sk) +{ + atomic_dec(&sk->sk_refcnt); +} + +static __inline__ int sk_del_node_init(struct sock *sk) +{ + int rc = __sk_del_node_init(sk); + + if (rc) { + /* paranoid for a while -acme */ + WARN_ON(atomic_read(&sk->sk_refcnt) == 1); + __sock_put(sk); + } + return rc; +} +#define sk_del_node_init_rcu(sk) sk_del_node_init(sk) + +static __inline__ int __sk_nulls_del_node_init_rcu(struct sock *sk) +{ + if (sk_hashed(sk)) { + hlist_nulls_del_init_rcu(&sk->sk_nulls_node); + return 1; + } + return 0; +} + +static __inline__ int sk_nulls_del_node_init_rcu(struct sock *sk) +{ + int rc = __sk_nulls_del_node_init_rcu(sk); + + if (rc) { + /* paranoid for a while -acme */ + WARN_ON(atomic_read(&sk->sk_refcnt) == 1); + __sock_put(sk); + } + return rc; +} + +static __inline__ void __sk_add_node(struct sock *sk, struct hlist_head *list) +{ + hlist_add_head(&sk->sk_node, list); +} + +static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list) +{ + sock_hold(sk); + __sk_add_node(sk, list); +} + +static __inline__ void sk_add_node_rcu(struct sock *sk, struct hlist_head *list) +{ + sock_hold(sk); + hlist_add_head_rcu(&sk->sk_node, list); +} + +static __inline__ void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) +{ + hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list); +} + +static __inline__ void sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) +{ + sock_hold(sk); + __sk_nulls_add_node_rcu(sk, list); +} + +static __inline__ void __sk_del_bind_node(struct sock *sk) +{ + __hlist_del(&sk->sk_bind_node); +} + +static __inline__ void sk_add_bind_node(struct sock *sk, + struct hlist_head *list) +{ + hlist_add_head(&sk->sk_bind_node, list); +} + +#define sk_for_each(__sk, node, list) \ + hlist_for_each_entry(__sk, node, list, sk_node) +#define sk_for_each_rcu(__sk, node, list) \ + hlist_for_each_entry_rcu(__sk, node, list, sk_node) +#define sk_nulls_for_each(__sk, node, list) \ + hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node) +#define sk_nulls_for_each_rcu(__sk, node, list) \ + hlist_nulls_for_each_entry_rcu(__sk, node, list, sk_nulls_node) +#define sk_for_each_from(__sk, node) \ + if (__sk && ({ node = &(__sk)->sk_node; 1; })) \ + hlist_for_each_entry_from(__sk, node, sk_node) +#define sk_nulls_for_each_from(__sk, node) \ + if (__sk && ({ node = &(__sk)->sk_nulls_node; 1; })) \ + hlist_nulls_for_each_entry_from(__sk, node, sk_nulls_node) +#define sk_for_each_continue(__sk, node) \ + if (__sk && ({ node = &(__sk)->sk_node; 1; })) \ + hlist_for_each_entry_continue(__sk, node, sk_node) +#define sk_for_each_safe(__sk, node, tmp, list) \ + hlist_for_each_entry_safe(__sk, node, tmp, list, sk_node) +#define sk_for_each_bound(__sk, node, list) \ + hlist_for_each_entry(__sk, node, list, sk_bind_node) + +/* Sock flags */ +enum sock_flags { + SOCK_DEAD, + SOCK_DONE, + SOCK_URGINLINE, + SOCK_KEEPOPEN, + SOCK_LINGER, + SOCK_DESTROY, + SOCK_BROADCAST, + SOCK_TIMESTAMP, + SOCK_ZAPPED, + SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */ + SOCK_DBG, /* %SO_DEBUG setting */ + SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */ + SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */ + SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */ + SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ + SOCK_TIMESTAMPING_TX_HARDWARE, /* %SOF_TIMESTAMPING_TX_HARDWARE */ + SOCK_TIMESTAMPING_TX_SOFTWARE, /* %SOF_TIMESTAMPING_TX_SOFTWARE */ + SOCK_TIMESTAMPING_RX_HARDWARE, /* %SOF_TIMESTAMPING_RX_HARDWARE */ + SOCK_TIMESTAMPING_RX_SOFTWARE, /* %SOF_TIMESTAMPING_RX_SOFTWARE */ + SOCK_TIMESTAMPING_SOFTWARE, /* %SOF_TIMESTAMPING_SOFTWARE */ + SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SOF_TIMESTAMPING_RAW_HARDWARE */ + SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SOF_TIMESTAMPING_SYS_HARDWARE */ + SOCK_FASYNC, /* fasync() active */ + SOCK_RXQ_OVFL, +}; + +static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) +{ + nsk->sk_flags = osk->sk_flags; +} + +static inline void sock_set_flag(struct sock *sk, enum sock_flags flag) +{ + __set_bit(flag, &sk->sk_flags); +} + +static inline void sock_reset_flag(struct sock *sk, enum sock_flags flag) +{ + __clear_bit(flag, &sk->sk_flags); +} + +static inline int sock_flag(struct sock *sk, enum sock_flags flag) +{ + return test_bit(flag, &sk->sk_flags); +} + +static inline void sk_acceptq_removed(struct sock *sk) +{ + sk->sk_ack_backlog--; +} + +static inline void sk_acceptq_added(struct sock *sk) +{ + sk->sk_ack_backlog++; +} + +static inline int sk_acceptq_is_full(struct sock *sk) +{ + return sk->sk_ack_backlog > sk->sk_max_ack_backlog; +} + +/* + * Compute minimal free write space needed to queue new packets. + */ +static inline int sk_stream_min_wspace(struct sock *sk) +{ + return sk->sk_wmem_queued >> 1; +} + +static inline int sk_stream_wspace(struct sock *sk) +{ + return sk->sk_sndbuf - sk->sk_wmem_queued; +} + +extern void sk_stream_write_space(struct sock *sk); + +static inline int sk_stream_memory_free(struct sock *sk) +{ + return sk->sk_wmem_queued < sk->sk_sndbuf; +} + +/* OOB backlog add */ +static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb) +{ + /* dont let skb dst not refcounted, we are going to leave rcu lock */ + skb_dst_force(skb); + + if (!sk->sk_backlog.tail) + sk->sk_backlog.head = skb; + else + sk->sk_backlog.tail->next = skb; + + sk->sk_backlog.tail = skb; + skb->next = NULL; +} + +/* + * Take into account size of receive queue and backlog queue + */ +static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff *skb) +{ + unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc); + + return qsize + skb->truesize > sk->sk_rcvbuf; +} + +/* The per-socket spinlock must be held here. */ +static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *skb) +{ + if (sk_rcvqueues_full(sk, skb)) + return -ENOBUFS; + + __sk_add_backlog(sk, skb); + sk->sk_backlog.len += skb->truesize; + return 0; +} + +static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) +{ + return sk->sk_backlog_rcv(sk, skb); +} + +static inline void sock_rps_record_flow(const struct sock *sk) +{ +#ifdef CONFIG_RPS + struct rps_sock_flow_table *sock_flow_table; + + rcu_read_lock(); + sock_flow_table = rcu_dereference(rps_sock_flow_table); + rps_record_sock_flow(sock_flow_table, sk->sk_rxhash); + rcu_read_unlock(); +#endif +} + +static inline void sock_rps_reset_flow(const struct sock *sk) +{ +#ifdef CONFIG_RPS + struct rps_sock_flow_table *sock_flow_table; + + rcu_read_lock(); + sock_flow_table = rcu_dereference(rps_sock_flow_table); + rps_reset_sock_flow(sock_flow_table, sk->sk_rxhash); + rcu_read_unlock(); +#endif +} + +static inline void sock_rps_save_rxhash(struct sock *sk, u32 rxhash) +{ +#ifdef CONFIG_RPS + if (unlikely(sk->sk_rxhash != rxhash)) { + sock_rps_reset_flow(sk); + sk->sk_rxhash = rxhash; + } +#endif +} + +#define sk_wait_event(__sk, __timeo, __condition) \ + ({ int __rc; \ + release_sock(__sk); \ + __rc = __condition; \ + if (!__rc) { \ + *(__timeo) = schedule_timeout(*(__timeo)); \ + } \ + lock_sock(__sk); \ + __rc = __condition; \ + __rc; \ + }) + +extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p); +extern int sk_stream_wait_memory(struct sock *sk, long *timeo_p); +extern void sk_stream_wait_close(struct sock *sk, long timeo_p); +extern int sk_stream_error(struct sock *sk, int flags, int err); +extern void sk_stream_kill_queues(struct sock *sk); + +extern int sk_wait_data(struct sock *sk, long *timeo); + +struct request_sock_ops; +struct timewait_sock_ops; +struct inet_hashinfo; +struct raw_hashinfo; + +/* Networking protocol blocks we attach to sockets. + * socket layer -> transport layer interface + * transport -> network interface is defined by struct inet_proto + */ +struct proto { + void (*close)(struct sock *sk, + long timeout); + int (*connect)(struct sock *sk, + struct sockaddr *uaddr, + int addr_len); + int (*disconnect)(struct sock *sk, int flags); + + struct sock * (*accept) (struct sock *sk, int flags, int *err); + + int (*ioctl)(struct sock *sk, int cmd, + unsigned long arg); + int (*init)(struct sock *sk); + void (*destroy)(struct sock *sk); + void (*shutdown)(struct sock *sk, int how); + int (*setsockopt)(struct sock *sk, int level, + int optname, char __user *optval, + unsigned int optlen); + int (*getsockopt)(struct sock *sk, int level, + int optname, char __user *optval, + int __user *option); +#ifdef CONFIG_COMPAT + int (*compat_setsockopt)(struct sock *sk, + int level, + int optname, char __user *optval, + unsigned int optlen); + int (*compat_getsockopt)(struct sock *sk, + int level, + int optname, char __user *optval, + int __user *option); +#endif + int (*sendmsg)(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len); + int (*recvmsg)(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, + size_t len, int noblock, int flags, + int *addr_len); + int (*sendpage)(struct sock *sk, struct page *page, + int offset, size_t size, int flags); + int (*bind)(struct sock *sk, + struct sockaddr *uaddr, int addr_len); + + int (*backlog_rcv) (struct sock *sk, + struct sk_buff *skb); + + /* Keeping track of sk's, looking them up, and port selection methods. */ + void (*hash)(struct sock *sk); + void (*unhash)(struct sock *sk); + void (*rehash)(struct sock *sk); + int (*get_port)(struct sock *sk, unsigned short snum); + + /* Keeping track of sockets in use */ +#ifdef CONFIG_PROC_FS + unsigned int inuse_idx; +#endif + + /* Memory pressure */ + void (*enter_memory_pressure)(struct sock *sk); + atomic_t *memory_allocated; /* Current allocated memory. */ + struct percpu_counter *sockets_allocated; /* Current number of sockets. */ + /* + * Pressure flag: try to collapse. + * Technical note: it is used by multiple contexts non atomically. + * All the __sk_mem_schedule() is of this nature: accounting + * is strict, actions are advisory and have some latency. + */ + int *memory_pressure; + int *sysctl_mem; + int *sysctl_wmem; + int *sysctl_rmem; + int max_header; + bool no_autobind; + + struct kmem_cache *slab; + unsigned int obj_size; + int slab_flags; + + struct percpu_counter *orphan_count; + + struct request_sock_ops *rsk_prot; + struct timewait_sock_ops *twsk_prot; + + union { + struct inet_hashinfo *hashinfo; + struct udp_table *udp_table; + struct raw_hashinfo *raw_hash; + } h; + + struct module *owner; + + char name[32]; + + struct list_head node; +#ifdef SOCK_REFCNT_DEBUG + atomic_t socks; +#endif +}; + +extern int proto_register(struct proto *prot, int alloc_slab); +extern void proto_unregister(struct proto *prot); + +#ifdef SOCK_REFCNT_DEBUG +static inline void sk_refcnt_debug_inc(struct sock *sk) +{ + atomic_inc(&sk->sk_prot->socks); +} + +static inline void sk_refcnt_debug_dec(struct sock *sk) +{ + atomic_dec(&sk->sk_prot->socks); + printk(KERN_DEBUG "%s socket %p released, %d are still alive\n", + sk->sk_prot->name, sk, atomic_read(&sk->sk_prot->socks)); +} + +static inline void sk_refcnt_debug_release(const struct sock *sk) +{ + if (atomic_read(&sk->sk_refcnt) != 1) + printk(KERN_DEBUG "Destruction of the %s socket %p delayed, refcnt=%d\n", + sk->sk_prot->name, sk, atomic_read(&sk->sk_refcnt)); +} +#else /* SOCK_REFCNT_DEBUG */ +#define sk_refcnt_debug_inc(sk) do { } while (0) +#define sk_refcnt_debug_dec(sk) do { } while (0) +#define sk_refcnt_debug_release(sk) do { } while (0) +#endif /* SOCK_REFCNT_DEBUG */ + + +#ifdef CONFIG_PROC_FS +/* Called with local bh disabled */ +extern void sock_prot_inuse_add(struct net *net, struct proto *prot, int inc); +extern int sock_prot_inuse_get(struct net *net, struct proto *proto); +#else +static void inline sock_prot_inuse_add(struct net *net, struct proto *prot, + int inc) +{ +} +#endif + + +/* With per-bucket locks this operation is not-atomic, so that + * this version is not worse. + */ +static inline void __sk_prot_rehash(struct sock *sk) +{ + sk->sk_prot->unhash(sk); + sk->sk_prot->hash(sk); +} + +/* About 10 seconds */ +#define SOCK_DESTROY_TIME (10*HZ) + +/* Sockets 0-1023 can't be bound to unless you are superuser */ +#define PROT_SOCK 1024 + +#define SHUTDOWN_MASK 3 +#define RCV_SHUTDOWN 1 +#define SEND_SHUTDOWN 2 + +#define SOCK_SNDBUF_LOCK 1 +#define SOCK_RCVBUF_LOCK 2 +#define SOCK_BINDADDR_LOCK 4 +#define SOCK_BINDPORT_LOCK 8 + +/* sock_iocb: used to kick off async processing of socket ios */ +struct sock_iocb { + struct list_head list; + + int flags; + int size; + struct socket *sock; + struct sock *sk; + struct scm_cookie *scm; + struct msghdr *msg, async_msg; + struct kiocb *kiocb; +}; + +static inline struct sock_iocb *kiocb_to_siocb(struct kiocb *iocb) +{ + return (struct sock_iocb *)iocb->private; +} + +static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si) +{ + return si->kiocb; +} + +struct socket_alloc { + struct socket socket; + struct inode vfs_inode; +}; + +static inline struct socket *SOCKET_I(struct inode *inode) +{ + return &container_of(inode, struct socket_alloc, vfs_inode)->socket; +} + +static inline struct inode *SOCK_INODE(struct socket *socket) +{ + return &container_of(socket, struct socket_alloc, socket)->vfs_inode; +} + +/* + * Functions for memory accounting + */ +extern int __sk_mem_schedule(struct sock *sk, int size, int kind); +extern void __sk_mem_reclaim(struct sock *sk); + +#define SK_MEM_QUANTUM ((int)PAGE_SIZE) +#define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM) +#define SK_MEM_SEND 0 +#define SK_MEM_RECV 1 + +static inline int sk_mem_pages(int amt) +{ + return (amt + SK_MEM_QUANTUM - 1) >> SK_MEM_QUANTUM_SHIFT; +} + +static inline int sk_has_account(struct sock *sk) +{ + /* return true if protocol supports memory accounting */ + return !!sk->sk_prot->memory_allocated; +} + +static inline int sk_wmem_schedule(struct sock *sk, int size) +{ + if (!sk_has_account(sk)) + return 1; + return size <= sk->sk_forward_alloc || + __sk_mem_schedule(sk, size, SK_MEM_SEND); +} + +static inline int sk_rmem_schedule(struct sock *sk, int size) +{ + if (!sk_has_account(sk)) + return 1; + return size <= sk->sk_forward_alloc || + __sk_mem_schedule(sk, size, SK_MEM_RECV); +} + +static inline void sk_mem_reclaim(struct sock *sk) +{ + if (!sk_has_account(sk)) + return; + if (sk->sk_forward_alloc >= SK_MEM_QUANTUM) + __sk_mem_reclaim(sk); +} + +static inline void sk_mem_reclaim_partial(struct sock *sk) +{ + if (!sk_has_account(sk)) + return; + if (sk->sk_forward_alloc > SK_MEM_QUANTUM) + __sk_mem_reclaim(sk); +} + +static inline void sk_mem_charge(struct sock *sk, int size) +{ + if (!sk_has_account(sk)) + return; + sk->sk_forward_alloc -= size; +} + +static inline void sk_mem_uncharge(struct sock *sk, int size) +{ + if (!sk_has_account(sk)) + return; + sk->sk_forward_alloc += size; +} + +static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb) +{ + sock_set_flag(sk, SOCK_QUEUE_SHRUNK); + sk->sk_wmem_queued -= skb->truesize; + sk_mem_uncharge(sk, skb->truesize); + __kfree_skb(skb); +} + +/* Used by processes to "lock" a socket state, so that + * interrupts and bottom half handlers won't change it + * from under us. It essentially blocks any incoming + * packets, so that we won't get any new data or any + * packets that change the state of the socket. + * + * While locked, BH processing will add new packets to + * the backlog queue. This queue is processed by the + * owner of the socket lock right before it is released. + * + * Since ~2.3.5 it is also exclusive sleep lock serializing + * accesses from user process context. + */ +#define sock_owned_by_user(sk) ((sk)->sk_lock.owned) + +/* + * Macro so as to not evaluate some arguments when + * lockdep is not enabled. + * + * Mark both the sk_lock and the sk_lock.slock as a + * per-address-family lock class. + */ +#define sock_lock_init_class_and_name(sk, sname, skey, name, key) \ +do { \ + sk->sk_lock.owned = 0; \ + init_waitqueue_head(&sk->sk_lock.wq); \ + spin_lock_init(&(sk)->sk_lock.slock); \ + debug_check_no_locks_freed((void *)&(sk)->sk_lock, \ + sizeof((sk)->sk_lock)); \ + lockdep_set_class_and_name(&(sk)->sk_lock.slock, \ + (skey), (sname)); \ + lockdep_init_map(&(sk)->sk_lock.dep_map, (name), (key), 0); \ +} while (0) + +extern void lock_sock_nested(struct sock *sk, int subclass); + +static inline void lock_sock(struct sock *sk) +{ + lock_sock_nested(sk, 0); +} + +extern void release_sock(struct sock *sk); + +/* BH context may only use the following locking interface. */ +#define bh_lock_sock(__sk) spin_lock(&((__sk)->sk_lock.slock)) +#define bh_lock_sock_nested(__sk) \ + spin_lock_nested(&((__sk)->sk_lock.slock), \ + SINGLE_DEPTH_NESTING) +#define bh_unlock_sock(__sk) spin_unlock(&((__sk)->sk_lock.slock)) + +extern bool lock_sock_fast(struct sock *sk); +/** + * unlock_sock_fast - complement of lock_sock_fast + * @sk: socket + * @slow: slow mode + * + * fast unlock socket for user context. + * If slow mode is on, we call regular release_sock() + */ +static inline void unlock_sock_fast(struct sock *sk, bool slow) +{ + if (slow) + release_sock(sk); + else + spin_unlock_bh(&sk->sk_lock.slock); +} + + +extern struct sock *sk_alloc(struct net *net, int family, + gfp_t priority, + struct proto *prot); +extern void sk_free(struct sock *sk); +extern void sk_release_kernel(struct sock *sk); +extern struct sock *sk_clone(const struct sock *sk, + const gfp_t priority); + +extern struct sk_buff *sock_wmalloc(struct sock *sk, + unsigned long size, int force, + gfp_t priority); +extern struct sk_buff *sock_rmalloc(struct sock *sk, + unsigned long size, int force, + gfp_t priority); +extern void sock_wfree(struct sk_buff *skb); +extern void sock_rfree(struct sk_buff *skb); + +extern int sock_setsockopt(struct socket *sock, int level, + int op, char __user *optval, + unsigned int optlen); + +extern int sock_getsockopt(struct socket *sock, int level, + int op, char __user *optval, + int __user *optlen); +extern struct sk_buff *sock_alloc_send_skb(struct sock *sk, + unsigned long size, + int noblock, + int *errcode); +extern struct sk_buff *sock_alloc_send_pskb(struct sock *sk, + unsigned long header_len, + unsigned long data_len, + int noblock, + int *errcode); +extern void *sock_kmalloc(struct sock *sk, int size, + gfp_t priority); +extern void sock_kfree_s(struct sock *sk, void *mem, int size); +extern void sk_send_sigurg(struct sock *sk); + +#ifdef CONFIG_CGROUPS +extern void sock_update_classid(struct sock *sk); +#else +static inline void sock_update_classid(struct sock *sk) +{ +} +#endif + +/* + * Functions to fill in entries in struct proto_ops when a protocol + * does not implement a particular function. + */ +extern int sock_no_bind(struct socket *, + struct sockaddr *, int); +extern int sock_no_connect(struct socket *, + struct sockaddr *, int, int); +extern int sock_no_socketpair(struct socket *, + struct socket *); +extern int sock_no_accept(struct socket *, + struct socket *, int); +extern int sock_no_getname(struct socket *, + struct sockaddr *, int *, int); +extern unsigned int sock_no_poll(struct file *, struct socket *, + struct poll_table_struct *); +extern int sock_no_ioctl(struct socket *, unsigned int, + unsigned long); +extern int sock_no_listen(struct socket *, int); +extern int sock_no_shutdown(struct socket *, int); +extern int sock_no_getsockopt(struct socket *, int , int, + char __user *, int __user *); +extern int sock_no_setsockopt(struct socket *, int, int, + char __user *, unsigned int); +extern int sock_no_sendmsg(struct kiocb *, struct socket *, + struct msghdr *, size_t); +extern int sock_no_recvmsg(struct kiocb *, struct socket *, + struct msghdr *, size_t, int); +extern int sock_no_mmap(struct file *file, + struct socket *sock, + struct vm_area_struct *vma); +extern ssize_t sock_no_sendpage(struct socket *sock, + struct page *page, + int offset, size_t size, + int flags); + +/* + * Functions to fill in entries in struct proto_ops when a protocol + * uses the inet style. + */ +extern int sock_common_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen); +extern int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size, int flags); +extern int sock_common_setsockopt(struct socket *sock, int level, int optname, + char __user *optval, unsigned int optlen); +extern int compat_sock_common_getsockopt(struct socket *sock, int level, + int optname, char __user *optval, int __user *optlen); +extern int compat_sock_common_setsockopt(struct socket *sock, int level, + int optname, char __user *optval, unsigned int optlen); + +extern void sk_common_release(struct sock *sk); + +/* + * Default socket callbacks and setup code + */ + +/* Initialise core socket variables */ +extern void sock_init_data(struct socket *sock, struct sock *sk); + +extern void sk_filter_release_rcu(struct rcu_head *rcu); + +/** + * sk_filter_release - release a socket filter + * @fp: filter to remove + * + * Remove a filter from a socket and release its resources. + */ + +static inline void sk_filter_release(struct sk_filter *fp) +{ + if (atomic_dec_and_test(&fp->refcnt)) + call_rcu_bh(&fp->rcu, sk_filter_release_rcu); +} + +static inline void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) +{ + unsigned int size = sk_filter_len(fp); + + atomic_sub(size, &sk->sk_omem_alloc); + sk_filter_release(fp); +} + +static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp) +{ + atomic_inc(&fp->refcnt); + atomic_add(sk_filter_len(fp), &sk->sk_omem_alloc); +} + +/* + * Socket reference counting postulates. + * + * * Each user of socket SHOULD hold a reference count. + * * Each access point to socket (an hash table bucket, reference from a list, + * running timer, skb in flight MUST hold a reference count. + * * When reference count hits 0, it means it will never increase back. + * * When reference count hits 0, it means that no references from + * outside exist to this socket and current process on current CPU + * is last user and may/should destroy this socket. + * * sk_free is called from any context: process, BH, IRQ. When + * it is called, socket has no references from outside -> sk_free + * may release descendant resources allocated by the socket, but + * to the time when it is called, socket is NOT referenced by any + * hash tables, lists etc. + * * Packets, delivered from outside (from network or from another process) + * and enqueued on receive/error queues SHOULD NOT grab reference count, + * when they sit in queue. Otherwise, packets will leak to hole, when + * socket is looked up by one cpu and unhasing is made by another CPU. + * It is true for udp/raw, netlink (leak to receive and error queues), tcp + * (leak to backlog). Packet socket does all the processing inside + * BR_NETPROTO_LOCK, so that it has not this race condition. UNIX sockets + * use separate SMP lock, so that they are prone too. + */ + +/* Ungrab socket and destroy it, if it was the last reference. */ +static inline void sock_put(struct sock *sk) +{ + if (atomic_dec_and_test(&sk->sk_refcnt)) + sk_free(sk); +} + +extern int sk_receive_skb(struct sock *sk, struct sk_buff *skb, + const int nested); + +static inline void sk_tx_queue_set(struct sock *sk, int tx_queue) +{ + sk->sk_tx_queue_mapping = tx_queue; +} + +static inline void sk_tx_queue_clear(struct sock *sk) +{ + sk->sk_tx_queue_mapping = -1; +} + +static inline int sk_tx_queue_get(const struct sock *sk) +{ + return sk ? sk->sk_tx_queue_mapping : -1; +} + +static inline void sk_set_socket(struct sock *sk, struct socket *sock) +{ + sk_tx_queue_clear(sk); + sk->sk_socket = sock; +} + +static inline wait_queue_head_t *sk_sleep(struct sock *sk) +{ + return &sk->sk_wq->wait; +} +/* Detach socket from process context. + * Announce socket dead, detach it from wait queue and inode. + * Note that parent inode held reference count on this struct sock, + * we do not release it in this function, because protocol + * probably wants some additional cleanups or even continuing + * to work with this socket (TCP). + */ +static inline void sock_orphan(struct sock *sk) +{ + write_lock_bh(&sk->sk_callback_lock); + sock_set_flag(sk, SOCK_DEAD); + sk_set_socket(sk, NULL); + sk->sk_wq = NULL; + write_unlock_bh(&sk->sk_callback_lock); +} + +static inline void sock_graft(struct sock *sk, struct socket *parent) +{ + write_lock_bh(&sk->sk_callback_lock); + rcu_assign_pointer(sk->sk_wq, parent->wq); + parent->sk = sk; + sk_set_socket(sk, parent); + security_sock_graft(sk, parent); + write_unlock_bh(&sk->sk_callback_lock); +} + +extern int sock_i_uid(struct sock *sk); +extern unsigned long sock_i_ino(struct sock *sk); + +static inline struct dst_entry * +__sk_dst_get(struct sock *sk) +{ + return rcu_dereference_check(sk->sk_dst_cache, rcu_read_lock_held() || + sock_owned_by_user(sk) || + lockdep_is_held(&sk->sk_lock.slock)); +} + +static inline struct dst_entry * +sk_dst_get(struct sock *sk) +{ + struct dst_entry *dst; + + rcu_read_lock(); + dst = rcu_dereference(sk->sk_dst_cache); + if (dst) + dst_hold(dst); + rcu_read_unlock(); + return dst; +} + +extern void sk_reset_txq(struct sock *sk); + +static inline void dst_negative_advice(struct sock *sk) +{ + struct dst_entry *ndst, *dst = __sk_dst_get(sk); + + if (dst && dst->ops->negative_advice) { + ndst = dst->ops->negative_advice(dst); + + if (ndst != dst) { + rcu_assign_pointer(sk->sk_dst_cache, ndst); + sk_reset_txq(sk); + } + } +} + +static inline void +__sk_dst_set(struct sock *sk, struct dst_entry *dst) +{ + struct dst_entry *old_dst; + + sk_tx_queue_clear(sk); + /* + * This can be called while sk is owned by the caller only, + * with no state that can be checked in a rcu_dereference_check() cond + */ + old_dst = rcu_dereference_raw(sk->sk_dst_cache); + rcu_assign_pointer(sk->sk_dst_cache, dst); + dst_release(old_dst); +} + +static inline void +sk_dst_set(struct sock *sk, struct dst_entry *dst) +{ + spin_lock(&sk->sk_dst_lock); + __sk_dst_set(sk, dst); + spin_unlock(&sk->sk_dst_lock); +} + +static inline void +__sk_dst_reset(struct sock *sk) +{ + __sk_dst_set(sk, NULL); +} + +static inline void +sk_dst_reset(struct sock *sk) +{ + spin_lock(&sk->sk_dst_lock); + __sk_dst_reset(sk); + spin_unlock(&sk->sk_dst_lock); +} + +extern struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie); + +extern struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie); + +static inline int sk_can_gso(const struct sock *sk) +{ + return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type); +} + +extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst); + +static inline void sk_nocaps_add(struct sock *sk, int flags) +{ + sk->sk_route_nocaps |= flags; + sk->sk_route_caps &= ~flags; +} + +static inline int skb_copy_to_page(struct sock *sk, char __user *from, + struct sk_buff *skb, struct page *page, + int off, int copy) +{ + if (skb->ip_summed == CHECKSUM_NONE) { + int err = 0; + __wsum csum = csum_and_copy_from_user(from, + page_address(page) + off, + copy, 0, &err); + if (err) + return err; + skb->csum = csum_block_add(skb->csum, csum, skb->len); + } else if (copy_from_user(page_address(page) + off, from, copy)) + return -EFAULT; + + skb->len += copy; + skb->data_len += copy; + skb->truesize += copy; + sk->sk_wmem_queued += copy; + sk_mem_charge(sk, copy); + return 0; +} + +/** + * sk_wmem_alloc_get - returns write allocations + * @sk: socket + * + * Returns sk_wmem_alloc minus initial offset of one + */ +static inline int sk_wmem_alloc_get(const struct sock *sk) +{ + return atomic_read(&sk->sk_wmem_alloc) - 1; +} + +/** + * sk_rmem_alloc_get - returns read allocations + * @sk: socket + * + * Returns sk_rmem_alloc + */ +static inline int sk_rmem_alloc_get(const struct sock *sk) +{ + return atomic_read(&sk->sk_rmem_alloc); +} + +/** + * sk_has_allocations - check if allocations are outstanding + * @sk: socket + * + * Returns true if socket has write or read allocations + */ +static inline int sk_has_allocations(const struct sock *sk) +{ + return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk); +} + +/** + * wq_has_sleeper - check if there are any waiting processes + * @wq: struct socket_wq + * + * Returns true if socket_wq has waiting processes + * + * The purpose of the wq_has_sleeper and sock_poll_wait is to wrap the memory + * barrier call. They were added due to the race found within the tcp code. + * + * Consider following tcp code paths: + * + * CPU1 CPU2 + * + * sys_select receive packet + * ... ... + * __add_wait_queue update tp->rcv_nxt + * ... ... + * tp->rcv_nxt check sock_def_readable + * ... { + * schedule rcu_read_lock(); + * wq = rcu_dereference(sk->sk_wq); + * if (wq && waitqueue_active(&wq->wait)) + * wake_up_interruptible(&wq->wait) + * ... + * } + * + * The race for tcp fires when the __add_wait_queue changes done by CPU1 stay + * in its cache, and so does the tp->rcv_nxt update on CPU2 side. The CPU1 + * could then endup calling schedule and sleep forever if there are no more + * data on the socket. + * + */ +static inline bool wq_has_sleeper(struct socket_wq *wq) +{ + + /* + * We need to be sure we are in sync with the + * add_wait_queue modifications to the wait queue. + * + * This memory barrier is paired in the sock_poll_wait. + */ + smp_mb(); + return wq && waitqueue_active(&wq->wait); +} + +/** + * sock_poll_wait - place memory barrier behind the poll_wait call. + * @filp: file + * @wait_address: socket wait queue + * @p: poll_table + * + * See the comments in the wq_has_sleeper function. + */ +static inline void sock_poll_wait(struct file *filp, + wait_queue_head_t *wait_address, poll_table *p) +{ + if (p && wait_address) { + poll_wait(filp, wait_address, p); + /* + * We need to be sure we are in sync with the + * socket flags modification. + * + * This memory barrier is paired in the wq_has_sleeper. + */ + smp_mb(); + } +} + +/* + * Queue a received datagram if it will fit. Stream and sequenced + * protocols can't normally use this as they need to fit buffers in + * and play with them. + * + * Inlined as it's very short and called for pretty much every + * packet ever received. + */ + +static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) +{ + skb_orphan(skb); + skb->sk = sk; + skb->destructor = sock_wfree; + /* + * We used to take a refcount on sk, but following operation + * is enough to guarantee sk_free() wont free this sock until + * all in-flight packets are completed + */ + atomic_add(skb->truesize, &sk->sk_wmem_alloc); +} + +static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) +{ + skb_orphan(skb); + skb->sk = sk; + skb->destructor = sock_rfree; + atomic_add(skb->truesize, &sk->sk_rmem_alloc); + sk_mem_charge(sk, skb->truesize); +} + +extern void sk_reset_timer(struct sock *sk, struct timer_list* timer, + unsigned long expires); + +extern void sk_stop_timer(struct sock *sk, struct timer_list* timer); + +extern int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); + +extern int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb); + +/* + * Recover an error report and clear atomically + */ + +static inline int sock_error(struct sock *sk) +{ + int err; + if (likely(!sk->sk_err)) + return 0; + err = xchg(&sk->sk_err, 0); + return -err; +} + +static inline unsigned long sock_wspace(struct sock *sk) +{ + int amt = 0; + + if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { + amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + if (amt < 0) + amt = 0; + } + return amt; +} + +static inline void sk_wake_async(struct sock *sk, int how, int band) +{ + if (sock_flag(sk, SOCK_FASYNC)) + sock_wake_async(sk->sk_socket, how, band); +} + +#define SOCK_MIN_SNDBUF 2048 +#define SOCK_MIN_RCVBUF 256 + +static inline void sk_stream_moderate_sndbuf(struct sock *sk) +{ + if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) { + sk->sk_sndbuf = min(sk->sk_sndbuf, sk->sk_wmem_queued >> 1); + sk->sk_sndbuf = max(sk->sk_sndbuf, SOCK_MIN_SNDBUF); + } +} + +struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp); + +static inline struct page *sk_stream_alloc_page(struct sock *sk) +{ + struct page *page = NULL; + + page = alloc_pages(sk->sk_allocation, 0); + if (!page) { + sk->sk_prot->enter_memory_pressure(sk); + sk_stream_moderate_sndbuf(sk); + } + return page; +} + +/* + * Default write policy as shown to user space via poll/select/SIGIO + */ +static inline int sock_writeable(const struct sock *sk) +{ + return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf >> 1); +} + +static inline gfp_t gfp_any(void) +{ + return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; +} + +static inline long sock_rcvtimeo(const struct sock *sk, int noblock) +{ + return noblock ? 0 : sk->sk_rcvtimeo; +} + +static inline long sock_sndtimeo(const struct sock *sk, int noblock) +{ + return noblock ? 0 : sk->sk_sndtimeo; +} + +static inline int sock_rcvlowat(const struct sock *sk, int waitall, int len) +{ + return (waitall ? len : min_t(int, sk->sk_rcvlowat, len)) ? : 1; +} + +/* Alas, with timeout socket operations are not restartable. + * Compare this to poll(). + */ +static inline int sock_intr_errno(long timeo) +{ + return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR; +} + +extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb); + +static __inline__ void +sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) +{ + ktime_t kt = skb->tstamp; + struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); + + /* + * generate control messages if + * - receive time stamping in software requested (SOCK_RCVTSTAMP + * or SOCK_TIMESTAMPING_RX_SOFTWARE) + * - software time stamp available and wanted + * (SOCK_TIMESTAMPING_SOFTWARE) + * - hardware time stamps available and wanted + * (SOCK_TIMESTAMPING_SYS_HARDWARE or + * SOCK_TIMESTAMPING_RAW_HARDWARE) + */ + if (sock_flag(sk, SOCK_RCVTSTAMP) || + sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) || + (kt.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) || + (hwtstamps->hwtstamp.tv64 && + sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)) || + (hwtstamps->syststamp.tv64 && + sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE))) + __sock_recv_timestamp(msg, sk, skb); + else + sk->sk_stamp = kt; +} + +extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb); + +static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb) +{ +#define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL) | \ + (1UL << SOCK_RCVTSTAMP) | \ + (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE) | \ + (1UL << SOCK_TIMESTAMPING_SOFTWARE) | \ + (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE) | \ + (1UL << SOCK_TIMESTAMPING_SYS_HARDWARE)) + + if (sk->sk_flags & FLAGS_TS_OR_DROPS) + __sock_recv_ts_and_drops(msg, sk, skb); + else + sk->sk_stamp = skb->tstamp; +} + +/** + * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped + * @msg: outgoing packet + * @sk: socket sending this packet + * @shtx: filled with instructions for time stamping + * + * Currently only depends on SOCK_TIMESTAMPING* flags. Returns error code if + * parameters are invalid. + */ +extern int sock_tx_timestamp(struct msghdr *msg, + struct sock *sk, + union skb_shared_tx *shtx); + + +/** + * sk_eat_skb - Release a skb if it is no longer needed + * @sk: socket to eat this skb from + * @skb: socket buffer to eat + * @copied_early: flag indicating whether DMA operations copied this data early + * + * This routine must be called with interrupts disabled or with the socket + * locked so that the sk_buff queue operation is ok. +*/ +#ifdef CONFIG_NET_DMA +static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_early) +{ + __skb_unlink(skb, &sk->sk_receive_queue); + if (!copied_early) + __kfree_skb(skb); + else + __skb_queue_tail(&sk->sk_async_wait_queue, skb); +} +#else +static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_early) +{ + __skb_unlink(skb, &sk->sk_receive_queue); + __kfree_skb(skb); +} +#endif + +static inline +struct net *sock_net(const struct sock *sk) +{ + return read_pnet(&sk->sk_net); +} + +static inline +void sock_net_set(struct sock *sk, struct net *net) +{ + write_pnet(&sk->sk_net, net); +} + +/* + * Kernel sockets, f.e. rtnl or icmp_socket, are a part of a namespace. + * They should not hold a referrence to a namespace in order to allow + * to stop it. + * Sockets after sk_change_net should be released using sk_release_kernel + */ +static inline void sk_change_net(struct sock *sk, struct net *net) +{ + put_net(sock_net(sk)); + sock_net_set(sk, hold_net(net)); +} + +static inline struct sock *skb_steal_sock(struct sk_buff *skb) +{ + if (unlikely(skb->sk)) { + struct sock *sk = skb->sk; + + skb->destructor = NULL; + skb->sk = NULL; + return sk; + } + return NULL; +} + +extern void sock_enable_timestamp(struct sock *sk, int flag); +extern int sock_get_timestamp(struct sock *, struct timeval __user *); +extern int sock_get_timestampns(struct sock *, struct timespec __user *); + +/* + * Enable debug/info messages + */ +extern int net_msg_warn; +#define NETDEBUG(fmt, args...) \ + do { if (net_msg_warn) printk(fmt,##args); } while (0) + +#define LIMIT_NETDEBUG(fmt, args...) \ + do { if (net_msg_warn && net_ratelimit()) printk(fmt,##args); } while(0) + +extern __u32 sysctl_wmem_max; +extern __u32 sysctl_rmem_max; + +extern void sk_init(void); + +extern int sysctl_optmem_max; + +extern __u32 sysctl_wmem_default; +extern __u32 sysctl_rmem_default; + +#endif /* _SOCK_H */ diff --git a/include/net/stp.h b/include/net/stp.h new file mode 100644 index 00000000..ad447f10 --- /dev/null +++ b/include/net/stp.h @@ -0,0 +1,14 @@ +#ifndef _NET_STP_H +#define _NET_STP_H + +struct stp_proto { + unsigned char group_address[ETH_ALEN]; + void (*rcv)(const struct stp_proto *, struct sk_buff *, + struct net_device *); + void *data; +}; + +extern int stp_proto_register(const struct stp_proto *proto); +extern void stp_proto_unregister(const struct stp_proto *proto); + +#endif /* _NET_STP_H */ diff --git a/include/net/tc_act/tc_defact.h b/include/net/tc_act/tc_defact.h new file mode 100644 index 00000000..65f024b8 --- /dev/null +++ b/include/net/tc_act/tc_defact.h @@ -0,0 +1,14 @@ +#ifndef __NET_TC_DEF_H +#define __NET_TC_DEF_H + +#include <net/act_api.h> + +struct tcf_defact { + struct tcf_common common; + u32 tcfd_datalen; + void *tcfd_defdata; +}; +#define to_defact(pc) \ + container_of(pc, struct tcf_defact, common) + +#endif /* __NET_TC_DEF_H */ diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h new file mode 100644 index 00000000..9e3f6767 --- /dev/null +++ b/include/net/tc_act/tc_gact.h @@ -0,0 +1,17 @@ +#ifndef __NET_TC_GACT_H +#define __NET_TC_GACT_H + +#include <net/act_api.h> + +struct tcf_gact { + struct tcf_common common; +#ifdef CONFIG_GACT_PROB + u16 tcfg_ptype; + u16 tcfg_pval; + int tcfg_paction; +#endif +}; +#define to_gact(pc) \ + container_of(pc, struct tcf_gact, common) + +#endif /* __NET_TC_GACT_H */ diff --git a/include/net/tc_act/tc_ipt.h b/include/net/tc_act/tc_ipt.h new file mode 100644 index 00000000..f7d25dfc --- /dev/null +++ b/include/net/tc_act/tc_ipt.h @@ -0,0 +1,17 @@ +#ifndef __NET_TC_IPT_H +#define __NET_TC_IPT_H + +#include <net/act_api.h> + +struct xt_entry_target; + +struct tcf_ipt { + struct tcf_common common; + u32 tcfi_hook; + char *tcfi_tname; + struct xt_entry_target *tcfi_t; +}; +#define to_ipt(pc) \ + container_of(pc, struct tcf_ipt, common) + +#endif /* __NET_TC_IPT_H */ diff --git a/include/net/tc_act/tc_mirred.h b/include/net/tc_act/tc_mirred.h new file mode 100644 index 00000000..cfe29436 --- /dev/null +++ b/include/net/tc_act/tc_mirred.h @@ -0,0 +1,17 @@ +#ifndef __NET_TC_MIR_H +#define __NET_TC_MIR_H + +#include <net/act_api.h> + +struct tcf_mirred { + struct tcf_common common; + int tcfm_eaction; + int tcfm_ifindex; + int tcfm_ok_push; + struct net_device *tcfm_dev; + struct list_head tcfm_list; +}; +#define to_mirred(pc) \ + container_of(pc, struct tcf_mirred, common) + +#endif /* __NET_TC_MIR_H */ diff --git a/include/net/tc_act/tc_nat.h b/include/net/tc_act/tc_nat.h new file mode 100644 index 00000000..4a691f34 --- /dev/null +++ b/include/net/tc_act/tc_nat.h @@ -0,0 +1,21 @@ +#ifndef __NET_TC_NAT_H +#define __NET_TC_NAT_H + +#include <linux/types.h> +#include <net/act_api.h> + +struct tcf_nat { + struct tcf_common common; + + __be32 old_addr; + __be32 new_addr; + __be32 mask; + u32 flags; +}; + +static inline struct tcf_nat *to_tcf_nat(struct tcf_common *pc) +{ + return container_of(pc, struct tcf_nat, common); +} + +#endif /* __NET_TC_NAT_H */ diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h new file mode 100644 index 00000000..e6f6e159 --- /dev/null +++ b/include/net/tc_act/tc_pedit.h @@ -0,0 +1,15 @@ +#ifndef __NET_TC_PED_H +#define __NET_TC_PED_H + +#include <net/act_api.h> + +struct tcf_pedit { + struct tcf_common common; + unsigned char tcfp_nkeys; + unsigned char tcfp_flags; + struct tc_pedit_key *tcfp_keys; +}; +#define to_pedit(pc) \ + container_of(pc, struct tcf_pedit, common) + +#endif /* __NET_TC_PED_H */ diff --git a/include/net/tc_act/tc_skbedit.h b/include/net/tc_act/tc_skbedit.h new file mode 100644 index 00000000..e103fe02 --- /dev/null +++ b/include/net/tc_act/tc_skbedit.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Author: Alexander Duyck <alexander.h.duyck@intel.com> + */ + +#ifndef __NET_TC_SKBEDIT_H +#define __NET_TC_SKBEDIT_H + +#include <net/act_api.h> + +struct tcf_skbedit { + struct tcf_common common; + u32 flags; + u32 priority; + u32 mark; + u16 queue_mapping; + /* XXX: 16-bit pad here? */ +}; +#define to_skbedit(pc) \ + container_of(pc, struct tcf_skbedit, common) + +#endif /* __NET_TC_SKBEDIT_H */ diff --git a/include/net/tcp.h b/include/net/tcp.h new file mode 100644 index 00000000..3e4b33e3 --- /dev/null +++ b/include/net/tcp.h @@ -0,0 +1,1531 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the TCP module. + * + * Version: @(#)tcp.h 1.0.5 05/23/93 + * + * Authors: Ross Biro + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _TCP_H +#define _TCP_H + +#define TCP_DEBUG 1 +#define FASTRETRANS_DEBUG 1 + +#include <linux/list.h> +#include <linux/tcp.h> +#include <linux/slab.h> +#include <linux/cache.h> +#include <linux/percpu.h> +#include <linux/skbuff.h> +#include <linux/dmaengine.h> +#include <linux/crypto.h> +#include <linux/cryptohash.h> +#include <linux/kref.h> + +#include <net/inet_connection_sock.h> +#include <net/inet_timewait_sock.h> +#include <net/inet_hashtables.h> +#include <net/checksum.h> +#include <net/request_sock.h> +#include <net/sock.h> +#include <net/snmp.h> +#include <net/ip.h> +#include <net/tcp_states.h> +#include <net/inet_ecn.h> +#include <net/dst.h> + +#include <linux/seq_file.h> + +extern struct inet_hashinfo tcp_hashinfo; + +extern struct percpu_counter tcp_orphan_count; +extern void tcp_time_wait(struct sock *sk, int state, int timeo); + +#define MAX_TCP_HEADER (128 + MAX_HEADER) +#define MAX_TCP_OPTION_SPACE 40 + +/* + * Never offer a window over 32767 without using window scaling. Some + * poor stacks do signed 16bit maths! + */ +#define MAX_TCP_WINDOW 32767U + +/* Minimal accepted MSS. It is (60+60+8) - (20+20). */ +#define TCP_MIN_MSS 88U + +/* The least MTU to use for probing */ +#define TCP_BASE_MSS 512 + +/* After receiving this amount of duplicate ACKs fast retransmit starts. */ +#define TCP_FASTRETRANS_THRESH 3 + +/* Maximal reordering. */ +#define TCP_MAX_REORDERING 127 + +/* Maximal number of ACKs sent quickly to accelerate slow-start. */ +#define TCP_MAX_QUICKACKS 16U + +/* urg_data states */ +#define TCP_URG_VALID 0x0100 +#define TCP_URG_NOTYET 0x0200 +#define TCP_URG_READ 0x0400 + +#define TCP_RETR1 3 /* + * This is how many retries it does before it + * tries to figure out if the gateway is + * down. Minimal RFC value is 3; it corresponds + * to ~3sec-8min depending on RTO. + */ + +#define TCP_RETR2 15 /* + * This should take at least + * 90 minutes to time out. + * RFC1122 says that the limit is 100 sec. + * 15 is ~13-30min depending on RTO. + */ + +#define TCP_SYN_RETRIES 5 /* number of times to retry active opening a + * connection: ~180sec is RFC minimum */ + +#define TCP_SYNACK_RETRIES 5 /* number of times to retry passive opening a + * connection: ~180sec is RFC minimum */ + + +#define TCP_ORPHAN_RETRIES 7 /* number of times to retry on an orphaned + * socket. 7 is ~50sec-16min. + */ + + +#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT + * state, about 60 seconds */ +#define TCP_FIN_TIMEOUT TCP_TIMEWAIT_LEN + /* BSD style FIN_WAIT2 deadlock breaker. + * It used to be 3min, new value is 60sec, + * to combine FIN-WAIT-2 timeout with + * TIME-WAIT timer. + */ + +#define TCP_DELACK_MAX ((unsigned)(HZ/5)) /* maximal time to delay before sending an ACK */ +#if HZ >= 100 +#define TCP_DELACK_MIN ((unsigned)(HZ/25)) /* minimal time to delay before sending an ACK */ +#define TCP_ATO_MIN ((unsigned)(HZ/25)) +#else +#define TCP_DELACK_MIN 4U +#define TCP_ATO_MIN 4U +#endif +#define TCP_RTO_MAX ((unsigned)(120*HZ)) +#define TCP_RTO_MIN ((unsigned)(HZ/5)) +#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value */ + +#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes + * for local resources. + */ + +#define TCP_KEEPALIVE_TIME (120*60*HZ) /* two hours */ +#define TCP_KEEPALIVE_PROBES 9 /* Max of 9 keepalive probes */ +#define TCP_KEEPALIVE_INTVL (75*HZ) + +#define MAX_TCP_KEEPIDLE 32767 +#define MAX_TCP_KEEPINTVL 32767 +#define MAX_TCP_KEEPCNT 127 +#define MAX_TCP_SYNCNT 127 + +#define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ + +#define TCP_PAWS_24DAYS (60 * 60 * 24 * 24) +#define TCP_PAWS_MSL 60 /* Per-host timestamps are invalidated + * after this time. It should be equal + * (or greater than) TCP_TIMEWAIT_LEN + * to provide reliability equal to one + * provided by timewait state. + */ +#define TCP_PAWS_WINDOW 1 /* Replay window for per-host + * timestamps. It must be less than + * minimal timewait lifetime. + */ +/* + * TCP option + */ + +#define TCPOPT_NOP 1 /* Padding */ +#define TCPOPT_EOL 0 /* End of options */ +#define TCPOPT_MSS 2 /* Segment size negotiating */ +#define TCPOPT_WINDOW 3 /* Window scaling */ +#define TCPOPT_SACK_PERM 4 /* SACK Permitted */ +#define TCPOPT_SACK 5 /* SACK Block */ +#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ +#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ +#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */ + +/* + * TCP option lengths + */ + +#define TCPOLEN_MSS 4 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_SACK_PERM 2 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_MD5SIG 18 +#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */ +#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */ +#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN) +#define TCPOLEN_COOKIE_MAX (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX) + +/* But this is what stacks really send out. */ +#define TCPOLEN_TSTAMP_ALIGNED 12 +#define TCPOLEN_WSCALE_ALIGNED 4 +#define TCPOLEN_SACKPERM_ALIGNED 4 +#define TCPOLEN_SACK_BASE 2 +#define TCPOLEN_SACK_BASE_ALIGNED 4 +#define TCPOLEN_SACK_PERBLOCK 8 +#define TCPOLEN_MD5SIG_ALIGNED 20 +#define TCPOLEN_MSS_ALIGNED 4 + +/* Flags in tp->nonagle */ +#define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ +#define TCP_NAGLE_CORK 2 /* Socket is corked */ +#define TCP_NAGLE_PUSH 4 /* Cork is overridden for already queued data */ + +/* TCP thin-stream limits */ +#define TCP_THIN_LINEAR_RETRIES 6 /* After 6 linear retries, do exp. backoff */ + +extern struct inet_timewait_death_row tcp_death_row; + +/* sysctl variables for tcp */ +extern int sysctl_tcp_timestamps; +extern int sysctl_tcp_window_scaling; +extern int sysctl_tcp_sack; +extern int sysctl_tcp_fin_timeout; +extern int sysctl_tcp_keepalive_time; +extern int sysctl_tcp_keepalive_probes; +extern int sysctl_tcp_keepalive_intvl; +extern int sysctl_tcp_syn_retries; +extern int sysctl_tcp_synack_retries; +extern int sysctl_tcp_retries1; +extern int sysctl_tcp_retries2; +extern int sysctl_tcp_orphan_retries; +extern int sysctl_tcp_syncookies; +extern int sysctl_tcp_retrans_collapse; +extern int sysctl_tcp_stdurg; +extern int sysctl_tcp_rfc1337; +extern int sysctl_tcp_abort_on_overflow; +extern int sysctl_tcp_max_orphans; +extern int sysctl_tcp_fack; +extern int sysctl_tcp_reordering; +extern int sysctl_tcp_ecn; +extern int sysctl_tcp_dsack; +extern int sysctl_tcp_mem[3]; +extern int sysctl_tcp_wmem[3]; +extern int sysctl_tcp_rmem[3]; +extern int sysctl_tcp_app_win; +extern int sysctl_tcp_adv_win_scale; +extern int sysctl_tcp_tw_reuse; +extern int sysctl_tcp_frto; +extern int sysctl_tcp_frto_response; +extern int sysctl_tcp_low_latency; +extern int sysctl_tcp_dma_copybreak; +extern int sysctl_tcp_nometrics_save; +extern int sysctl_tcp_moderate_rcvbuf; +extern int sysctl_tcp_tso_win_divisor; +extern int sysctl_tcp_abc; +extern int sysctl_tcp_mtu_probing; +extern int sysctl_tcp_base_mss; +extern int sysctl_tcp_workaround_signed_windows; +extern int sysctl_tcp_slow_start_after_idle; +extern int sysctl_tcp_max_ssthresh; +extern int sysctl_tcp_cookie_size; +extern int sysctl_tcp_thin_linear_timeouts; +extern int sysctl_tcp_thin_dupack; + +extern atomic_t tcp_memory_allocated; +extern struct percpu_counter tcp_sockets_allocated; +extern int tcp_memory_pressure; + +/* + * The next routines deal with comparing 32 bit unsigned ints + * and worry about wraparound (automatic with unsigned arithmetic). + */ + +static inline int before(__u32 seq1, __u32 seq2) +{ + return (__s32)(seq1-seq2) < 0; +} +#define after(seq2, seq1) before(seq1, seq2) + +/* is s2<=s1<=s3 ? */ +static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) +{ + return seq3 - seq2 >= seq1 - seq2; +} + +static inline bool tcp_too_many_orphans(struct sock *sk, int shift) +{ + struct percpu_counter *ocp = sk->sk_prot->orphan_count; + int orphans = percpu_counter_read_positive(ocp); + + if (orphans << shift > sysctl_tcp_max_orphans) { + orphans = percpu_counter_sum_positive(ocp); + if (orphans << shift > sysctl_tcp_max_orphans) + return true; + } + + if (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && + atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]) + return true; + return false; +} + +/* syncookies: remember time of last synqueue overflow */ +static inline void tcp_synq_overflow(struct sock *sk) +{ + tcp_sk(sk)->rx_opt.ts_recent_stamp = jiffies; +} + +/* syncookies: no recent synqueue overflow on this listening socket? */ +static inline int tcp_synq_no_recent_overflow(const struct sock *sk) +{ + unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp; + return time_after(jiffies, last_overflow + TCP_TIMEOUT_INIT); +} + +extern struct proto tcp_prot; + +#define TCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.tcp_statistics, field) +#define TCP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.tcp_statistics, field) +#define TCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mib.tcp_statistics, field) +#define TCP_ADD_STATS_USER(net, field, val) SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val) +#define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val) + +extern void tcp_v4_err(struct sk_buff *skb, u32); + +extern void tcp_shutdown (struct sock *sk, int how); + +extern int tcp_v4_rcv(struct sk_buff *skb); + +extern int tcp_v4_remember_stamp(struct sock *sk); +extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); +extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t size); +extern int tcp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags); +extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); +extern int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, + struct tcphdr *th, unsigned len); +extern int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, + struct tcphdr *th, unsigned len); +extern void tcp_rcv_space_adjust(struct sock *sk); +extern void tcp_cleanup_rbuf(struct sock *sk, int copied); +extern int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); +extern void tcp_twsk_destructor(struct sock *sk); +extern ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); + +static inline void tcp_dec_quickack_mode(struct sock *sk, + const unsigned int pkts) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + + if (icsk->icsk_ack.quick) { + if (pkts >= icsk->icsk_ack.quick) { + icsk->icsk_ack.quick = 0; + /* Leaving quickack mode we deflate ATO. */ + icsk->icsk_ack.ato = TCP_ATO_MIN; + } else + icsk->icsk_ack.quick -= pkts; + } +} + +extern void tcp_enter_quickack_mode(struct sock *sk); + +#define TCP_ECN_OK 1 +#define TCP_ECN_QUEUE_CWR 2 +#define TCP_ECN_DEMAND_CWR 4 + +static __inline__ void +TCP_ECN_create_request(struct request_sock *req, struct tcphdr *th) +{ + if (sysctl_tcp_ecn && th->ece && th->cwr) + inet_rsk(req)->ecn_ok = 1; +} + +enum tcp_tw_status { + TCP_TW_SUCCESS = 0, + TCP_TW_RST = 1, + TCP_TW_ACK = 2, + TCP_TW_SYN = 3 +}; + + +extern enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw, + struct sk_buff *skb, + const struct tcphdr *th); +extern struct sock * tcp_check_req(struct sock *sk,struct sk_buff *skb, + struct request_sock *req, + struct request_sock **prev); +extern int tcp_child_process(struct sock *parent, struct sock *child, + struct sk_buff *skb); +extern int tcp_use_frto(struct sock *sk); +extern void tcp_enter_frto(struct sock *sk); +extern void tcp_enter_loss(struct sock *sk, int how); +extern void tcp_clear_retrans(struct tcp_sock *tp); +extern void tcp_update_metrics(struct sock *sk); +extern void tcp_close(struct sock *sk, long timeout); +extern unsigned int tcp_poll(struct file * file, struct socket *sock, + struct poll_table_struct *wait); +extern int tcp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +extern int tcp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, unsigned int optlen); +extern int compat_tcp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +extern int compat_tcp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, unsigned int optlen); +extern void tcp_set_keepalive(struct sock *sk, int val); +extern void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req); +extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int nonblock, int flags, int *addr_len); +extern void tcp_parse_options(struct sk_buff *skb, + struct tcp_options_received *opt_rx, u8 **hvpp, + int estab); +extern u8 *tcp_parse_md5sig_option(struct tcphdr *th); + +/* + * TCP v4 functions exported for the inet6 API + */ + +extern void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); +extern int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); +extern struct sock * tcp_create_openreq_child(struct sock *sk, + struct request_sock *req, + struct sk_buff *skb); +extern struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, + struct request_sock *req, + struct dst_entry *dst); +extern int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb); +extern int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, + int addr_len); +extern int tcp_connect(struct sock *sk); +extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, + struct request_sock *req, + struct request_values *rvp); +extern int tcp_disconnect(struct sock *sk, int flags); + + +/* From syncookies.c */ +extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; +extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, + struct ip_options *opt); +extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, + __u16 *mss); + +extern __u32 cookie_init_timestamp(struct request_sock *req); +extern bool cookie_check_timestamp(struct tcp_options_received *opt, bool *); + +/* From net/ipv6/syncookies.c */ +extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); +extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, + __u16 *mss); + +/* tcp_output.c */ + +extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, + int nonagle); +extern int tcp_may_send_now(struct sock *sk); +extern int tcp_retransmit_skb(struct sock *, struct sk_buff *); +extern void tcp_retransmit_timer(struct sock *sk); +extern void tcp_xmit_retransmit_queue(struct sock *); +extern void tcp_simple_retransmit(struct sock *); +extern int tcp_trim_head(struct sock *, struct sk_buff *, u32); +extern int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int); + +extern void tcp_send_probe0(struct sock *); +extern void tcp_send_partial(struct sock *); +extern int tcp_write_wakeup(struct sock *); +extern void tcp_send_fin(struct sock *sk); +extern void tcp_send_active_reset(struct sock *sk, gfp_t priority); +extern int tcp_send_synack(struct sock *); +extern void tcp_push_one(struct sock *, unsigned int mss_now); +extern void tcp_send_ack(struct sock *sk); +extern void tcp_send_delayed_ack(struct sock *sk); + +/* tcp_input.c */ +extern void tcp_cwnd_application_limited(struct sock *sk); + +/* tcp_timer.c */ +extern void tcp_init_xmit_timers(struct sock *); +static inline void tcp_clear_xmit_timers(struct sock *sk) +{ + inet_csk_clear_xmit_timers(sk); +} + +extern unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu); +extern unsigned int tcp_current_mss(struct sock *sk); + +/* Bound MSS / TSO packet size with the half of the window */ +static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) +{ + int cutoff; + + /* When peer uses tiny windows, there is no use in packetizing + * to sub-MSS pieces for the sake of SWS or making sure there + * are enough packets in the pipe for fast recovery. + * + * On the other hand, for extremely large MSS devices, handling + * smaller than MSS windows in this way does make sense. + */ + if (tp->max_window >= 512) + cutoff = (tp->max_window >> 1); + else + cutoff = tp->max_window; + + if (cutoff && pktsize > cutoff) + return max_t(int, cutoff, 68U - tp->tcp_header_len); + else + return pktsize; +} + +/* tcp.c */ +extern void tcp_get_info(struct sock *, struct tcp_info *); + +/* Read 'sendfile()'-style from a TCP socket */ +typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, + unsigned int, size_t); +extern int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor); + +extern void tcp_initialize_rcv_mss(struct sock *sk); + +extern int tcp_mtu_to_mss(struct sock *sk, int pmtu); +extern int tcp_mss_to_mtu(struct sock *sk, int mss); +extern void tcp_mtup_init(struct sock *sk); + +static inline void tcp_bound_rto(const struct sock *sk) +{ + if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX) + inet_csk(sk)->icsk_rto = TCP_RTO_MAX; +} + +static inline u32 __tcp_set_rto(const struct tcp_sock *tp) +{ + return (tp->srtt >> 3) + tp->rttvar; +} + +static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd) +{ + tp->pred_flags = htonl((tp->tcp_header_len << 26) | + ntohl(TCP_FLAG_ACK) | + snd_wnd); +} + +static inline void tcp_fast_path_on(struct tcp_sock *tp) +{ + __tcp_fast_path_on(tp, tp->snd_wnd >> tp->rx_opt.snd_wscale); +} + +static inline void tcp_fast_path_check(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (skb_queue_empty(&tp->out_of_order_queue) && + tp->rcv_wnd && + atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && + !tp->urg_data) + tcp_fast_path_on(tp); +} + +/* Compute the actual rto_min value */ +static inline u32 tcp_rto_min(struct sock *sk) +{ + struct dst_entry *dst = __sk_dst_get(sk); + u32 rto_min = TCP_RTO_MIN; + + if (dst && dst_metric_locked(dst, RTAX_RTO_MIN)) + rto_min = dst_metric_rtt(dst, RTAX_RTO_MIN); + return rto_min; +} + +/* Compute the actual receive window we are currently advertising. + * Rcv_nxt can be after the window if our peer push more data + * than the offered window. + */ +static inline u32 tcp_receive_window(const struct tcp_sock *tp) +{ + s32 win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt; + + if (win < 0) + win = 0; + return (u32) win; +} + +/* Choose a new window, without checks for shrinking, and without + * scaling applied to the result. The caller does these things + * if necessary. This is a "raw" window selection. + */ +extern u32 __tcp_select_window(struct sock *sk); + +/* TCP timestamps are only 32-bits, this causes a slight + * complication on 64-bit systems since we store a snapshot + * of jiffies in the buffer control blocks below. We decided + * to use only the low 32-bits of jiffies and hide the ugly + * casts with the following macro. + */ +#define tcp_time_stamp ((__u32)(jiffies)) + +#define tcp_flag_byte(th) (((u_int8_t *)th)[13]) + +#define TCPHDR_FIN 0x01 +#define TCPHDR_SYN 0x02 +#define TCPHDR_RST 0x04 +#define TCPHDR_PSH 0x08 +#define TCPHDR_ACK 0x10 +#define TCPHDR_URG 0x20 +#define TCPHDR_ECE 0x40 +#define TCPHDR_CWR 0x80 + +/* This is what the send packet queuing engine uses to pass + * TCP per-packet control information to the transmission code. + * We also store the host-order sequence numbers in here too. + * This is 44 bytes if IPV6 is enabled. + * If this grows please adjust skbuff.h:skbuff->cb[xxx] size appropriately. + */ +struct tcp_skb_cb { + union { + struct inet_skb_parm h4; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + struct inet6_skb_parm h6; +#endif + } header; /* For incoming frames */ + __u32 seq; /* Starting sequence number */ + __u32 end_seq; /* SEQ + FIN + SYN + datalen */ + __u32 when; /* used to compute rtt's */ + __u8 flags; /* TCP header flags. */ + __u8 sacked; /* State flags for SACK/FACK. */ +#define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block */ +#define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */ +#define TCPCB_LOST 0x04 /* SKB is lost */ +#define TCPCB_TAGBITS 0x07 /* All tag bits */ + +#define TCPCB_EVER_RETRANS 0x80 /* Ever retransmitted frame */ +#define TCPCB_RETRANS (TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS) + + __u32 ack_seq; /* Sequence number ACK'd */ +}; + +#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) + +/* Due to TSO, an SKB can be composed of multiple actual + * packets. To keep these tracked properly, we use this. + */ +static inline int tcp_skb_pcount(const struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_segs; +} + +/* This is valid iff tcp_skb_pcount() > 1. */ +static inline int tcp_skb_mss(const struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_size; +} + +/* Events passed to congestion control interface */ +enum tcp_ca_event { + CA_EVENT_TX_START, /* first transmit when no packets in flight */ + CA_EVENT_CWND_RESTART, /* congestion window restart */ + CA_EVENT_COMPLETE_CWR, /* end of congestion recovery */ + CA_EVENT_FRTO, /* fast recovery timeout */ + CA_EVENT_LOSS, /* loss timeout */ + CA_EVENT_FAST_ACK, /* in sequence ack */ + CA_EVENT_SLOW_ACK, /* other ack */ +}; + +/* + * Interface for adding new TCP congestion control handlers + */ +#define TCP_CA_NAME_MAX 16 +#define TCP_CA_MAX 128 +#define TCP_CA_BUF_MAX (TCP_CA_NAME_MAX*TCP_CA_MAX) + +#define TCP_CONG_NON_RESTRICTED 0x1 +#define TCP_CONG_RTT_STAMP 0x2 + +struct tcp_congestion_ops { + struct list_head list; + unsigned long flags; + + /* initialize private data (optional) */ + void (*init)(struct sock *sk); + /* cleanup private data (optional) */ + void (*release)(struct sock *sk); + + /* return slow start threshold (required) */ + u32 (*ssthresh)(struct sock *sk); + /* lower bound for congestion window (optional) */ + u32 (*min_cwnd)(const struct sock *sk); + /* do new cwnd calculation (required) */ + void (*cong_avoid)(struct sock *sk, u32 ack, u32 in_flight); + /* call before changing ca_state (optional) */ + void (*set_state)(struct sock *sk, u8 new_state); + /* call when cwnd event occurs (optional) */ + void (*cwnd_event)(struct sock *sk, enum tcp_ca_event ev); + /* new value of cwnd after loss (optional) */ + u32 (*undo_cwnd)(struct sock *sk); + /* hook for packet ack accounting (optional) */ + void (*pkts_acked)(struct sock *sk, u32 num_acked, s32 rtt_us); + /* get info for inet_diag (optional) */ + void (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb); + + char name[TCP_CA_NAME_MAX]; + struct module *owner; +}; + +extern int tcp_register_congestion_control(struct tcp_congestion_ops *type); +extern void tcp_unregister_congestion_control(struct tcp_congestion_ops *type); + +extern void tcp_init_congestion_control(struct sock *sk); +extern void tcp_cleanup_congestion_control(struct sock *sk); +extern int tcp_set_default_congestion_control(const char *name); +extern void tcp_get_default_congestion_control(char *name); +extern void tcp_get_available_congestion_control(char *buf, size_t len); +extern void tcp_get_allowed_congestion_control(char *buf, size_t len); +extern int tcp_set_allowed_congestion_control(char *allowed); +extern int tcp_set_congestion_control(struct sock *sk, const char *name); +extern void tcp_slow_start(struct tcp_sock *tp); +extern void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w); + +extern struct tcp_congestion_ops tcp_init_congestion_ops; +extern u32 tcp_reno_ssthresh(struct sock *sk); +extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight); +extern u32 tcp_reno_min_cwnd(const struct sock *sk); +extern struct tcp_congestion_ops tcp_reno; + +static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + + if (icsk->icsk_ca_ops->set_state) + icsk->icsk_ca_ops->set_state(sk, ca_state); + icsk->icsk_ca_state = ca_state; +} + +static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) +{ + const struct inet_connection_sock *icsk = inet_csk(sk); + + if (icsk->icsk_ca_ops->cwnd_event) + icsk->icsk_ca_ops->cwnd_event(sk, event); +} + +/* These functions determine how the current flow behaves in respect of SACK + * handling. SACK is negotiated with the peer, and therefore it can vary + * between different flows. + * + * tcp_is_sack - SACK enabled + * tcp_is_reno - No SACK + * tcp_is_fack - FACK enabled, implies SACK enabled + */ +static inline int tcp_is_sack(const struct tcp_sock *tp) +{ + return tp->rx_opt.sack_ok; +} + +static inline int tcp_is_reno(const struct tcp_sock *tp) +{ + return !tcp_is_sack(tp); +} + +static inline int tcp_is_fack(const struct tcp_sock *tp) +{ + return tp->rx_opt.sack_ok & 2; +} + +static inline void tcp_enable_fack(struct tcp_sock *tp) +{ + tp->rx_opt.sack_ok |= 2; +} + +static inline unsigned int tcp_left_out(const struct tcp_sock *tp) +{ + return tp->sacked_out + tp->lost_out; +} + +/* This determines how many packets are "in the network" to the best + * of our knowledge. In many cases it is conservative, but where + * detailed information is available from the receiver (via SACK + * blocks etc.) we can make more aggressive calculations. + * + * Use this for decisions involving congestion control, use just + * tp->packets_out to determine if the send queue is empty or not. + * + * Read this equation as: + * + * "Packets sent once on transmission queue" MINUS + * "Packets left network, but not honestly ACKed yet" PLUS + * "Packets fast retransmitted" + */ +static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp) +{ + return tp->packets_out - tcp_left_out(tp) + tp->retrans_out; +} + +#define TCP_INFINITE_SSTHRESH 0x7fffffff + +static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp) +{ + return tp->snd_ssthresh >= TCP_INFINITE_SSTHRESH; +} + +/* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. + * The exception is rate halving phase, when cwnd is decreasing towards + * ssthresh. + */ +static inline __u32 tcp_current_ssthresh(const struct sock *sk) +{ + const struct tcp_sock *tp = tcp_sk(sk); + if ((1 << inet_csk(sk)->icsk_ca_state) & (TCPF_CA_CWR | TCPF_CA_Recovery)) + return tp->snd_ssthresh; + else + return max(tp->snd_ssthresh, + ((tp->snd_cwnd >> 1) + + (tp->snd_cwnd >> 2))); +} + +/* Use define here intentionally to get WARN_ON location shown at the caller */ +#define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out) + +extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh); +extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst); + +/* Slow start with delack produces 3 packets of burst, so that + * it is safe "de facto". This will be the default - same as + * the default reordering threshold - but if reordering increases, + * we must be able to allow cwnd to burst at least this much in order + * to not pull it back when holes are filled. + */ +static __inline__ __u32 tcp_max_burst(const struct tcp_sock *tp) +{ + return tp->reordering; +} + +/* Returns end sequence number of the receiver's advertised window */ +static inline u32 tcp_wnd_end(const struct tcp_sock *tp) +{ + return tp->snd_una + tp->snd_wnd; +} +extern int tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight); + +static inline void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss, + const struct sk_buff *skb) +{ + if (skb->len < mss) + tp->snd_sml = TCP_SKB_CB(skb)->end_seq; +} + +static inline void tcp_check_probe_timer(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + const struct inet_connection_sock *icsk = inet_csk(sk); + + if (!tp->packets_out && !icsk->icsk_pending) + inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, + icsk->icsk_rto, TCP_RTO_MAX); +} + +static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq) +{ + tp->snd_wl1 = seq; +} + +static inline void tcp_update_wl(struct tcp_sock *tp, u32 seq) +{ + tp->snd_wl1 = seq; +} + +/* + * Calculate(/check) TCP checksum + */ +static inline __sum16 tcp_v4_check(int len, __be32 saddr, + __be32 daddr, __wsum base) +{ + return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base); +} + +static inline __sum16 __tcp_checksum_complete(struct sk_buff *skb) +{ + return __skb_checksum_complete(skb); +} + +static inline int tcp_checksum_complete(struct sk_buff *skb) +{ + return !skb_csum_unnecessary(skb) && + __tcp_checksum_complete(skb); +} + +/* Prequeue for VJ style copy to user, combined with checksumming. */ + +static inline void tcp_prequeue_init(struct tcp_sock *tp) +{ + tp->ucopy.task = NULL; + tp->ucopy.len = 0; + tp->ucopy.memory = 0; + skb_queue_head_init(&tp->ucopy.prequeue); +#ifdef CONFIG_NET_DMA + tp->ucopy.dma_chan = NULL; + tp->ucopy.wakeup = 0; + tp->ucopy.pinned_list = NULL; + tp->ucopy.dma_cookie = 0; +#endif +} + +/* Packet is added to VJ-style prequeue for processing in process + * context, if a reader task is waiting. Apparently, this exciting + * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93) + * failed somewhere. Latency? Burstiness? Well, at least now we will + * see, why it failed. 8)8) --ANK + * + * NOTE: is this not too big to inline? + */ +static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (sysctl_tcp_low_latency || !tp->ucopy.task) + return 0; + + __skb_queue_tail(&tp->ucopy.prequeue, skb); + tp->ucopy.memory += skb->truesize; + if (tp->ucopy.memory > sk->sk_rcvbuf) { + struct sk_buff *skb1; + + BUG_ON(sock_owned_by_user(sk)); + + while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { + sk_backlog_rcv(sk, skb1); + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPPREQUEUEDROPPED); + } + + tp->ucopy.memory = 0; + } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { + wake_up_interruptible_sync_poll(sk_sleep(sk), + POLLIN | POLLRDNORM | POLLRDBAND); + if (!inet_csk_ack_scheduled(sk)) + inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, + (3 * tcp_rto_min(sk)) / 4, + TCP_RTO_MAX); + } + return 1; +} + + +#undef STATE_TRACE + +#ifdef STATE_TRACE +static const char *statename[]={ + "Unused","Established","Syn Sent","Syn Recv", + "Fin Wait 1","Fin Wait 2","Time Wait", "Close", + "Close Wait","Last ACK","Listen","Closing" +}; +#endif +extern void tcp_set_state(struct sock *sk, int state); + +extern void tcp_done(struct sock *sk); + +static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) +{ + rx_opt->dsack = 0; + rx_opt->num_sacks = 0; +} + +/* Determine a window scaling and initial window to offer. */ +extern void tcp_select_initial_window(int __space, __u32 mss, + __u32 *rcv_wnd, __u32 *window_clamp, + int wscale_ok, __u8 *rcv_wscale, + __u32 init_rcv_wnd); + +static inline int tcp_win_from_space(int space) +{ + return sysctl_tcp_adv_win_scale<=0 ? + (space>>(-sysctl_tcp_adv_win_scale)) : + space - (space>>sysctl_tcp_adv_win_scale); +} + +/* Note: caller must be prepared to deal with negative returns */ +static inline int tcp_space(const struct sock *sk) +{ + return tcp_win_from_space(sk->sk_rcvbuf - + atomic_read(&sk->sk_rmem_alloc)); +} + +static inline int tcp_full_space(const struct sock *sk) +{ + return tcp_win_from_space(sk->sk_rcvbuf); +} + +static inline void tcp_openreq_init(struct request_sock *req, + struct tcp_options_received *rx_opt, + struct sk_buff *skb) +{ + struct inet_request_sock *ireq = inet_rsk(req); + + req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */ + req->cookie_ts = 0; + tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; + req->mss = rx_opt->mss_clamp; + req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; + ireq->tstamp_ok = rx_opt->tstamp_ok; + ireq->sack_ok = rx_opt->sack_ok; + ireq->snd_wscale = rx_opt->snd_wscale; + ireq->wscale_ok = rx_opt->wscale_ok; + ireq->acked = 0; + ireq->ecn_ok = 0; + ireq->rmt_port = tcp_hdr(skb)->source; + ireq->loc_port = tcp_hdr(skb)->dest; +} + +extern void tcp_enter_memory_pressure(struct sock *sk); + +static inline int keepalive_intvl_when(const struct tcp_sock *tp) +{ + return tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl; +} + +static inline int keepalive_time_when(const struct tcp_sock *tp) +{ + return tp->keepalive_time ? : sysctl_tcp_keepalive_time; +} + +static inline int keepalive_probes(const struct tcp_sock *tp) +{ + return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes; +} + +static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp) +{ + const struct inet_connection_sock *icsk = &tp->inet_conn; + + return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime, + tcp_time_stamp - tp->rcv_tstamp); +} + +static inline int tcp_fin_time(const struct sock *sk) +{ + int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout; + const int rto = inet_csk(sk)->icsk_rto; + + if (fin_timeout < (rto << 2) - (rto >> 1)) + fin_timeout = (rto << 2) - (rto >> 1); + + return fin_timeout; +} + +static inline int tcp_paws_check(const struct tcp_options_received *rx_opt, + int paws_win) +{ + if ((s32)(rx_opt->ts_recent - rx_opt->rcv_tsval) <= paws_win) + return 1; + if (unlikely(get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS)) + return 1; + + return 0; +} + +static inline int tcp_paws_reject(const struct tcp_options_received *rx_opt, + int rst) +{ + if (tcp_paws_check(rx_opt, 0)) + return 0; + + /* RST segments are not recommended to carry timestamp, + and, if they do, it is recommended to ignore PAWS because + "their cleanup function should take precedence over timestamps." + Certainly, it is mistake. It is necessary to understand the reasons + of this constraint to relax it: if peer reboots, clock may go + out-of-sync and half-open connections will not be reset. + Actually, the problem would be not existing if all + the implementations followed draft about maintaining clock + via reboots. Linux-2.2 DOES NOT! + + However, we can relax time bounds for RST segments to MSL. + */ + if (rst && get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_MSL) + return 0; + return 1; +} + +#define TCP_CHECK_TIMER(sk) do { } while (0) + +static inline void tcp_mib_init(struct net *net) +{ + /* See RFC 2012 */ + TCP_ADD_STATS_USER(net, TCP_MIB_RTOALGORITHM, 1); + TCP_ADD_STATS_USER(net, TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ); + TCP_ADD_STATS_USER(net, TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ); + TCP_ADD_STATS_USER(net, TCP_MIB_MAXCONN, -1); +} + +/* from STCP */ +static inline void tcp_clear_retrans_hints_partial(struct tcp_sock *tp) +{ + tp->lost_skb_hint = NULL; + tp->scoreboard_skb_hint = NULL; +} + +static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) +{ + tcp_clear_retrans_hints_partial(tp); + tp->retransmit_skb_hint = NULL; +} + +/* MD5 Signature */ +struct crypto_hash; + +/* - key database */ +struct tcp_md5sig_key { + u8 *key; + u8 keylen; +}; + +struct tcp4_md5sig_key { + struct tcp_md5sig_key base; + __be32 addr; +}; + +struct tcp6_md5sig_key { + struct tcp_md5sig_key base; +#if 0 + u32 scope_id; /* XXX */ +#endif + struct in6_addr addr; +}; + +/* - sock block */ +struct tcp_md5sig_info { + struct tcp4_md5sig_key *keys4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct tcp6_md5sig_key *keys6; + u32 entries6; + u32 alloced6; +#endif + u32 entries4; + u32 alloced4; +}; + +/* - pseudo header */ +struct tcp4_pseudohdr { + __be32 saddr; + __be32 daddr; + __u8 pad; + __u8 protocol; + __be16 len; +}; + +struct tcp6_pseudohdr { + struct in6_addr saddr; + struct in6_addr daddr; + __be32 len; + __be32 protocol; /* including padding */ +}; + +union tcp_md5sum_block { + struct tcp4_pseudohdr ip4; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct tcp6_pseudohdr ip6; +#endif +}; + +/* - pool: digest algorithm, hash description and scratch buffer */ +struct tcp_md5sig_pool { + struct hash_desc md5_desc; + union tcp_md5sum_block md5_blk; +}; + +#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ + +/* - functions */ +extern int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, + struct sock *sk, struct request_sock *req, + struct sk_buff *skb); +extern struct tcp_md5sig_key * tcp_v4_md5_lookup(struct sock *sk, + struct sock *addr_sk); +extern int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, u8 *newkey, + u8 newkeylen); +extern int tcp_v4_md5_do_del(struct sock *sk, __be32 addr); + +#ifdef CONFIG_TCP_MD5SIG +#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_keylen ? \ + &(struct tcp_md5sig_key) { \ + .key = (twsk)->tw_md5_key, \ + .keylen = (twsk)->tw_md5_keylen, \ + } : NULL) +#else +#define tcp_twsk_md5_key(twsk) NULL +#endif + +extern struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *); +extern void tcp_free_md5sig_pool(void); + +extern struct tcp_md5sig_pool *tcp_get_md5sig_pool(void); +extern void tcp_put_md5sig_pool(void); + +extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *); +extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *, + unsigned header_len); +extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, + struct tcp_md5sig_key *key); + +/* write queue abstraction */ +static inline void tcp_write_queue_purge(struct sock *sk) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) + sk_wmem_free_skb(sk, skb); + sk_mem_reclaim(sk); + tcp_clear_all_retrans_hints(tcp_sk(sk)); +} + +static inline struct sk_buff *tcp_write_queue_head(struct sock *sk) +{ + return skb_peek(&sk->sk_write_queue); +} + +static inline struct sk_buff *tcp_write_queue_tail(struct sock *sk) +{ + return skb_peek_tail(&sk->sk_write_queue); +} + +static inline struct sk_buff *tcp_write_queue_next(struct sock *sk, struct sk_buff *skb) +{ + return skb_queue_next(&sk->sk_write_queue, skb); +} + +static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_buff *skb) +{ + return skb_queue_prev(&sk->sk_write_queue, skb); +} + +#define tcp_for_write_queue(skb, sk) \ + skb_queue_walk(&(sk)->sk_write_queue, skb) + +#define tcp_for_write_queue_from(skb, sk) \ + skb_queue_walk_from(&(sk)->sk_write_queue, skb) + +#define tcp_for_write_queue_from_safe(skb, tmp, sk) \ + skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp) + +static inline struct sk_buff *tcp_send_head(struct sock *sk) +{ + return sk->sk_send_head; +} + +static inline bool tcp_skb_is_last(const struct sock *sk, + const struct sk_buff *skb) +{ + return skb_queue_is_last(&sk->sk_write_queue, skb); +} + +static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb) +{ + if (tcp_skb_is_last(sk, skb)) + sk->sk_send_head = NULL; + else + sk->sk_send_head = tcp_write_queue_next(sk, skb); +} + +static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked) +{ + if (sk->sk_send_head == skb_unlinked) + sk->sk_send_head = NULL; +} + +static inline void tcp_init_send_head(struct sock *sk) +{ + sk->sk_send_head = NULL; +} + +static inline void __tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb) +{ + __skb_queue_tail(&sk->sk_write_queue, skb); +} + +static inline void tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb) +{ + __tcp_add_write_queue_tail(sk, skb); + + /* Queue it, remembering where we must start sending. */ + if (sk->sk_send_head == NULL) { + sk->sk_send_head = skb; + + if (tcp_sk(sk)->highest_sack == NULL) + tcp_sk(sk)->highest_sack = skb; + } +} + +static inline void __tcp_add_write_queue_head(struct sock *sk, struct sk_buff *skb) +{ + __skb_queue_head(&sk->sk_write_queue, skb); +} + +/* Insert buff after skb on the write queue of sk. */ +static inline void tcp_insert_write_queue_after(struct sk_buff *skb, + struct sk_buff *buff, + struct sock *sk) +{ + __skb_queue_after(&sk->sk_write_queue, skb, buff); +} + +/* Insert new before skb on the write queue of sk. */ +static inline void tcp_insert_write_queue_before(struct sk_buff *new, + struct sk_buff *skb, + struct sock *sk) +{ + __skb_queue_before(&sk->sk_write_queue, skb, new); + + if (sk->sk_send_head == skb) + sk->sk_send_head = new; +} + +static inline void tcp_unlink_write_queue(struct sk_buff *skb, struct sock *sk) +{ + __skb_unlink(skb, &sk->sk_write_queue); +} + +static inline int tcp_write_queue_empty(struct sock *sk) +{ + return skb_queue_empty(&sk->sk_write_queue); +} + +static inline void tcp_push_pending_frames(struct sock *sk) +{ + if (tcp_send_head(sk)) { + struct tcp_sock *tp = tcp_sk(sk); + + __tcp_push_pending_frames(sk, tcp_current_mss(sk), tp->nonagle); + } +} + +/* Start sequence of the highest skb with SACKed bit, valid only if + * sacked > 0 or when the caller has ensured validity by itself. + */ +static inline u32 tcp_highest_sack_seq(struct tcp_sock *tp) +{ + if (!tp->sacked_out) + return tp->snd_una; + + if (tp->highest_sack == NULL) + return tp->snd_nxt; + + return TCP_SKB_CB(tp->highest_sack)->seq; +} + +static inline void tcp_advance_highest_sack(struct sock *sk, struct sk_buff *skb) +{ + tcp_sk(sk)->highest_sack = tcp_skb_is_last(sk, skb) ? NULL : + tcp_write_queue_next(sk, skb); +} + +static inline struct sk_buff *tcp_highest_sack(struct sock *sk) +{ + return tcp_sk(sk)->highest_sack; +} + +static inline void tcp_highest_sack_reset(struct sock *sk) +{ + tcp_sk(sk)->highest_sack = tcp_write_queue_head(sk); +} + +/* Called when old skb is about to be deleted (to be combined with new skb) */ +static inline void tcp_highest_sack_combine(struct sock *sk, + struct sk_buff *old, + struct sk_buff *new) +{ + if (tcp_sk(sk)->sacked_out && (old == tcp_sk(sk)->highest_sack)) + tcp_sk(sk)->highest_sack = new; +} + +/* Determines whether this is a thin stream (which may suffer from + * increased latency). Used to trigger latency-reducing mechanisms. + */ +static inline unsigned int tcp_stream_is_thin(struct tcp_sock *tp) +{ + return tp->packets_out < 4 && !tcp_in_initial_slowstart(tp); +} + +/* /proc */ +enum tcp_seq_states { + TCP_SEQ_STATE_LISTENING, + TCP_SEQ_STATE_OPENREQ, + TCP_SEQ_STATE_ESTABLISHED, + TCP_SEQ_STATE_TIME_WAIT, +}; + +struct tcp_seq_afinfo { + char *name; + sa_family_t family; + struct file_operations seq_fops; + struct seq_operations seq_ops; +}; + +struct tcp_iter_state { + struct seq_net_private p; + sa_family_t family; + enum tcp_seq_states state; + struct sock *syn_wait_sk; + int bucket, offset, sbucket, num, uid; + loff_t last_pos; +}; + +extern int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo); +extern void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo); + +extern struct request_sock_ops tcp_request_sock_ops; +extern struct request_sock_ops tcp6_request_sock_ops; + +extern void tcp_v4_destroy_sock(struct sock *sk); + +extern int tcp_v4_gso_send_check(struct sk_buff *skb); +extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features); +extern struct sk_buff **tcp_gro_receive(struct sk_buff **head, + struct sk_buff *skb); +extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head, + struct sk_buff *skb); +extern int tcp_gro_complete(struct sk_buff *skb); +extern int tcp4_gro_complete(struct sk_buff *skb); + +#ifdef CONFIG_PROC_FS +extern int tcp4_proc_init(void); +extern void tcp4_proc_exit(void); +#endif + +/* TCP af-specific functions */ +struct tcp_sock_af_ops { +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk, + struct sock *addr_sk); + int (*calc_md5_hash) (char *location, + struct tcp_md5sig_key *md5, + struct sock *sk, + struct request_sock *req, + struct sk_buff *skb); + int (*md5_add) (struct sock *sk, + struct sock *addr_sk, + u8 *newkey, + u8 len); + int (*md5_parse) (struct sock *sk, + char __user *optval, + int optlen); +#endif +}; + +struct tcp_request_sock_ops { +#ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk, + struct request_sock *req); + int (*calc_md5_hash) (char *location, + struct tcp_md5sig_key *md5, + struct sock *sk, + struct request_sock *req, + struct sk_buff *skb); +#endif +}; + +/* Using SHA1 for now, define some constants. + */ +#define COOKIE_DIGEST_WORDS (SHA_DIGEST_WORDS) +#define COOKIE_MESSAGE_WORDS (SHA_MESSAGE_BYTES / 4) +#define COOKIE_WORKSPACE_WORDS (COOKIE_DIGEST_WORDS + COOKIE_MESSAGE_WORDS) + +extern int tcp_cookie_generator(u32 *bakery); + +/** + * struct tcp_cookie_values - each socket needs extra space for the + * cookies, together with (optional) space for any SYN data. + * + * A tcp_sock contains a pointer to the current value, and this is + * cloned to the tcp_timewait_sock. + * + * @cookie_pair: variable data from the option exchange. + * + * @cookie_desired: user specified tcpct_cookie_desired. Zero + * indicates default (sysctl_tcp_cookie_size). + * After cookie sent, remembers size of cookie. + * Range 0, TCP_COOKIE_MIN to TCP_COOKIE_MAX. + * + * @s_data_desired: user specified tcpct_s_data_desired. When the + * constant payload is specified (@s_data_constant), + * holds its length instead. + * Range 0 to TCP_MSS_DESIRED. + * + * @s_data_payload: constant data that is to be included in the + * payload of SYN or SYNACK segments when the + * cookie option is present. + */ +struct tcp_cookie_values { + struct kref kref; + u8 cookie_pair[TCP_COOKIE_PAIR_SIZE]; + u8 cookie_pair_size; + u8 cookie_desired; + u16 s_data_desired:11, + s_data_constant:1, + s_data_in:1, + s_data_out:1, + s_data_unused:2; + u8 s_data_payload[0]; +}; + +static inline void tcp_cookie_values_release(struct kref *kref) +{ + kfree(container_of(kref, struct tcp_cookie_values, kref)); +} + +/* The length of constant payload data. Note that s_data_desired is + * overloaded, depending on s_data_constant: either the length of constant + * data (returned here) or the limit on variable data. + */ +static inline int tcp_s_data_size(const struct tcp_sock *tp) +{ + return (tp->cookie_values != NULL && tp->cookie_values->s_data_constant) + ? tp->cookie_values->s_data_desired + : 0; +} + +/** + * struct tcp_extend_values - tcp_ipv?.c to tcp_output.c workspace. + * + * As tcp_request_sock has already been extended in other places, the + * only remaining method is to pass stack values along as function + * parameters. These parameters are not needed after sending SYNACK. + * + * @cookie_bakery: cryptographic secret and message workspace. + * + * @cookie_plus: bytes in authenticator/cookie option, copied from + * struct tcp_options_received (above). + */ +struct tcp_extend_values { + struct request_values rv; + u32 cookie_bakery[COOKIE_WORKSPACE_WORDS]; + u8 cookie_plus:6, + cookie_out_never:1, + cookie_in_always:1; +}; + +static inline struct tcp_extend_values *tcp_xv(struct request_values *rvp) +{ + return (struct tcp_extend_values *)rvp; +} + +extern void tcp_v4_init(void); +extern void tcp_init(void); + +#endif /* _TCP_H */ diff --git a/include/net/tcp_states.h b/include/net/tcp_states.h new file mode 100644 index 00000000..b0b64598 --- /dev/null +++ b/include/net/tcp_states.h @@ -0,0 +1,50 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the TCP protocol sk_state field. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_TCP_STATES_H +#define _LINUX_TCP_STATES_H + +enum { + TCP_ESTABLISHED = 1, + TCP_SYN_SENT, + TCP_SYN_RECV, + TCP_FIN_WAIT1, + TCP_FIN_WAIT2, + TCP_TIME_WAIT, + TCP_CLOSE, + TCP_CLOSE_WAIT, + TCP_LAST_ACK, + TCP_LISTEN, + TCP_CLOSING, /* Now a valid state */ + + TCP_MAX_STATES /* Leave at the end! */ +}; + +#define TCP_STATE_MASK 0xF + +#define TCP_ACTION_FIN (1 << 7) + +enum { + TCPF_ESTABLISHED = (1 << 1), + TCPF_SYN_SENT = (1 << 2), + TCPF_SYN_RECV = (1 << 3), + TCPF_FIN_WAIT1 = (1 << 4), + TCPF_FIN_WAIT2 = (1 << 5), + TCPF_TIME_WAIT = (1 << 6), + TCPF_CLOSE = (1 << 7), + TCPF_CLOSE_WAIT = (1 << 8), + TCPF_LAST_ACK = (1 << 9), + TCPF_LISTEN = (1 << 10), + TCPF_CLOSING = (1 << 11) +}; + +#endif /* _LINUX_TCP_STATES_H */ diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h new file mode 100644 index 00000000..97c3b14d --- /dev/null +++ b/include/net/timewait_sock.h @@ -0,0 +1,42 @@ +/* + * NET Generic infrastructure for Network protocols. + * + * Authors: Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _TIMEWAIT_SOCK_H +#define _TIMEWAIT_SOCK_H + +#include <linux/slab.h> +#include <net/sock.h> + +struct timewait_sock_ops { + struct kmem_cache *twsk_slab; + char *twsk_slab_name; + unsigned int twsk_obj_size; + int (*twsk_unique)(struct sock *sk, + struct sock *sktw, void *twp); + void (*twsk_destructor)(struct sock *sk); +}; + +static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) +{ + if (sk->sk_prot->twsk_prot->twsk_unique != NULL) + return sk->sk_prot->twsk_prot->twsk_unique(sk, sktw, twp); + return 0; +} + +static inline void twsk_destructor(struct sock *sk) +{ + BUG_ON(sk == NULL); + BUG_ON(sk->sk_prot == NULL); + BUG_ON(sk->sk_prot->twsk_prot == NULL); + if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) + sk->sk_prot->twsk_prot->twsk_destructor(sk); +} + +#endif /* _TIMEWAIT_SOCK_H */ diff --git a/include/net/tipc/tipc.h b/include/net/tipc/tipc.h new file mode 100644 index 00000000..15af6dca --- /dev/null +++ b/include/net/tipc/tipc.h @@ -0,0 +1,257 @@ +/* + * include/net/tipc/tipc.h: Main include file for TIPC users + * + * Copyright (c) 2003-2006, Ericsson AB + * Copyright (c) 2005,2010 Wind River Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must 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 names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (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_TIPC_H_ +#define _NET_TIPC_H_ + +#ifdef __KERNEL__ + +#include <linux/tipc.h> +#include <linux/skbuff.h> + +/* + * Native API + */ + +/* + * TIPC operating mode routines + */ + +u32 tipc_get_addr(void); + +#define TIPC_NOT_RUNNING 0 +#define TIPC_NODE_MODE 1 +#define TIPC_NET_MODE 2 + +typedef void (*tipc_mode_event)(void *usr_handle, int mode, u32 addr); + +int tipc_attach(unsigned int *userref, tipc_mode_event, void *usr_handle); + +void tipc_detach(unsigned int userref); + +int tipc_get_mode(void); + +/* + * TIPC port manipulation routines + */ + +typedef void (*tipc_msg_err_event) (void *usr_handle, + u32 portref, + struct sk_buff **buf, + unsigned char const *data, + unsigned int size, + int reason, + struct tipc_portid const *attmpt_destid); + +typedef void (*tipc_named_msg_err_event) (void *usr_handle, + u32 portref, + struct sk_buff **buf, + unsigned char const *data, + unsigned int size, + int reason, + struct tipc_name_seq const *attmpt_dest); + +typedef void (*tipc_conn_shutdown_event) (void *usr_handle, + u32 portref, + struct sk_buff **buf, + unsigned char const *data, + unsigned int size, + int reason); + +typedef void (*tipc_msg_event) (void *usr_handle, + u32 portref, + struct sk_buff **buf, + unsigned char const *data, + unsigned int size, + unsigned int importance, + struct tipc_portid const *origin); + +typedef void (*tipc_named_msg_event) (void *usr_handle, + u32 portref, + struct sk_buff **buf, + unsigned char const *data, + unsigned int size, + unsigned int importance, + struct tipc_portid const *orig, + struct tipc_name_seq const *dest); + +typedef void (*tipc_conn_msg_event) (void *usr_handle, + u32 portref, + struct sk_buff **buf, + unsigned char const *data, + unsigned int size); + +typedef void (*tipc_continue_event) (void *usr_handle, + u32 portref); + +int tipc_createport(unsigned int tipc_user, + void *usr_handle, + unsigned int importance, + tipc_msg_err_event error_cb, + tipc_named_msg_err_event named_error_cb, + tipc_conn_shutdown_event conn_error_cb, + tipc_msg_event message_cb, + tipc_named_msg_event named_message_cb, + tipc_conn_msg_event conn_message_cb, + tipc_continue_event continue_event_cb, + u32 *portref); + +int tipc_deleteport(u32 portref); + +int tipc_ownidentity(u32 portref, struct tipc_portid *port); + +int tipc_portimportance(u32 portref, unsigned int *importance); +int tipc_set_portimportance(u32 portref, unsigned int importance); + +int tipc_portunreliable(u32 portref, unsigned int *isunreliable); +int tipc_set_portunreliable(u32 portref, unsigned int isunreliable); + +int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable); +int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable); + +int tipc_publish(u32 portref, unsigned int scope, + struct tipc_name_seq const *name_seq); +int tipc_withdraw(u32 portref, unsigned int scope, + struct tipc_name_seq const *name_seq); + +int tipc_connect2port(u32 portref, struct tipc_portid const *port); + +int tipc_disconnect(u32 portref); + +int tipc_shutdown(u32 ref); + +int tipc_isconnected(u32 portref, int *isconnected); + +int tipc_peer(u32 portref, struct tipc_portid *peer); + +int tipc_ref_valid(u32 portref); + +/* + * TIPC messaging routines + */ + +#define TIPC_PORT_IMPORTANCE 100 /* send using current port setting */ + + +int tipc_send(u32 portref, + unsigned int num_sect, + struct iovec const *msg_sect); + +int tipc_send_buf(u32 portref, + struct sk_buff *buf, + unsigned int dsz); + +int tipc_send2name(u32 portref, + struct tipc_name const *name, + u32 domain, + unsigned int num_sect, + struct iovec const *msg_sect); + +int tipc_send_buf2name(u32 portref, + struct tipc_name const *name, + u32 domain, + struct sk_buff *buf, + unsigned int dsz); + +int tipc_forward2name(u32 portref, + struct tipc_name const *name, + u32 domain, + unsigned int section_count, + struct iovec const *msg_sect, + struct tipc_portid const *origin, + unsigned int importance); + +int tipc_forward_buf2name(u32 portref, + struct tipc_name const *name, + u32 domain, + struct sk_buff *buf, + unsigned int dsz, + struct tipc_portid const *orig, + unsigned int importance); + +int tipc_send2port(u32 portref, + struct tipc_portid const *dest, + unsigned int num_sect, + struct iovec const *msg_sect); + +int tipc_send_buf2port(u32 portref, + struct tipc_portid const *dest, + struct sk_buff *buf, + unsigned int dsz); + +int tipc_forward2port(u32 portref, + struct tipc_portid const *dest, + unsigned int num_sect, + struct iovec const *msg_sect, + struct tipc_portid const *origin, + unsigned int importance); + +int tipc_forward_buf2port(u32 portref, + struct tipc_portid const *dest, + struct sk_buff *buf, + unsigned int dsz, + struct tipc_portid const *orig, + unsigned int importance); + +int tipc_multicast(u32 portref, + struct tipc_name_seq const *seq, + u32 domain, /* currently unused */ + unsigned int section_count, + struct iovec const *msg); + +#if 0 +int tipc_multicast_buf(u32 portref, + struct tipc_name_seq const *seq, + u32 domain, + void *buf, + unsigned int size); +#endif + +/* + * TIPC subscription routines + */ + +int tipc_ispublished(struct tipc_name const *name); + +/* + * Get number of available nodes within specified domain (excluding own node) + */ + +unsigned int tipc_available_nodes(const u32 domain); + +#endif + +#endif diff --git a/include/net/tipc/tipc_bearer.h b/include/net/tipc/tipc_bearer.h new file mode 100644 index 00000000..ee2f304e --- /dev/null +++ b/include/net/tipc/tipc_bearer.h @@ -0,0 +1,138 @@ +/* + * include/net/tipc/tipc_bearer.h: Include file for privileged access to TIPC bearers + * + * Copyright (c) 2003-2006, Ericsson AB + * Copyright (c) 2005, Wind River Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must 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 names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (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_TIPC_BEARER_H_ +#define _NET_TIPC_BEARER_H_ + +#ifdef __KERNEL__ + +#include <linux/tipc_config.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> + +/* + * Identifiers of supported TIPC media types + */ + +#define TIPC_MEDIA_TYPE_ETH 1 + +/* + * Destination address structure used by TIPC bearers when sending messages + * + * IMPORTANT: The fields of this structure MUST be stored using the specified + * byte order indicated below, as the structure is exchanged between nodes + * as part of a link setup process. + */ + +struct tipc_media_addr { + __be32 type; /* bearer type (network byte order) */ + union { + __u8 eth_addr[6]; /* 48 bit Ethernet addr (byte array) */ +#if 0 + /* Prototypes for other possible bearer types */ + + struct { + __u16 sin_family; + __u16 sin_port; + struct { + __u32 s_addr; + } sin_addr; + char pad[4]; + } addr_in; /* IP-based bearer */ + __u16 sock_descr; /* generic socket bearer */ +#endif + } dev_addr; +}; + +/** + * struct tipc_bearer - TIPC bearer info available to privileged users + * @usr_handle: pointer to additional user-defined information about bearer + * @mtu: max packet size bearer can support + * @blocked: non-zero if bearer is blocked + * @lock: spinlock for controlling access to bearer + * @addr: media-specific address associated with bearer + * @name: bearer name (format = media:interface) + * + * Note: TIPC initializes "name" and "lock" fields; user is responsible for + * initialization all other fields when a bearer is enabled. + */ + +struct tipc_bearer { + void *usr_handle; + u32 mtu; + int blocked; + spinlock_t lock; + struct tipc_media_addr addr; + char name[TIPC_MAX_BEARER_NAME]; +}; + +/* + * TIPC routines available to supported media types + */ + +int tipc_register_media(u32 media_type, + char *media_name, + int (*enable)(struct tipc_bearer *), + void (*disable)(struct tipc_bearer *), + int (*send_msg)(struct sk_buff *, + struct tipc_bearer *, + struct tipc_media_addr *), + char *(*addr2str)(struct tipc_media_addr *a, + char *str_buf, + int str_size), + struct tipc_media_addr *bcast_addr, + const u32 bearer_priority, + const u32 link_tolerance, /* [ms] */ + const u32 send_window_limit); + +void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); + +int tipc_block_bearer(const char *name); +void tipc_continue(struct tipc_bearer *tb_ptr); + +int tipc_enable_bearer(const char *bearer_name, u32 bcast_scope, u32 priority); +int tipc_disable_bearer(const char *name); + +/* + * Routines made available to TIPC by supported media types + */ + +int tipc_eth_media_start(void); +void tipc_eth_media_stop(void); + +#endif + +#endif diff --git a/include/net/tipc/tipc_msg.h b/include/net/tipc/tipc_msg.h new file mode 100644 index 00000000..2e159a81 --- /dev/null +++ b/include/net/tipc/tipc_msg.h @@ -0,0 +1,207 @@ +/* + * include/net/tipc/tipc_msg.h: Include file for privileged access to TIPC message headers + * + * Copyright (c) 2003-2006, Ericsson AB + * Copyright (c) 2005, Wind River Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must 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 names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (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_TIPC_MSG_H_ +#define _NET_TIPC_MSG_H_ + +#ifdef __KERNEL__ + +struct tipc_msg { + __be32 hdr[15]; +}; + + +/* + TIPC user data message header format, version 2: + + + 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w0:|vers | user |hdr sz |n|d|s|-| message size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w1:|mstyp| error |rer cnt|lsc|opt p| broadcast ack no | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w2:| link level ack no | broadcast/link level seq no | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w3:| previous node | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w4:| originating port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w5:| destination port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w6:| originating node | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w7:| destination node | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w8:| name type / transport sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + w9:| name instance/multicast lower bound | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + wA:| multicast upper bound | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + \ options \ + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +*/ + +#define TIPC_CONN_MSG 0 +#define TIPC_MCAST_MSG 1 +#define TIPC_NAMED_MSG 2 +#define TIPC_DIRECT_MSG 3 + + +static inline u32 msg_word(struct tipc_msg *m, u32 pos) +{ + return ntohl(m->hdr[pos]); +} + +static inline u32 msg_bits(struct tipc_msg *m, u32 w, u32 pos, u32 mask) +{ + return (msg_word(m, w) >> pos) & mask; +} + +static inline u32 msg_importance(struct tipc_msg *m) +{ + return msg_bits(m, 0, 25, 0xf); +} + +static inline u32 msg_hdr_sz(struct tipc_msg *m) +{ + return msg_bits(m, 0, 21, 0xf) << 2; +} + +static inline int msg_short(struct tipc_msg *m) +{ + return (msg_hdr_sz(m) == 24); +} + +static inline u32 msg_size(struct tipc_msg *m) +{ + return msg_bits(m, 0, 0, 0x1ffff); +} + +static inline u32 msg_data_sz(struct tipc_msg *m) +{ + return (msg_size(m) - msg_hdr_sz(m)); +} + +static inline unchar *msg_data(struct tipc_msg *m) +{ + return ((unchar *)m) + msg_hdr_sz(m); +} + +static inline u32 msg_type(struct tipc_msg *m) +{ + return msg_bits(m, 1, 29, 0x7); +} + +static inline u32 msg_named(struct tipc_msg *m) +{ + return (msg_type(m) == TIPC_NAMED_MSG); +} + +static inline u32 msg_mcast(struct tipc_msg *m) +{ + return (msg_type(m) == TIPC_MCAST_MSG); +} + +static inline u32 msg_connected(struct tipc_msg *m) +{ + return (msg_type(m) == TIPC_CONN_MSG); +} + +static inline u32 msg_errcode(struct tipc_msg *m) +{ + return msg_bits(m, 1, 25, 0xf); +} + +static inline u32 msg_prevnode(struct tipc_msg *m) +{ + return msg_word(m, 3); +} + +static inline u32 msg_origport(struct tipc_msg *m) +{ + return msg_word(m, 4); +} + +static inline u32 msg_destport(struct tipc_msg *m) +{ + return msg_word(m, 5); +} + +static inline u32 msg_mc_netid(struct tipc_msg *m) +{ + return msg_word(m, 5); +} + +static inline u32 msg_orignode(struct tipc_msg *m) +{ + if (likely(msg_short(m))) + return msg_prevnode(m); + return msg_word(m, 6); +} + +static inline u32 msg_destnode(struct tipc_msg *m) +{ + return msg_word(m, 7); +} + +static inline u32 msg_nametype(struct tipc_msg *m) +{ + return msg_word(m, 8); +} + +static inline u32 msg_nameinst(struct tipc_msg *m) +{ + return msg_word(m, 9); +} + +static inline u32 msg_namelower(struct tipc_msg *m) +{ + return msg_nameinst(m); +} + +static inline u32 msg_nameupper(struct tipc_msg *m) +{ + return msg_word(m, 10); +} + +#endif + +#endif diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h new file mode 100644 index 00000000..c54917cb --- /dev/null +++ b/include/net/tipc/tipc_port.h @@ -0,0 +1,103 @@ +/* + * include/net/tipc/tipc_port.h: Include file for privileged access to TIPC ports + * + * Copyright (c) 1994-2007, Ericsson AB + * Copyright (c) 2005-2008, Wind River Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must 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 names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (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_TIPC_PORT_H_ +#define _NET_TIPC_PORT_H_ + +#ifdef __KERNEL__ + +#include <linux/tipc.h> +#include <linux/skbuff.h> +#include <net/tipc/tipc_msg.h> + +#define TIPC_FLOW_CONTROL_WIN 512 + +/** + * struct tipc_port - native TIPC port info available to privileged users + * @usr_handle: pointer to additional user-defined information about port + * @lock: pointer to spinlock for controlling access to port + * @connected: non-zero if port is currently connected to a peer port + * @conn_type: TIPC type used when connection was established + * @conn_instance: TIPC instance used when connection was established + * @conn_unacked: number of unacknowledged messages received from peer port + * @published: non-zero if port has one or more associated names + * @congested: non-zero if cannot send because of link or port congestion + * @max_pkt: maximum packet size "hint" used when building messages sent by port + * @ref: unique reference to port in TIPC object registry + * @phdr: preformatted message header used when sending messages + */ + +struct tipc_port { + void *usr_handle; + spinlock_t *lock; + int connected; + u32 conn_type; + u32 conn_instance; + u32 conn_unacked; + int published; + u32 congested; + u32 max_pkt; + u32 ref; + struct tipc_msg phdr; +}; + + +struct tipc_port *tipc_createport_raw(void *usr_handle, + u32 (*dispatcher)(struct tipc_port *, struct sk_buff *), + void (*wakeup)(struct tipc_port *), + const u32 importance); + +int tipc_reject_msg(struct sk_buff *buf, u32 err); + +int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode); + +void tipc_acknowledge(u32 port_ref,u32 ack); + +struct tipc_port *tipc_get_port(const u32 ref); + +void *tipc_get_handle(const u32 ref); + +/* + * The following routines require that the port be locked on entry + */ + +int tipc_disconnect_port(struct tipc_port *tp_ptr); + + +#endif + +#endif + diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h new file mode 100644 index 00000000..42a0eb68 --- /dev/null +++ b/include/net/transp_v6.h @@ -0,0 +1,61 @@ +#ifndef _TRANSP_V6_H +#define _TRANSP_V6_H + +#include <net/checksum.h> + +/* + * IPv6 transport protocols + */ + +#ifdef __KERNEL__ + +extern struct proto rawv6_prot; +extern struct proto udpv6_prot; +extern struct proto udplitev6_prot; +extern struct proto tcpv6_prot; + +struct flowi; + +/* extention headers */ +extern int ipv6_exthdrs_init(void); +extern void ipv6_exthdrs_exit(void); +extern int ipv6_frag_init(void); +extern void ipv6_frag_exit(void); + +/* transport protocols */ +extern int rawv6_init(void); +extern void rawv6_exit(void); +extern int udpv6_init(void); +extern void udpv6_exit(void); +extern int udplitev6_init(void); +extern void udplitev6_exit(void); +extern int tcpv6_init(void); +extern void tcpv6_exit(void); + +extern int udpv6_connect(struct sock *sk, + struct sockaddr *uaddr, + int addr_len); + +extern int datagram_recv_ctl(struct sock *sk, + struct msghdr *msg, + struct sk_buff *skb); + +extern int datagram_send_ctl(struct net *net, + struct msghdr *msg, + struct flowi *fl, + struct ipv6_txoptions *opt, + int *hlimit, int *tclass, + int *dontfrag); + +#define LOOPBACK4_IPV6 cpu_to_be32(0x7f000006) + +/* + * address family specific functions + */ +extern const struct inet_connection_sock_af_ops ipv4_specific; + +extern void inet6_destroy_sock(struct sock *sk); + +#endif + +#endif diff --git a/include/net/udp.h b/include/net/udp.h new file mode 100644 index 00000000..a184d349 --- /dev/null +++ b/include/net/udp.h @@ -0,0 +1,246 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the UDP module. + * + * Version: @(#)udp.h 1.0.2 05/07/93 + * + * Authors: Ross Biro + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * Fixes: + * Alan Cox : Turned on udp checksums. I don't want to + * chase 'memory corruption' bugs that aren't! + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _UDP_H +#define _UDP_H + +#include <linux/list.h> +#include <net/inet_sock.h> +#include <net/sock.h> +#include <net/snmp.h> +#include <net/ip.h> +#include <linux/ipv6.h> +#include <linux/seq_file.h> +#include <linux/poll.h> + +/** + * struct udp_skb_cb - UDP(-Lite) private variables + * + * @header: private variables used by IPv4/IPv6 + * @cscov: checksum coverage length (UDP-Lite only) + * @partial_cov: if set indicates partial csum coverage + */ +struct udp_skb_cb { + union { + struct inet_skb_parm h4; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + struct inet6_skb_parm h6; +#endif + } header; + __u16 cscov; + __u8 partial_cov; +}; +#define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) + +/** + * struct udp_hslot - UDP hash slot + * + * @head: head of list of sockets + * @count: number of sockets in 'head' list + * @lock: spinlock protecting changes to head/count + */ +struct udp_hslot { + struct hlist_nulls_head head; + int count; + spinlock_t lock; +} __attribute__((aligned(2 * sizeof(long)))); + +/** + * struct udp_table - UDP table + * + * @hash: hash table, sockets are hashed on (local port) + * @hash2: hash table, sockets are hashed on (local port, local address) + * @mask: number of slots in hash tables, minus 1 + * @log: log2(number of slots in hash table) + */ +struct udp_table { + struct udp_hslot *hash; + struct udp_hslot *hash2; + unsigned int mask; + unsigned int log; +}; +extern struct udp_table udp_table; +extern void udp_table_init(struct udp_table *, const char *); +static inline struct udp_hslot *udp_hashslot(struct udp_table *table, + struct net *net, unsigned num) +{ + return &table->hash[udp_hashfn(net, num, table->mask)]; +} +/* + * For secondary hash, net_hash_mix() is performed before calling + * udp_hashslot2(), this explains difference with udp_hashslot() + */ +static inline struct udp_hslot *udp_hashslot2(struct udp_table *table, + unsigned int hash) +{ + return &table->hash2[hash & table->mask]; +} + +/* Note: this must match 'valbool' in sock_setsockopt */ +#define UDP_CSUM_NOXMIT 1 + +/* Used by SunRPC/xprt layer. */ +#define UDP_CSUM_NORCV 2 + +/* Default, as per the RFC, is to always do csums. */ +#define UDP_CSUM_DEFAULT 0 + +extern struct proto udp_prot; + +extern atomic_t udp_memory_allocated; + +/* sysctl variables for udp */ +extern int sysctl_udp_mem[3]; +extern int sysctl_udp_rmem_min; +extern int sysctl_udp_wmem_min; + +struct sk_buff; + +/* + * Generic checksumming routines for UDP(-Lite) v4 and v6 + */ +static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) +{ + return __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov); +} + +static inline int udp_lib_checksum_complete(struct sk_buff *skb) +{ + return !skb_csum_unnecessary(skb) && + __udp_lib_checksum_complete(skb); +} + +/** + * udp_csum_outgoing - compute UDPv4/v6 checksum over fragments + * @sk: socket we are writing to + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static inline __wsum udp_csum_outgoing(struct sock *sk, struct sk_buff *skb) +{ + __wsum csum = csum_partial(skb_transport_header(skb), + sizeof(struct udphdr), 0); + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + return csum; +} + +/* hash routines shared between UDPv4/6 and UDP-Litev4/6 */ +static inline void udp_lib_hash(struct sock *sk) +{ + BUG(); +} + +extern void udp_lib_unhash(struct sock *sk); +extern void udp_lib_rehash(struct sock *sk, u16 new_hash); + +static inline void udp_lib_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + +extern int udp_lib_get_port(struct sock *sk, unsigned short snum, + int (*)(const struct sock *,const struct sock *), + unsigned int hash2_nulladdr); + +/* net/ipv4/udp.c */ +extern int udp_get_port(struct sock *sk, unsigned short snum, + int (*saddr_cmp)(const struct sock *, + const struct sock *)); +extern void udp_err(struct sk_buff *, u32); +extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len); +extern void udp_flush_pending_frames(struct sock *sk); +extern int udp_rcv(struct sk_buff *skb); +extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); +extern int udp_disconnect(struct sock *sk, int flags); +extern unsigned int udp_poll(struct file *file, struct socket *sock, + poll_table *wait); +extern int udp_lib_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen); +extern int udp_lib_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, unsigned int optlen, + int (*push_pending_frames)(struct sock *)); +extern struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, + __be32 daddr, __be16 dport, + int dif); + +/* + * SNMP statistics for UDP and UDP-Lite + */ +#define UDP_INC_STATS_USER(net, field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_USER((net)->mib.udplite_statistics, field); \ + else SNMP_INC_STATS_USER((net)->mib.udp_statistics, field); } while(0) +#define UDP_INC_STATS_BH(net, field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_BH((net)->mib.udplite_statistics, field); \ + else SNMP_INC_STATS_BH((net)->mib.udp_statistics, field); } while(0) + +#define UDP6_INC_STATS_BH(net, field, is_udplite) do { \ + if (is_udplite) SNMP_INC_STATS_BH((net)->mib.udplite_stats_in6, field);\ + else SNMP_INC_STATS_BH((net)->mib.udp_stats_in6, field); \ +} while(0) +#define UDP6_INC_STATS_USER(net, field, __lite) do { \ + if (__lite) SNMP_INC_STATS_USER((net)->mib.udplite_stats_in6, field); \ + else SNMP_INC_STATS_USER((net)->mib.udp_stats_in6, field); \ +} while(0) + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#define UDPX_INC_STATS_BH(sk, field) \ + do { \ + if ((sk)->sk_family == AF_INET) \ + UDP_INC_STATS_BH(sock_net(sk), field, 0); \ + else \ + UDP6_INC_STATS_BH(sock_net(sk), field, 0); \ + } while (0); +#else +#define UDPX_INC_STATS_BH(sk, field) UDP_INC_STATS_BH(sock_net(sk), field, 0) +#endif + +/* /proc */ +struct udp_seq_afinfo { + char *name; + sa_family_t family; + struct udp_table *udp_table; + struct file_operations seq_fops; + struct seq_operations seq_ops; +}; + +struct udp_iter_state { + struct seq_net_private p; + sa_family_t family; + int bucket; + struct udp_table *udp_table; +}; + +#ifdef CONFIG_PROC_FS +extern int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo); +extern void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo); + +extern int udp4_proc_init(void); +extern void udp4_proc_exit(void); +#endif + +extern void udp_init(void); + +extern int udp4_ufo_send_check(struct sk_buff *skb); +extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features); +#endif /* _UDP_H */ diff --git a/include/net/udplite.h b/include/net/udplite.h new file mode 100644 index 00000000..afdffe60 --- /dev/null +++ b/include/net/udplite.h @@ -0,0 +1,121 @@ +/* + * Definitions for the UDP-Lite (RFC 3828) code. + */ +#ifndef _UDPLITE_H +#define _UDPLITE_H + +#include <net/ip6_checksum.h> + +/* UDP-Lite socket options */ +#define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ +#define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ + +extern struct proto udplite_prot; +extern struct udp_table udplite_table; + +/* + * Checksum computation is all in software, hence simpler getfrag. + */ +static __inline__ int udplite_getfrag(void *from, char *to, int offset, + int len, int odd, struct sk_buff *skb) +{ + return memcpy_fromiovecend(to, (struct iovec *) from, offset, len); +} + +/* Designate sk as UDP-Lite socket */ +static inline int udplite_sk_init(struct sock *sk) +{ + udp_sk(sk)->pcflag = UDPLITE_BIT; + return 0; +} + +/* + * Checksumming routines + */ +static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) +{ + u16 cscov; + + /* In UDPv4 a zero checksum means that the transmitter generated no + * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets + * with a zero checksum field are illegal. */ + if (uh->check == 0) { + LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: zeroed checksum field\n"); + return 1; + } + + cscov = ntohs(uh->len); + + if (cscov == 0) /* Indicates that full coverage is required. */ + ; + else if (cscov < 8 || cscov > skb->len) { + /* + * Coverage length violates RFC 3828: log and discard silently. + */ + LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: bad csum coverage %d/%d\n", + cscov, skb->len); + return 1; + + } else if (cscov < skb->len) { + UDP_SKB_CB(skb)->partial_cov = 1; + UDP_SKB_CB(skb)->cscov = cscov; + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->ip_summed = CHECKSUM_NONE; + } + + return 0; +} + +static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) +{ + int cscov = up->len; + + /* + * Sender has set `partial coverage' option on UDP-Lite socket + */ + if (up->pcflag & UDPLITE_SEND_CC) { + if (up->pcslen < up->len) { + /* up->pcslen == 0 means that full coverage is required, + * partial coverage only if 0 < up->pcslen < up->len */ + if (0 < up->pcslen) { + cscov = up->pcslen; + } + uh->len = htons(up->pcslen); + } + /* + * NOTE: Causes for the error case `up->pcslen > up->len': + * (i) Application error (will not be penalized). + * (ii) Payload too big for send buffer: data is split + * into several packets, each with its own header. + * In this case (e.g. last segment), coverage may + * exceed packet length. + * Since packets with coverage length > packet length are + * illegal, we fall back to the defaults here. + */ + } + return cscov; +} + +static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) +{ + int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb)); + __wsum csum = 0; + + skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ + + skb_queue_walk(&sk->sk_write_queue, skb) { + const int off = skb_transport_offset(skb); + const int len = skb->len - off; + + csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum); + + if ((cscov -= len) <= 0) + break; + } + return csum; +} + +extern void udplite4_register(void); +extern int udplite_get_port(struct sock *sk, unsigned short snum, + int (*scmp)(const struct sock *, const struct sock *)); +#endif /* _UDPLITE_H */ diff --git a/include/net/wext.h b/include/net/wext.h new file mode 100644 index 00000000..4f6e7423 --- /dev/null +++ b/include/net/wext.h @@ -0,0 +1,60 @@ +#ifndef __NET_WEXT_H +#define __NET_WEXT_H + +#include <net/iw_handler.h> + +struct net; + +#ifdef CONFIG_WEXT_CORE +extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, + void __user *arg); +extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg); + +extern struct iw_statistics *get_wireless_stats(struct net_device *dev); +extern int call_commit_handler(struct net_device *dev); +#else +static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, + void __user *arg) +{ + return -EINVAL; +} +static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg) +{ + return -EINVAL; +} +#endif + +#ifdef CONFIG_WEXT_PROC +extern int wext_proc_init(struct net *net); +extern void wext_proc_exit(struct net *net); +#else +static inline int wext_proc_init(struct net *net) +{ + return 0; +} +static inline void wext_proc_exit(struct net *net) +{ + return; +} +#endif + +#ifdef CONFIG_WEXT_PRIV +int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler); +int compat_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler); +int iw_handler_get_private(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +#else +#define ioctl_private_call NULL +#define compat_private_call NULL +#endif + + +#endif /* __NET_WEXT_H */ diff --git a/include/net/wimax.h b/include/net/wimax.h new file mode 100644 index 00000000..3461aa1d --- /dev/null +++ b/include/net/wimax.h @@ -0,0 +1,525 @@ +/* + * Linux WiMAX + * Kernel space API for accessing WiMAX devices + * + * + * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> + * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * + * The WiMAX stack provides an API for controlling and managing the + * system's WiMAX devices. This API affects the control plane; the + * data plane is accessed via the network stack (netdev). + * + * Parts of the WiMAX stack API and notifications are exported to + * user space via Generic Netlink. In user space, libwimax (part of + * the wimax-tools package) provides a shim layer for accessing those + * calls. + * + * The API is standarized for all WiMAX devices and different drivers + * implement the backend support for it. However, device-specific + * messaging pipes are provided that can be used to issue commands and + * receive notifications in free form. + * + * Currently the messaging pipes are the only means of control as it + * is not known (due to the lack of more devices in the market) what + * will be a good abstraction layer. Expect this to change as more + * devices show in the market. This API is designed to be growable in + * order to address this problem. + * + * USAGE + * + * Embed a `struct wimax_dev` at the beginning of the the device's + * private structure, initialize and register it. For details, see + * `struct wimax_dev`s documentation. + * + * Once this is done, wimax-tools's libwimaxll can be used to + * communicate with the driver from user space. You user space + * application does not have to forcibily use libwimaxll and can talk + * the generic netlink protocol directly if desired. + * + * Remember this is a very low level API that will to provide all of + * WiMAX features. Other daemons and services running in user space + * are the expected clients of it. They offer a higher level API that + * applications should use (an example of this is the Intel's WiMAX + * Network Service for the i2400m). + * + * DESIGN + * + * Although not set on final stone, this very basic interface is + * mostly completed. Remember this is meant to grow as new common + * operations are decided upon. New operations will be added to the + * interface, intent being on keeping backwards compatibility as much + * as possible. + * + * This layer implements a set of calls to control a WiMAX device, + * exposing a frontend to the rest of the kernel and user space (via + * generic netlink) and a backend implementation in the driver through + * function pointers. + * + * WiMAX devices have a state, and a kernel-only API allows the + * drivers to manipulate that state. State transitions are atomic, and + * only some of them are allowed (see `enum wimax_st`). + * + * Most API calls will set the state automatically; in most cases + * drivers have to only report state changes due to external + * conditions. + * + * All API operations are 'atomic', serialized through a mutex in the + * `struct wimax_dev`. + * + * EXPORTING TO USER SPACE THROUGH GENERIC NETLINK + * + * The API is exported to user space using generic netlink (other + * methods can be added as needed). + * + * There is a Generic Netlink Family named "WiMAX", where interfaces + * supporting the WiMAX interface receive commands and broadcast their + * signals over a multicast group named "msg". + * + * Mapping to the source/destination interface is done by an interface + * index attribute. + * + * For user-to-kernel traffic (commands) we use a function call + * marshalling mechanism, where a message X with attributes A, B, C + * sent from user space to kernel space means executing the WiMAX API + * call wimax_X(A, B, C), sending the results back as a message. + * + * Kernel-to-user (notifications or signals) communication is sent + * over multicast groups. This allows to have multiple applications + * monitoring them. + * + * Each command/signal gets assigned it's own attribute policy. This + * way the validator will verify that all the attributes in there are + * only the ones that should be for each command/signal. Thing of an + * attribute mapping to a type+argumentname for each command/signal. + * + * If we had a single policy for *all* commands/signals, after running + * the validator we'd have to check "does this attribute belong in + * here"? for each one. It can be done manually, but it's just easier + * to have the validator do that job with multiple policies. As well, + * it makes it easier to later expand each command/signal signature + * without affecting others and keeping the namespace more or less + * sane. Not that it is too complicated, but it makes it even easier. + * + * No state information is maintained in the kernel for each user + * space connection (the connection is stateless). + * + * TESTING FOR THE INTERFACE AND VERSIONING + * + * If network interface X is a WiMAX device, there will be a Generic + * Netlink family named "WiMAX X" and the device will present a + * "wimax" directory in it's network sysfs directory + * (/sys/class/net/DEVICE/wimax) [used by HAL]. + * + * The inexistence of any of these means the device does not support + * this WiMAX API. + * + * By querying the generic netlink controller, versioning information + * and the multicast groups available can be found. Applications using + * the interface can either rely on that or use the generic netlink + * controller to figure out which generic netlink commands/signals are + * supported. + * + * NOTE: this versioning is a last resort to avoid hard + * incompatibilities. It is the intention of the design of this + * stack not to introduce backward incompatible changes. + * + * The version code has to fit in one byte (restrictions imposed by + * generic netlink); we use `version / 10` for the major version and + * `version % 10` for the minor. This gives 9 minors for each major + * and 25 majors. + * + * The version change protocol is as follow: + * + * - Major versions: needs to be increased if an existing message/API + * call is changed or removed. Doesn't need to be changed if a new + * message is added. + * + * - Minor version: needs to be increased if new messages/API calls are + * being added or some other consideration that doesn't impact the + * user-kernel interface too much (like some kind of bug fix) and + * that is kind of left up in the air to common sense. + * + * User space code should not try to work if the major version it was + * compiled for differs from what the kernel offers. As well, if the + * minor version of the kernel interface is lower than the one user + * space is expecting (the one it was compiled for), the kernel + * might be missing API calls; user space shall be ready to handle + * said condition. Use the generic netlink controller operations to + * find which ones are supported and which not. + * + * libwimaxll:wimaxll_open() takes care of checking versions. + * + * THE OPERATIONS: + * + * Each operation is defined in its on file (drivers/net/wimax/op-*.c) + * for clarity. The parts needed for an operation are: + * + * - a function pointer in `struct wimax_dev`: optional, as the + * operation might be implemented by the stack and not by the + * driver. + * + * All function pointers are named wimax_dev->op_*(), and drivers + * must implement them except where noted otherwise. + * + * - When exported to user space, a `struct nla_policy` to define the + * attributes of the generic netlink command and a `struct genl_ops` + * to define the operation. + * + * All the declarations for the operation codes (WIMAX_GNL_OP_<NAME>) + * and generic netlink attributes (WIMAX_GNL_<NAME>_*) are declared in + * include/linux/wimax.h; this file is intended to be cloned by user + * space to gain access to those declarations. + * + * A few caveats to remember: + * + * - Need to define attribute numbers starting in 1; otherwise it + * fails. + * + * - the `struct genl_family` requires a maximum attribute id; when + * defining the `struct nla_policy` for each message, it has to have + * an array size of WIMAX_GNL_ATTR_MAX+1. + * + * The op_*() function pointers will not be called if the wimax_dev is + * in a state <= %WIMAX_ST_UNINITIALIZED. The exception is: + * + * - op_reset: can be called at any time after wimax_dev_add() has + * been called. + * + * THE PIPE INTERFACE: + * + * This interface is kept intentionally simple. The driver can send + * and receive free-form messages to/from user space through a + * pipe. See drivers/net/wimax/op-msg.c for details. + * + * The kernel-to-user messages are sent with + * wimax_msg(). user-to-kernel messages are delivered via + * wimax_dev->op_msg_from_user(). + * + * RFKILL: + * + * RFKILL support is built into the wimax_dev layer; the driver just + * needs to call wimax_report_rfkill_{hw,sw}() to inform of changes in + * the hardware or software RF kill switches. When the stack wants to + * turn the radio off, it will call wimax_dev->op_rfkill_sw_toggle(), + * which the driver implements. + * + * User space can set the software RF Kill switch by calling + * wimax_rfkill(). + * + * The code for now only supports devices that don't require polling; + * If the device needs to be polled, create a self-rearming delayed + * work struct for polling or look into adding polled support to the + * WiMAX stack. + * + * When initializing the hardware (_probe), after calling + * wimax_dev_add(), query the device for it's RF Kill switches status + * and feed it back to the WiMAX stack using + * wimax_report_rfkill_{hw,sw}(). If any switch is missing, always + * report it as ON. + * + * NOTE: the wimax stack uses an inverted terminology to that of the + * RFKILL subsystem: + * + * - ON: radio is ON, RFKILL is DISABLED or OFF. + * - OFF: radio is OFF, RFKILL is ENABLED or ON. + * + * MISCELLANEOUS OPS: + * + * wimax_reset() can be used to reset the device to power on state; by + * default it issues a warm reset that maintains the same device + * node. If that is not possible, it falls back to a cold reset + * (device reconnect). The driver implements the backend to this + * through wimax_dev->op_reset(). + */ + +#ifndef __NET__WIMAX_H__ +#define __NET__WIMAX_H__ +#ifdef __KERNEL__ + +#include <linux/wimax.h> +#include <net/genetlink.h> +#include <linux/netdevice.h> + +struct net_device; +struct genl_info; +struct wimax_dev; + +/** + * struct wimax_dev - Generic WiMAX device + * + * @net_dev: [fill] Pointer to the &struct net_device this WiMAX + * device implements. + * + * @op_msg_from_user: [fill] Driver-specific operation to + * handle a raw message from user space to the driver. The + * driver can send messages to user space using with + * wimax_msg_to_user(). + * + * @op_rfkill_sw_toggle: [fill] Driver-specific operation to act on + * userspace (or any other agent) requesting the WiMAX device to + * change the RF Kill software switch (WIMAX_RF_ON or + * WIMAX_RF_OFF). + * If such hardware support is not present, it is assumed the + * radio cannot be switched off and it is always on (and the stack + * will error out when trying to switch it off). In such case, + * this function pointer can be left as NULL. + * + * @op_reset: [fill] Driver specific operation to reset the + * device. + * This operation should always attempt first a warm reset that + * does not disconnect the device from the bus and return 0. + * If that fails, it should resort to some sort of cold or bus + * reset (even if it implies a bus disconnection and device + * dissapearance). In that case, -ENODEV should be returned to + * indicate the device is gone. + * This operation has to be synchronous, and return only when the + * reset is complete. In case of having had to resort to bus/cold + * reset implying a device disconnection, the call is allowed to + * return inmediately. + * NOTE: wimax_dev->mutex is NOT locked when this op is being + * called; however, wimax_dev->mutex_reset IS locked to ensure + * serialization of calls to wimax_reset(). + * See wimax_reset()'s documentation. + * + * @name: [fill] A way to identify this device. We need to register a + * name with many subsystems (rfkill, workqueue creation, etc). + * We can't use the network device name as that + * might change and in some instances we don't know it yet (until + * we don't call register_netdev()). So we generate an unique one + * using the driver name and device bus id, place it here and use + * it across the board. Recommended naming: + * DRIVERNAME-BUSNAME:BUSID (dev->bus->name, dev->bus_id). + * + * @id_table_node: [private] link to the list of wimax devices kept by + * id-table.c. Protected by it's own spinlock. + * + * @mutex: [private] Serializes all concurrent access and execution of + * operations. + * + * @mutex_reset: [private] Serializes reset operations. Needs to be a + * different mutex because as part of the reset operation, the + * driver has to call back into the stack to do things such as + * state change, that require wimax_dev->mutex. + * + * @state: [private] Current state of the WiMAX device. + * + * @rfkill: [private] integration into the RF-Kill infrastructure. + * + * @rf_sw: [private] State of the software radio switch (OFF/ON) + * + * @rf_hw: [private] State of the hardware radio switch (OFF/ON) + * + * @debugfs_dentry: [private] Used to hook up a debugfs entry. This + * shows up in the debugfs root as wimax\:DEVICENAME. + * + * Description: + * This structure defines a common interface to access all WiMAX + * devices from different vendors and provides a common API as well as + * a free-form device-specific messaging channel. + * + * Usage: + * 1. Embed a &struct wimax_dev at *the beginning* the network + * device structure so that netdev_priv() points to it. + * + * 2. memset() it to zero + * + * 3. Initialize with wimax_dev_init(). This will leave the WiMAX + * device in the %__WIMAX_ST_NULL state. + * + * 4. Fill all the fields marked with [fill]; once called + * wimax_dev_add(), those fields CANNOT be modified. + * + * 5. Call wimax_dev_add() *after* registering the network + * device. This will leave the WiMAX device in the %WIMAX_ST_DOWN + * state. + * Protect the driver's net_device->open() against succeeding if + * the wimax device state is lower than %WIMAX_ST_DOWN. + * + * 6. Select when the device is going to be turned on/initialized; + * for example, it could be initialized on 'ifconfig up' (when the + * netdev op 'open()' is called on the driver). + * + * When the device is initialized (at `ifconfig up` time, or right + * after calling wimax_dev_add() from _probe(), make sure the + * following steps are taken + * + * a. Move the device to %WIMAX_ST_UNINITIALIZED. This is needed so + * some API calls that shouldn't work until the device is ready + * can be blocked. + * + * b. Initialize the device. Make sure to turn the SW radio switch + * off and move the device to state %WIMAX_ST_RADIO_OFF when + * done. When just initialized, a device should be left in RADIO + * OFF state until user space devices to turn it on. + * + * c. Query the device for the state of the hardware rfkill switch + * and call wimax_rfkill_report_hw() and wimax_rfkill_report_sw() + * as needed. See below. + * + * wimax_dev_rm() undoes before unregistering the network device. Once + * wimax_dev_add() is called, the driver can get called on the + * wimax_dev->op_* function pointers + * + * CONCURRENCY: + * + * The stack provides a mutex for each device that will disallow API + * calls happening concurrently; thus, op calls into the driver + * through the wimax_dev->op*() function pointers will always be + * serialized and *never* concurrent. + * + * For locking, take wimax_dev->mutex is taken; (most) operations in + * the API have to check for wimax_dev_is_ready() to return 0 before + * continuing (this is done internally). + * + * REFERENCE COUNTING: + * + * The WiMAX device is reference counted by the associated network + * device. The only operation that can be used to reference the device + * is wimax_dev_get_by_genl_info(), and the reference it acquires has + * to be released with dev_put(wimax_dev->net_dev). + * + * RFKILL: + * + * At startup, both HW and SW radio switchess are assumed to be off. + * + * At initialization time [after calling wimax_dev_add()], have the + * driver query the device for the status of the software and hardware + * RF kill switches and call wimax_report_rfkill_hw() and + * wimax_rfkill_report_sw() to indicate their state. If any is + * missing, just call it to indicate it is ON (radio always on). + * + * Whenever the driver detects a change in the state of the RF kill + * switches, it should call wimax_report_rfkill_hw() or + * wimax_report_rfkill_sw() to report it to the stack. + */ +struct wimax_dev { + struct net_device *net_dev; + struct list_head id_table_node; + struct mutex mutex; /* Protects all members and API calls */ + struct mutex mutex_reset; + enum wimax_st state; + + int (*op_msg_from_user)(struct wimax_dev *wimax_dev, + const char *, + const void *, size_t, + const struct genl_info *info); + int (*op_rfkill_sw_toggle)(struct wimax_dev *wimax_dev, + enum wimax_rf_state); + int (*op_reset)(struct wimax_dev *wimax_dev); + + struct rfkill *rfkill; + struct input_dev *rfkill_input; + unsigned rf_hw; + unsigned rf_sw; + char name[32]; + + struct dentry *debugfs_dentry; +}; + + + +/* + * WiMAX stack public API for device drivers + * ----------------------------------------- + * + * These functions are not exported to user space. + */ +extern void wimax_dev_init(struct wimax_dev *); +extern int wimax_dev_add(struct wimax_dev *, struct net_device *); +extern void wimax_dev_rm(struct wimax_dev *); + +static inline +struct wimax_dev *net_dev_to_wimax(struct net_device *net_dev) +{ + return netdev_priv(net_dev); +} + +static inline +struct device *wimax_dev_to_dev(struct wimax_dev *wimax_dev) +{ + return wimax_dev->net_dev->dev.parent; +} + +extern void wimax_state_change(struct wimax_dev *, enum wimax_st); +extern enum wimax_st wimax_state_get(struct wimax_dev *); + +/* + * Radio Switch state reporting. + * + * enum wimax_rf_state is declared in linux/wimax.h so the exports + * to user space can use it. + */ +extern void wimax_report_rfkill_hw(struct wimax_dev *, enum wimax_rf_state); +extern void wimax_report_rfkill_sw(struct wimax_dev *, enum wimax_rf_state); + + +/* + * Free-form messaging to/from user space + * + * Sending a message: + * + * wimax_msg(wimax_dev, pipe_name, buf, buf_size, GFP_KERNEL); + * + * Broken up: + * + * skb = wimax_msg_alloc(wimax_dev, pipe_name, buf_size, GFP_KERNEL); + * ...fill up skb... + * wimax_msg_send(wimax_dev, pipe_name, skb); + * + * Be sure not to modify skb->data in the middle (ie: don't use + * skb_push()/skb_pull()/skb_reserve() on the skb). + * + * "pipe_name" is any string, than can be interpreted as the name of + * the pipe or destinatary; the interpretation of it is driver + * specific, so the recipient can multiplex it as wished. It can be + * NULL, it won't be used - an example is using a "diagnostics" tag to + * send diagnostics information that a device-specific diagnostics + * tool would be interested in. + */ +extern struct sk_buff *wimax_msg_alloc(struct wimax_dev *, const char *, + const void *, size_t, gfp_t); +extern int wimax_msg_send(struct wimax_dev *, struct sk_buff *); +extern int wimax_msg(struct wimax_dev *, const char *, + const void *, size_t, gfp_t); + +extern const void *wimax_msg_data_len(struct sk_buff *, size_t *); +extern const void *wimax_msg_data(struct sk_buff *); +extern ssize_t wimax_msg_len(struct sk_buff *); + + +/* + * WiMAX stack user space API + * -------------------------- + * + * This API is what gets exported to user space for general + * operations. As well, they can be called from within the kernel, + * (with a properly referenced `struct wimax_dev`). + * + * Properly referenced means: the 'struct net_device' that embeds the + * device's control structure and (as such) the 'struct wimax_dev' is + * referenced by the caller. + */ +extern int wimax_rfkill(struct wimax_dev *, enum wimax_rf_state); +extern int wimax_reset(struct wimax_dev *); + +#else +/* You might be looking for linux/wimax.h */ +#error This file should not be included from user space. +#endif /* #ifdef __KERNEL__ */ +#endif /* #ifndef __NET__WIMAX_H__ */ diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h new file mode 100644 index 00000000..85926231 --- /dev/null +++ b/include/net/wpan-phy.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> + */ + +#ifndef WPAN_PHY_H +#define WPAN_PHY_H + +#include <linux/netdevice.h> +#include <linux/mutex.h> + +struct wpan_phy { + struct mutex pib_lock; + + /* + * This is a PIB acording to 802.15.4-2006. + * We do not provide timing-related variables, as they + * aren't used outside of driver + */ + u8 current_channel; + u8 current_page; + u32 channels_supported[32]; + u8 transmit_power; + u8 cca_mode; + + struct device dev; + int idx; + + struct net_device *(*add_iface)(struct wpan_phy *phy, + const char *name); + void (*del_iface)(struct wpan_phy *phy, struct net_device *dev); + + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) + +struct wpan_phy *wpan_phy_alloc(size_t priv_size); +static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev) +{ + phy->dev.parent = dev; +} +int wpan_phy_register(struct wpan_phy *phy); +void wpan_phy_unregister(struct wpan_phy *phy); +void wpan_phy_free(struct wpan_phy *phy); +/* Same semantics as for class_for_each_device */ +int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), void *data); + +static inline void *wpan_phy_priv(struct wpan_phy *phy) +{ + BUG_ON(!phy); + return &phy->priv; +} + +struct wpan_phy *wpan_phy_find(const char *str); + +static inline void wpan_phy_put(struct wpan_phy *phy) +{ + put_device(&phy->dev); +} + +static inline const char *wpan_phy_name(struct wpan_phy *phy) +{ + return dev_name(&phy->dev); +} +#endif diff --git a/include/net/x25.h b/include/net/x25.h new file mode 100644 index 00000000..1479cb4a --- /dev/null +++ b/include/net/x25.h @@ -0,0 +1,321 @@ +/* + * Declarations of X.25 Packet Layer type objects. + * + * History + * nov/17/96 Jonathan Naylor Initial version. + * mar/20/00 Daniela Squassoni Disabling/enabling of facilities + * negotiation. + */ + +#ifndef _X25_H +#define _X25_H +#include <linux/x25.h> +#include <linux/slab.h> +#include <net/sock.h> + +#define X25_ADDR_LEN 16 + +#define X25_MAX_L2_LEN 18 /* 802.2 LLC */ + +#define X25_STD_MIN_LEN 3 +#define X25_EXT_MIN_LEN 4 + +#define X25_GFI_SEQ_MASK 0x30 +#define X25_GFI_STDSEQ 0x10 +#define X25_GFI_EXTSEQ 0x20 + +#define X25_Q_BIT 0x80 +#define X25_D_BIT 0x40 +#define X25_STD_M_BIT 0x10 +#define X25_EXT_M_BIT 0x01 + +#define X25_CALL_REQUEST 0x0B +#define X25_CALL_ACCEPTED 0x0F +#define X25_CLEAR_REQUEST 0x13 +#define X25_CLEAR_CONFIRMATION 0x17 +#define X25_DATA 0x00 +#define X25_INTERRUPT 0x23 +#define X25_INTERRUPT_CONFIRMATION 0x27 +#define X25_RR 0x01 +#define X25_RNR 0x05 +#define X25_REJ 0x09 +#define X25_RESET_REQUEST 0x1B +#define X25_RESET_CONFIRMATION 0x1F +#define X25_REGISTRATION_REQUEST 0xF3 +#define X25_REGISTRATION_CONFIRMATION 0xF7 +#define X25_RESTART_REQUEST 0xFB +#define X25_RESTART_CONFIRMATION 0xFF +#define X25_DIAGNOSTIC 0xF1 +#define X25_ILLEGAL 0xFD + +/* Define the various conditions that may exist */ + +#define X25_COND_ACK_PENDING 0x01 +#define X25_COND_OWN_RX_BUSY 0x02 +#define X25_COND_PEER_RX_BUSY 0x04 + +/* Define Link State constants. */ +enum { + X25_STATE_0, /* Ready */ + X25_STATE_1, /* Awaiting Call Accepted */ + X25_STATE_2, /* Awaiting Clear Confirmation */ + X25_STATE_3, /* Data Transfer */ + X25_STATE_4 /* Awaiting Reset Confirmation */ +}; + +enum { + X25_LINK_STATE_0, + X25_LINK_STATE_1, + X25_LINK_STATE_2, + X25_LINK_STATE_3 +}; + +#define X25_DEFAULT_T20 (180 * HZ) /* Default T20 value */ +#define X25_DEFAULT_T21 (200 * HZ) /* Default T21 value */ +#define X25_DEFAULT_T22 (180 * HZ) /* Default T22 value */ +#define X25_DEFAULT_T23 (180 * HZ) /* Default T23 value */ +#define X25_DEFAULT_T2 (3 * HZ) /* Default ack holdback value */ + +#define X25_DEFAULT_WINDOW_SIZE 2 /* Default Window Size */ +#define X25_DEFAULT_PACKET_SIZE X25_PS128 /* Default Packet Size */ +#define X25_DEFAULT_THROUGHPUT 0x0A /* Deafult Throughput */ +#define X25_DEFAULT_REVERSE 0x00 /* Default Reverse Charging */ + +#define X25_SMODULUS 8 +#define X25_EMODULUS 128 + +/* + * X.25 Facilities constants. + */ + +#define X25_FAC_CLASS_MASK 0xC0 + +#define X25_FAC_CLASS_A 0x00 +#define X25_FAC_CLASS_B 0x40 +#define X25_FAC_CLASS_C 0x80 +#define X25_FAC_CLASS_D 0xC0 + +#define X25_FAC_REVERSE 0x01 /* also fast select */ +#define X25_FAC_THROUGHPUT 0x02 +#define X25_FAC_PACKET_SIZE 0x42 +#define X25_FAC_WINDOW_SIZE 0x43 + +#define X25_MAX_FAC_LEN 60 +#define X25_MAX_CUD_LEN 128 + +#define X25_FAC_CALLING_AE 0xCB +#define X25_FAC_CALLED_AE 0xC9 + +#define X25_MARKER 0x00 +#define X25_DTE_SERVICES 0x0F +#define X25_MAX_AE_LEN 40 /* Max num of semi-octets in AE - OSI Nw */ +#define X25_MAX_DTE_FACIL_LEN 21 /* Max length of DTE facility params */ + +/* Bitset in x25_sock->flags for misc flags */ +#define X25_Q_BIT_FLAG 0 +#define X25_INTERRUPT_FLAG 1 +#define X25_ACCPT_APPRV_FLAG 2 + +/** + * struct x25_route - x25 routing entry + * @node - entry in x25_list_lock + * @address - Start of address range + * @sigdigits - Number of sig digits + * @dev - More than one for MLP + * @refcnt - reference counter + */ +struct x25_route { + struct list_head node; + struct x25_address address; + unsigned int sigdigits; + struct net_device *dev; + atomic_t refcnt; +}; + +struct x25_neigh { + struct list_head node; + struct net_device *dev; + unsigned int state; + unsigned int extended; + struct sk_buff_head queue; + unsigned long t20; + struct timer_list t20timer; + unsigned long global_facil_mask; + atomic_t refcnt; +}; + +struct x25_sock { + struct sock sk; + struct x25_address source_addr, dest_addr; + struct x25_neigh *neighbour; + unsigned int lci, cudmatchlength; + unsigned char state, condition; + unsigned short vs, vr, va, vl; + unsigned long t2, t21, t22, t23; + unsigned short fraglen; + unsigned long flags; + struct sk_buff_head ack_queue; + struct sk_buff_head fragment_queue; + struct sk_buff_head interrupt_in_queue; + struct sk_buff_head interrupt_out_queue; + struct timer_list timer; + struct x25_causediag causediag; + struct x25_facilities facilities; + struct x25_dte_facilities dte_facilities; + struct x25_calluserdata calluserdata; + unsigned long vc_facil_mask; /* inc_call facilities mask */ +}; + +struct x25_forward { + struct list_head node; + unsigned int lci; + struct net_device *dev1; + struct net_device *dev2; + atomic_t refcnt; +}; + +static inline struct x25_sock *x25_sk(const struct sock *sk) +{ + return (struct x25_sock *)sk; +} + +/* af_x25.c */ +extern int sysctl_x25_restart_request_timeout; +extern int sysctl_x25_call_request_timeout; +extern int sysctl_x25_reset_request_timeout; +extern int sysctl_x25_clear_request_timeout; +extern int sysctl_x25_ack_holdback_timeout; +extern int sysctl_x25_forward; + +extern int x25_parse_address_block(struct sk_buff *skb, + struct x25_address *called_addr, + struct x25_address *calling_addr); + +extern int x25_addr_ntoa(unsigned char *, struct x25_address *, + struct x25_address *); +extern int x25_addr_aton(unsigned char *, struct x25_address *, + struct x25_address *); +extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *); +extern void x25_destroy_socket_from_timer(struct sock *); +extern int x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int); +extern void x25_kill_by_neigh(struct x25_neigh *); + +/* x25_dev.c */ +extern void x25_send_frame(struct sk_buff *, struct x25_neigh *); +extern int x25_lapb_receive_frame(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); +extern void x25_establish_link(struct x25_neigh *); +extern void x25_terminate_link(struct x25_neigh *); + +/* x25_facilities.c */ +extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *, + struct x25_dte_facilities *, unsigned long *); +extern int x25_create_facilities(unsigned char *, struct x25_facilities *, + struct x25_dte_facilities *, unsigned long); +extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, + struct x25_facilities *, + struct x25_dte_facilities *); +extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); + +/* x25_forward.c */ +extern void x25_clear_forward_by_lci(unsigned int lci); +extern void x25_clear_forward_by_dev(struct net_device *); +extern int x25_forward_data(int, struct x25_neigh *, struct sk_buff *); +extern int x25_forward_call(struct x25_address *, struct x25_neigh *, + struct sk_buff *, int); + +/* x25_in.c */ +extern int x25_process_rx_frame(struct sock *, struct sk_buff *); +extern int x25_backlog_rcv(struct sock *, struct sk_buff *); + +/* x25_link.c */ +extern void x25_link_control(struct sk_buff *, struct x25_neigh *, unsigned short); +extern void x25_link_device_up(struct net_device *); +extern void x25_link_device_down(struct net_device *); +extern void x25_link_established(struct x25_neigh *); +extern void x25_link_terminated(struct x25_neigh *); +extern void x25_transmit_clear_request(struct x25_neigh *, unsigned int, unsigned char); +extern void x25_transmit_link(struct sk_buff *, struct x25_neigh *); +extern int x25_subscr_ioctl(unsigned int, void __user *); +extern struct x25_neigh *x25_get_neigh(struct net_device *); +extern void x25_link_free(void); + +/* x25_neigh.c */ +static __inline__ void x25_neigh_hold(struct x25_neigh *nb) +{ + atomic_inc(&nb->refcnt); +} + +static __inline__ void x25_neigh_put(struct x25_neigh *nb) +{ + if (atomic_dec_and_test(&nb->refcnt)) + kfree(nb); +} + +/* x25_out.c */ +extern int x25_output(struct sock *, struct sk_buff *); +extern void x25_kick(struct sock *); +extern void x25_enquiry_response(struct sock *); + +/* x25_route.c */ +extern struct x25_route *x25_get_route(struct x25_address *addr); +extern struct net_device *x25_dev_get(char *); +extern void x25_route_device_down(struct net_device *dev); +extern int x25_route_ioctl(unsigned int, void __user *); +extern void x25_route_free(void); + +static __inline__ void x25_route_hold(struct x25_route *rt) +{ + atomic_inc(&rt->refcnt); +} + +static __inline__ void x25_route_put(struct x25_route *rt) +{ + if (atomic_dec_and_test(&rt->refcnt)) + kfree(rt); +} + +/* x25_subr.c */ +extern void x25_clear_queues(struct sock *); +extern void x25_frames_acked(struct sock *, unsigned short); +extern void x25_requeue_frames(struct sock *); +extern int x25_validate_nr(struct sock *, unsigned short); +extern void x25_write_internal(struct sock *, int); +extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *); +extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char); + +/* x25_timer.c */ +extern void x25_init_timers(struct sock *sk); +extern void x25_start_heartbeat(struct sock *); +extern void x25_start_t2timer(struct sock *); +extern void x25_start_t21timer(struct sock *); +extern void x25_start_t22timer(struct sock *); +extern void x25_start_t23timer(struct sock *); +extern void x25_stop_heartbeat(struct sock *); +extern void x25_stop_timer(struct sock *); +extern unsigned long x25_display_timer(struct sock *); +extern void x25_check_rbuf(struct sock *); + +/* sysctl_net_x25.c */ +#ifdef CONFIG_SYSCTL +extern void x25_register_sysctl(void); +extern void x25_unregister_sysctl(void); +#else +static inline void x25_register_sysctl(void) {}; +static inline void x25_unregister_sysctl(void) {}; +#endif /* CONFIG_SYSCTL */ + +struct x25_skb_cb { + unsigned flags; +}; +#define X25_SKB_CB(s) ((struct x25_skb_cb *) ((s)->cb)) + +extern struct hlist_head x25_list; +extern rwlock_t x25_list_lock; +extern struct list_head x25_route_list; +extern rwlock_t x25_route_list_lock; +extern struct list_head x25_forward_list; +extern rwlock_t x25_forward_list_lock; + +extern int x25_proc_init(void); +extern void x25_proc_exit(void); +#endif diff --git a/include/net/x25device.h b/include/net/x25device.h new file mode 100644 index 00000000..1fa08b49 --- /dev/null +++ b/include/net/x25device.h @@ -0,0 +1,17 @@ +#ifndef _X25DEVICE_H +#define _X25DEVICE_H + +#include <linux/if_ether.h> +#include <linux/if_packet.h> +#include <linux/if_x25.h> +#include <linux/skbuff.h> + +static inline __be16 x25_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + skb->dev = dev; + skb_reset_mac_header(skb); + skb->pkt_type = PACKET_HOST; + + return htons(ETH_P_X25); +} +#endif diff --git a/include/net/xfrm.h b/include/net/xfrm.h new file mode 100644 index 00000000..4f53532d --- /dev/null +++ b/include/net/xfrm.h @@ -0,0 +1,1606 @@ +#ifndef _NET_XFRM_H +#define _NET_XFRM_H + +#include <linux/compiler.h> +#include <linux/xfrm.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/skbuff.h> +#include <linux/socket.h> +#include <linux/pfkeyv2.h> +#include <linux/ipsec.h> +#include <linux/in6.h> +#include <linux/mutex.h> +#include <linux/audit.h> +#include <linux/slab.h> + +#include <net/sock.h> +#include <net/dst.h> +#include <net/ip.h> +#include <net/route.h> +#include <net/ipv6.h> +#include <net/ip6_fib.h> +#include <net/flow.h> + +#include <linux/interrupt.h> + +#ifdef CONFIG_XFRM_STATISTICS +#include <net/snmp.h> +#endif + +#define XFRM_PROTO_ESP 50 +#define XFRM_PROTO_AH 51 +#define XFRM_PROTO_COMP 108 +#define XFRM_PROTO_IPIP 4 +#define XFRM_PROTO_IPV6 41 +#define XFRM_PROTO_ROUTING IPPROTO_ROUTING +#define XFRM_PROTO_DSTOPTS IPPROTO_DSTOPTS + +#define XFRM_ALIGN8(len) (((len) + 7) & ~7) +#define MODULE_ALIAS_XFRM_MODE(family, encap) \ + MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap)) +#define MODULE_ALIAS_XFRM_TYPE(family, proto) \ + MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto)) + +#ifdef CONFIG_XFRM_STATISTICS +#define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field) +#define XFRM_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.xfrm_statistics, field) +#define XFRM_INC_STATS_USER(net, field) SNMP_INC_STATS_USER((net)-mib.xfrm_statistics, field) +#else +#define XFRM_INC_STATS(net, field) ((void)(net)) +#define XFRM_INC_STATS_BH(net, field) ((void)(net)) +#define XFRM_INC_STATS_USER(net, field) ((void)(net)) +#endif + +extern struct mutex xfrm_cfg_mutex; + +/* Organization of SPD aka "XFRM rules" + ------------------------------------ + + Basic objects: + - policy rule, struct xfrm_policy (=SPD entry) + - bundle of transformations, struct dst_entry == struct xfrm_dst (=SA bundle) + - instance of a transformer, struct xfrm_state (=SA) + - template to clone xfrm_state, struct xfrm_tmpl + + SPD is plain linear list of xfrm_policy rules, ordered by priority. + (To be compatible with existing pfkeyv2 implementations, + many rules with priority of 0x7fffffff are allowed to exist and + such rules are ordered in an unpredictable way, thanks to bsd folks.) + + Lookup is plain linear search until the first match with selector. + + If "action" is "block", then we prohibit the flow, otherwise: + if "xfrms_nr" is zero, the flow passes untransformed. Otherwise, + policy entry has list of up to XFRM_MAX_DEPTH transformations, + described by templates xfrm_tmpl. Each template is resolved + to a complete xfrm_state (see below) and we pack bundle of transformations + to a dst_entry returned to requestor. + + dst -. xfrm .-> xfrm_state #1 + |---. child .-> dst -. xfrm .-> xfrm_state #2 + |---. child .-> dst -. xfrm .-> xfrm_state #3 + |---. child .-> NULL + + Bundles are cached at xrfm_policy struct (field ->bundles). + + + Resolution of xrfm_tmpl + ----------------------- + Template contains: + 1. ->mode Mode: transport or tunnel + 2. ->id.proto Protocol: AH/ESP/IPCOMP + 3. ->id.daddr Remote tunnel endpoint, ignored for transport mode. + Q: allow to resolve security gateway? + 4. ->id.spi If not zero, static SPI. + 5. ->saddr Local tunnel endpoint, ignored for transport mode. + 6. ->algos List of allowed algos. Plain bitmask now. + Q: ealgos, aalgos, calgos. What a mess... + 7. ->share Sharing mode. + Q: how to implement private sharing mode? To add struct sock* to + flow id? + + Having this template we search through SAD searching for entries + with appropriate mode/proto/algo, permitted by selector. + If no appropriate entry found, it is requested from key manager. + + PROBLEMS: + Q: How to find all the bundles referring to a physical path for + PMTU discovery? Seems, dst should contain list of all parents... + and enter to infinite locking hierarchy disaster. + No! It is easier, we will not search for them, let them find us. + We add genid to each dst plus pointer to genid of raw IP route, + pmtu disc will update pmtu on raw IP route and increase its genid. + dst_check() will see this for top level and trigger resyncing + metrics. Plus, it will be made via sk->sk_dst_cache. Solved. + */ + +struct xfrm_state_walk { + struct list_head all; + u8 state; + union { + u8 dying; + u8 proto; + }; + u32 seq; +}; + +/* Full description of state of transformer. */ +struct xfrm_state { +#ifdef CONFIG_NET_NS + struct net *xs_net; +#endif + union { + struct hlist_node gclist; + struct hlist_node bydst; + }; + struct hlist_node bysrc; + struct hlist_node byspi; + + atomic_t refcnt; + spinlock_t lock; + + struct xfrm_id id; + struct xfrm_selector sel; + struct xfrm_mark mark; + + u32 genid; + + /* Key manager bits */ + struct xfrm_state_walk km; + + /* Parameters of this state. */ + struct { + u32 reqid; + u8 mode; + u8 replay_window; + u8 aalgo, ealgo, calgo; + u8 flags; + u16 family; + xfrm_address_t saddr; + int header_len; + int trailer_len; + } props; + + struct xfrm_lifetime_cfg lft; + + /* Data for transformer */ + struct xfrm_algo_auth *aalg; + struct xfrm_algo *ealg; + struct xfrm_algo *calg; + struct xfrm_algo_aead *aead; + + /* Data for encapsulator */ + struct xfrm_encap_tmpl *encap; + + /* Data for care-of address */ + xfrm_address_t *coaddr; + + /* IPComp needs an IPIP tunnel for handling uncompressed packets */ + struct xfrm_state *tunnel; + + /* If a tunnel, number of users + 1 */ + atomic_t tunnel_users; + + /* State for replay detection */ + struct xfrm_replay_state replay; + + /* Replay detection state at the time we sent the last notification */ + struct xfrm_replay_state preplay; + + /* internal flag that only holds state for delayed aevent at the + * moment + */ + u32 xflags; + + /* Replay detection notification settings */ + u32 replay_maxage; + u32 replay_maxdiff; + + /* Replay detection notification timer */ + struct timer_list rtimer; + + /* Statistics */ + struct xfrm_stats stats; + + struct xfrm_lifetime_cur curlft; + struct tasklet_hrtimer mtimer; + + /* Last used time */ + unsigned long lastused; + + /* Reference to data common to all the instances of this + * transformer. */ + const struct xfrm_type *type; + struct xfrm_mode *inner_mode; + struct xfrm_mode *inner_mode_iaf; + struct xfrm_mode *outer_mode; + + /* Security context */ + struct xfrm_sec_ctx *security; + + /* Private data of this transformer, format is opaque, + * interpreted by xfrm_type methods. */ + void *data; +}; + +static inline struct net *xs_net(struct xfrm_state *x) +{ + return read_pnet(&x->xs_net); +} + +/* xflags - make enum if more show up */ +#define XFRM_TIME_DEFER 1 + +enum { + XFRM_STATE_VOID, + XFRM_STATE_ACQ, + XFRM_STATE_VALID, + XFRM_STATE_ERROR, + XFRM_STATE_EXPIRED, + XFRM_STATE_DEAD +}; + +/* callback structure passed from either netlink or pfkey */ +struct km_event { + union { + u32 hard; + u32 proto; + u32 byid; + u32 aevent; + u32 type; + } data; + + u32 seq; + u32 pid; + u32 event; + struct net *net; +}; + +struct net_device; +struct xfrm_type; +struct xfrm_dst; +struct xfrm_policy_afinfo { + unsigned short family; + struct dst_ops *dst_ops; + void (*garbage_collect)(struct net *net); + struct dst_entry *(*dst_lookup)(struct net *net, int tos, + xfrm_address_t *saddr, + xfrm_address_t *daddr); + int (*get_saddr)(struct net *net, xfrm_address_t *saddr, xfrm_address_t *daddr); + void (*decode_session)(struct sk_buff *skb, + struct flowi *fl, + int reverse); + int (*get_tos)(struct flowi *fl); + int (*init_path)(struct xfrm_dst *path, + struct dst_entry *dst, + int nfheader_len); + int (*fill_dst)(struct xfrm_dst *xdst, + struct net_device *dev, + struct flowi *fl); +}; + +extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); +extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo); +extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c); +extern void km_state_notify(struct xfrm_state *x, struct km_event *c); + +struct xfrm_tmpl; +extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); +extern void km_state_expired(struct xfrm_state *x, int hard, u32 pid); +extern int __xfrm_state_delete(struct xfrm_state *x); + +struct xfrm_state_afinfo { + unsigned int family; + unsigned int proto; + __be16 eth_proto; + struct module *owner; + const struct xfrm_type *type_map[IPPROTO_MAX]; + struct xfrm_mode *mode_map[XFRM_MODE_MAX]; + int (*init_flags)(struct xfrm_state *x); + void (*init_tempsel)(struct xfrm_selector *sel, struct flowi *fl); + void (*init_temprop)(struct xfrm_state *x, struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr); + int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); + int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); + int (*output)(struct sk_buff *skb); + int (*extract_input)(struct xfrm_state *x, + struct sk_buff *skb); + int (*extract_output)(struct xfrm_state *x, + struct sk_buff *skb); + int (*transport_finish)(struct sk_buff *skb, + int async); +}; + +extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); +extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); + +extern void xfrm_state_delete_tunnel(struct xfrm_state *x); + +struct xfrm_type { + char *description; + struct module *owner; + u8 proto; + u8 flags; +#define XFRM_TYPE_NON_FRAGMENT 1 +#define XFRM_TYPE_REPLAY_PROT 2 +#define XFRM_TYPE_LOCAL_COADDR 4 +#define XFRM_TYPE_REMOTE_COADDR 8 + + int (*init_state)(struct xfrm_state *x); + void (*destructor)(struct xfrm_state *); + int (*input)(struct xfrm_state *, struct sk_buff *skb); + int (*output)(struct xfrm_state *, struct sk_buff *pskb); + int (*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *); + int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **); + /* Estimate maximal size of result of transformation of a dgram */ + u32 (*get_mtu)(struct xfrm_state *, int size); +}; + +extern int xfrm_register_type(const struct xfrm_type *type, unsigned short family); +extern int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family); + +struct xfrm_mode { + /* + * Remove encapsulation header. + * + * The IP header will be moved over the top of the encapsulation + * header. + * + * On entry, the transport header shall point to where the IP header + * should be and the network header shall be set to where the IP + * header currently is. skb->data shall point to the start of the + * payload. + */ + int (*input2)(struct xfrm_state *x, struct sk_buff *skb); + + /* + * This is the actual input entry point. + * + * For transport mode and equivalent this would be identical to + * input2 (which does not need to be set). While tunnel mode + * and equivalent would set this to the tunnel encapsulation function + * xfrm4_prepare_input that would in turn call input2. + */ + int (*input)(struct xfrm_state *x, struct sk_buff *skb); + + /* + * Add encapsulation header. + * + * On exit, the transport header will be set to the start of the + * encapsulation header to be filled in by x->type->output and + * the mac header will be set to the nextheader (protocol for + * IPv4) field of the extension header directly preceding the + * encapsulation header, or in its absence, that of the top IP + * header. The value of the network header will always point + * to the top IP header while skb->data will point to the payload. + */ + int (*output2)(struct xfrm_state *x,struct sk_buff *skb); + + /* + * This is the actual output entry point. + * + * For transport mode and equivalent this would be identical to + * output2 (which does not need to be set). While tunnel mode + * and equivalent would set this to a tunnel encapsulation function + * (xfrm4_prepare_output or xfrm6_prepare_output) that would in turn + * call output2. + */ + int (*output)(struct xfrm_state *x, struct sk_buff *skb); + + struct xfrm_state_afinfo *afinfo; + struct module *owner; + unsigned int encap; + int flags; +}; + +/* Flags for xfrm_mode. */ +enum { + XFRM_MODE_FLAG_TUNNEL = 1, +}; + +extern int xfrm_register_mode(struct xfrm_mode *mode, int family); +extern int xfrm_unregister_mode(struct xfrm_mode *mode, int family); + +static inline int xfrm_af2proto(unsigned int family) +{ + switch(family) { + case AF_INET: + return IPPROTO_IPIP; + case AF_INET6: + return IPPROTO_IPV6; + default: + return 0; + } +} + +static inline struct xfrm_mode *xfrm_ip2inner_mode(struct xfrm_state *x, int ipproto) +{ + if ((ipproto == IPPROTO_IPIP && x->props.family == AF_INET) || + (ipproto == IPPROTO_IPV6 && x->props.family == AF_INET6)) + return x->inner_mode; + else + return x->inner_mode_iaf; +} + +struct xfrm_tmpl { +/* id in template is interpreted as: + * daddr - destination of tunnel, may be zero for transport mode. + * spi - zero to acquire spi. Not zero if spi is static, then + * daddr must be fixed too. + * proto - AH/ESP/IPCOMP + */ + struct xfrm_id id; + +/* Source address of tunnel. Ignored, if it is not a tunnel. */ + xfrm_address_t saddr; + + unsigned short encap_family; + + u32 reqid; + +/* Mode: transport, tunnel etc. */ + u8 mode; + +/* Sharing mode: unique, this session only, this user only etc. */ + u8 share; + +/* May skip this transfomration if no SA is found */ + u8 optional; + +/* Skip aalgos/ealgos/calgos checks. */ + u8 allalgs; + +/* Bit mask of algos allowed for acquisition */ + u32 aalgos; + u32 ealgos; + u32 calgos; +}; + +#define XFRM_MAX_DEPTH 6 + +struct xfrm_policy_walk_entry { + struct list_head all; + u8 dead; +}; + +struct xfrm_policy_walk { + struct xfrm_policy_walk_entry walk; + u8 type; + u32 seq; +}; + +struct xfrm_policy { +#ifdef CONFIG_NET_NS + struct net *xp_net; +#endif + struct hlist_node bydst; + struct hlist_node byidx; + + /* This lock only affects elements except for entry. */ + rwlock_t lock; + atomic_t refcnt; + struct timer_list timer; + + struct flow_cache_object flo; + atomic_t genid; + u32 priority; + u32 index; + struct xfrm_mark mark; + struct xfrm_selector selector; + struct xfrm_lifetime_cfg lft; + struct xfrm_lifetime_cur curlft; + struct xfrm_policy_walk_entry walk; + u8 type; + u8 action; + u8 flags; + u8 xfrm_nr; + u16 family; + struct xfrm_sec_ctx *security; + struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; +}; + +static inline struct net *xp_net(struct xfrm_policy *xp) +{ + return read_pnet(&xp->xp_net); +} + +struct xfrm_kmaddress { + xfrm_address_t local; + xfrm_address_t remote; + u32 reserved; + u16 family; +}; + +struct xfrm_migrate { + xfrm_address_t old_daddr; + xfrm_address_t old_saddr; + xfrm_address_t new_daddr; + xfrm_address_t new_saddr; + u8 proto; + u8 mode; + u16 reserved; + u32 reqid; + u16 old_family; + u16 new_family; +}; + +#define XFRM_KM_TIMEOUT 30 +/* which seqno */ +#define XFRM_REPLAY_SEQ 1 +#define XFRM_REPLAY_OSEQ 2 +#define XFRM_REPLAY_SEQ_MASK 3 +/* what happened */ +#define XFRM_REPLAY_UPDATE XFRM_AE_CR +#define XFRM_REPLAY_TIMEOUT XFRM_AE_CE + +/* default aevent timeout in units of 100ms */ +#define XFRM_AE_ETIME 10 +/* Async Event timer multiplier */ +#define XFRM_AE_ETH_M 10 +/* default seq threshold size */ +#define XFRM_AE_SEQT_SIZE 2 + +struct xfrm_mgr { + struct list_head list; + char *id; + int (*notify)(struct xfrm_state *x, struct km_event *c); + int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); + struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir); + int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); + int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); + int (*report)(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); + int (*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles, struct xfrm_kmaddress *k); +}; + +extern int xfrm_register_km(struct xfrm_mgr *km); +extern int xfrm_unregister_km(struct xfrm_mgr *km); + +/* + * This structure is used for the duration where packets are being + * transformed by IPsec. As soon as the packet leaves IPsec the + * area beyond the generic IP part may be overwritten. + */ +struct xfrm_skb_cb { + union { + struct inet_skb_parm h4; + struct inet6_skb_parm h6; + } header; + + /* Sequence number for replay protection. */ + union { + u64 output; + __be32 input; + } seq; +}; + +#define XFRM_SKB_CB(__skb) ((struct xfrm_skb_cb *)&((__skb)->cb[0])) + +/* + * This structure is used by the afinfo prepare_input/prepare_output functions + * to transmit header information to the mode input/output functions. + */ +struct xfrm_mode_skb_cb { + union { + struct inet_skb_parm h4; + struct inet6_skb_parm h6; + } header; + + /* Copied from header for IPv4, always set to zero and DF for IPv6. */ + __be16 id; + __be16 frag_off; + + /* IP header length (excluding options or extension headers). */ + u8 ihl; + + /* TOS for IPv4, class for IPv6. */ + u8 tos; + + /* TTL for IPv4, hop limitfor IPv6. */ + u8 ttl; + + /* Protocol for IPv4, NH for IPv6. */ + u8 protocol; + + /* Option length for IPv4, zero for IPv6. */ + u8 optlen; + + /* Used by IPv6 only, zero for IPv4. */ + u8 flow_lbl[3]; +}; + +#define XFRM_MODE_SKB_CB(__skb) ((struct xfrm_mode_skb_cb *)&((__skb)->cb[0])) + +/* + * This structure is used by the input processing to locate the SPI and + * related information. + */ +struct xfrm_spi_skb_cb { + union { + struct inet_skb_parm h4; + struct inet6_skb_parm h6; + } header; + + unsigned int daddroff; + unsigned int family; +}; + +#define XFRM_SPI_SKB_CB(__skb) ((struct xfrm_spi_skb_cb *)&((__skb)->cb[0])) + +/* Audit Information */ +struct xfrm_audit { + u32 secid; + uid_t loginuid; + u32 sessionid; +}; + +#ifdef CONFIG_AUDITSYSCALL +static inline struct audit_buffer *xfrm_audit_start(const char *op) +{ + struct audit_buffer *audit_buf = NULL; + + if (audit_enabled == 0) + return NULL; + audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, + AUDIT_MAC_IPSEC_EVENT); + if (audit_buf == NULL) + return NULL; + audit_log_format(audit_buf, "op=%s", op); + return audit_buf; +} + +static inline void xfrm_audit_helper_usrinfo(uid_t auid, u32 ses, u32 secid, + struct audit_buffer *audit_buf) +{ + char *secctx; + u32 secctx_len; + + audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses); + if (secid != 0 && + security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) { + audit_log_format(audit_buf, " subj=%s", secctx); + security_release_secctx(secctx, secctx_len); + } else + audit_log_task_context(audit_buf); +} + +extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, + u32 auid, u32 ses, u32 secid); +extern void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, + u32 auid, u32 ses, u32 secid); +extern void xfrm_audit_state_add(struct xfrm_state *x, int result, + u32 auid, u32 ses, u32 secid); +extern void xfrm_audit_state_delete(struct xfrm_state *x, int result, + u32 auid, u32 ses, u32 secid); +extern void xfrm_audit_state_replay_overflow(struct xfrm_state *x, + struct sk_buff *skb); +extern void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family); +extern void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, + __be32 net_spi, __be32 net_seq); +extern void xfrm_audit_state_icvfail(struct xfrm_state *x, + struct sk_buff *skb, u8 proto); +#else + +static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, + u32 auid, u32 ses, u32 secid) +{ +} + +static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, + u32 auid, u32 ses, u32 secid) +{ +} + +static inline void xfrm_audit_state_add(struct xfrm_state *x, int result, + u32 auid, u32 ses, u32 secid) +{ +} + +static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result, + u32 auid, u32 ses, u32 secid) +{ +} + +static inline void xfrm_audit_state_replay_overflow(struct xfrm_state *x, + struct sk_buff *skb) +{ +} + +static inline void xfrm_audit_state_notfound_simple(struct sk_buff *skb, + u16 family) +{ +} + +static inline void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, + __be32 net_spi, __be32 net_seq) +{ +} + +static inline void xfrm_audit_state_icvfail(struct xfrm_state *x, + struct sk_buff *skb, u8 proto) +{ +} +#endif /* CONFIG_AUDITSYSCALL */ + +static inline void xfrm_pol_hold(struct xfrm_policy *policy) +{ + if (likely(policy != NULL)) + atomic_inc(&policy->refcnt); +} + +extern void xfrm_policy_destroy(struct xfrm_policy *policy); + +static inline void xfrm_pol_put(struct xfrm_policy *policy) +{ + if (atomic_dec_and_test(&policy->refcnt)) + xfrm_policy_destroy(policy); +} + +static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) +{ + int i; + for (i = npols - 1; i >= 0; --i) + xfrm_pol_put(pols[i]); +} + +extern void __xfrm_state_destroy(struct xfrm_state *); + +static inline void __xfrm_state_put(struct xfrm_state *x) +{ + atomic_dec(&x->refcnt); +} + +static inline void xfrm_state_put(struct xfrm_state *x) +{ + if (atomic_dec_and_test(&x->refcnt)) + __xfrm_state_destroy(x); +} + +static inline void xfrm_state_hold(struct xfrm_state *x) +{ + atomic_inc(&x->refcnt); +} + +static __inline__ int addr_match(void *token1, void *token2, int prefixlen) +{ + __be32 *a1 = token1; + __be32 *a2 = token2; + int pdw; + int pbi; + + pdw = prefixlen >> 5; /* num of whole u32 in prefix */ + pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ + + if (pdw) + if (memcmp(a1, a2, pdw << 2)) + return 0; + + if (pbi) { + __be32 mask; + + mask = htonl((0xffffffff) << (32 - pbi)); + + if ((a1[pdw] ^ a2[pdw]) & mask) + return 0; + } + + return 1; +} + +static __inline__ +__be16 xfrm_flowi_sport(struct flowi *fl) +{ + __be16 port; + switch(fl->proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + case IPPROTO_SCTP: + port = fl->fl_ip_sport; + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + port = htons(fl->fl_icmp_type); + break; + case IPPROTO_MH: + port = htons(fl->fl_mh_type); + break; + default: + port = 0; /*XXX*/ + } + return port; +} + +static __inline__ +__be16 xfrm_flowi_dport(struct flowi *fl) +{ + __be16 port; + switch(fl->proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + case IPPROTO_SCTP: + port = fl->fl_ip_dport; + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + port = htons(fl->fl_icmp_code); + break; + default: + port = 0; /*XXX*/ + } + return port; +} + +extern int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, + unsigned short family); + +#ifdef CONFIG_SECURITY_NETWORK_XFRM +/* If neither has a context --> match + * Otherwise, both must have a context and the sids, doi, alg must match + */ +static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) +{ + return ((!s1 && !s2) || + (s1 && s2 && + (s1->ctx_sid == s2->ctx_sid) && + (s1->ctx_doi == s2->ctx_doi) && + (s1->ctx_alg == s2->ctx_alg))); +} +#else +static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) +{ + return 1; +} +#endif + +/* A struct encoding bundle of transformations to apply to some set of flow. + * + * dst->child points to the next element of bundle. + * dst->xfrm points to an instanse of transformer. + * + * Due to unfortunate limitations of current routing cache, which we + * have no time to fix, it mirrors struct rtable and bound to the same + * routing key, including saddr,daddr. However, we can have many of + * bundles differing by session id. All the bundles grow from a parent + * policy rule. + */ +struct xfrm_dst { + union { + struct dst_entry dst; + struct rtable rt; + struct rt6_info rt6; + } u; + struct dst_entry *route; + struct flow_cache_object flo; + struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; + int num_pols, num_xfrms; +#ifdef CONFIG_XFRM_SUB_POLICY + struct flowi *origin; + struct xfrm_selector *partner; +#endif + u32 xfrm_genid; + u32 policy_genid; + u32 route_mtu_cached; + u32 child_mtu_cached; + u32 route_cookie; + u32 path_cookie; +}; + +#ifdef CONFIG_XFRM +static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) +{ + xfrm_pols_put(xdst->pols, xdst->num_pols); + dst_release(xdst->route); + if (likely(xdst->u.dst.xfrm)) + xfrm_state_put(xdst->u.dst.xfrm); +#ifdef CONFIG_XFRM_SUB_POLICY + kfree(xdst->origin); + xdst->origin = NULL; + kfree(xdst->partner); + xdst->partner = NULL; +#endif +} +#endif + +extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); + +struct sec_path { + atomic_t refcnt; + int len; + struct xfrm_state *xvec[XFRM_MAX_DEPTH]; +}; + +static inline struct sec_path * +secpath_get(struct sec_path *sp) +{ + if (sp) + atomic_inc(&sp->refcnt); + return sp; +} + +extern void __secpath_destroy(struct sec_path *sp); + +static inline void +secpath_put(struct sec_path *sp) +{ + if (sp && atomic_dec_and_test(&sp->refcnt)) + __secpath_destroy(sp); +} + +extern struct sec_path *secpath_dup(struct sec_path *src); + +static inline void +secpath_reset(struct sk_buff *skb) +{ +#ifdef CONFIG_XFRM + secpath_put(skb->sp); + skb->sp = NULL; +#endif +} + +static inline int +xfrm_addr_any(xfrm_address_t *addr, unsigned short family) +{ + switch (family) { + case AF_INET: + return addr->a4 == 0; + case AF_INET6: + return ipv6_addr_any((struct in6_addr *)&addr->a6); + } + return 0; +} + +static inline int +__xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x) +{ + return (tmpl->saddr.a4 && + tmpl->saddr.a4 != x->props.saddr.a4); +} + +static inline int +__xfrm6_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x) +{ + return (!ipv6_addr_any((struct in6_addr*)&tmpl->saddr) && + ipv6_addr_cmp((struct in6_addr *)&tmpl->saddr, (struct in6_addr*)&x->props.saddr)); +} + +static inline int +xfrm_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short family) +{ + switch (family) { + case AF_INET: + return __xfrm4_state_addr_cmp(tmpl, x); + case AF_INET6: + return __xfrm6_state_addr_cmp(tmpl, x); + } + return !0; +} + +#ifdef CONFIG_XFRM +extern int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb, unsigned short family); + +static inline int __xfrm_policy_check2(struct sock *sk, int dir, + struct sk_buff *skb, + unsigned int family, int reverse) +{ + struct net *net = dev_net(skb->dev); + int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0); + + if (sk && sk->sk_policy[XFRM_POLICY_IN]) + return __xfrm_policy_check(sk, ndir, skb, family); + + return (!net->xfrm.policy_count[dir] && !skb->sp) || + (skb_dst(skb)->flags & DST_NOPOLICY) || + __xfrm_policy_check(sk, ndir, skb, family); +} + +static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) +{ + return __xfrm_policy_check2(sk, dir, skb, family, 0); +} + +static inline int xfrm4_policy_check(struct sock *sk, int dir, struct sk_buff *skb) +{ + return xfrm_policy_check(sk, dir, skb, AF_INET); +} + +static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *skb) +{ + return xfrm_policy_check(sk, dir, skb, AF_INET6); +} + +static inline int xfrm4_policy_check_reverse(struct sock *sk, int dir, + struct sk_buff *skb) +{ + return __xfrm_policy_check2(sk, dir, skb, AF_INET, 1); +} + +static inline int xfrm6_policy_check_reverse(struct sock *sk, int dir, + struct sk_buff *skb) +{ + return __xfrm_policy_check2(sk, dir, skb, AF_INET6, 1); +} + +extern int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, + unsigned int family, int reverse); + +static inline int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, + unsigned int family) +{ + return __xfrm_decode_session(skb, fl, family, 0); +} + +static inline int xfrm_decode_session_reverse(struct sk_buff *skb, + struct flowi *fl, + unsigned int family) +{ + return __xfrm_decode_session(skb, fl, family, 1); +} + +extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family); + +static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) +{ + struct net *net = dev_net(skb->dev); + + return !net->xfrm.policy_count[XFRM_POLICY_OUT] || + (skb_dst(skb)->flags & DST_NOXFRM) || + __xfrm_route_forward(skb, family); +} + +static inline int xfrm4_route_forward(struct sk_buff *skb) +{ + return xfrm_route_forward(skb, AF_INET); +} + +static inline int xfrm6_route_forward(struct sk_buff *skb) +{ + return xfrm_route_forward(skb, AF_INET6); +} + +extern int __xfrm_sk_clone_policy(struct sock *sk); + +static inline int xfrm_sk_clone_policy(struct sock *sk) +{ + if (unlikely(sk->sk_policy[0] || sk->sk_policy[1])) + return __xfrm_sk_clone_policy(sk); + return 0; +} + +extern int xfrm_policy_delete(struct xfrm_policy *pol, int dir); + +static inline void xfrm_sk_free_policy(struct sock *sk) +{ + if (unlikely(sk->sk_policy[0] != NULL)) { + xfrm_policy_delete(sk->sk_policy[0], XFRM_POLICY_MAX); + sk->sk_policy[0] = NULL; + } + if (unlikely(sk->sk_policy[1] != NULL)) { + xfrm_policy_delete(sk->sk_policy[1], XFRM_POLICY_MAX+1); + sk->sk_policy[1] = NULL; + } +} + +#else + +static inline void xfrm_sk_free_policy(struct sock *sk) {} +static inline int xfrm_sk_clone_policy(struct sock *sk) { return 0; } +static inline int xfrm6_route_forward(struct sk_buff *skb) { return 1; } +static inline int xfrm4_route_forward(struct sk_buff *skb) { return 1; } +static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *skb) +{ + return 1; +} +static inline int xfrm4_policy_check(struct sock *sk, int dir, struct sk_buff *skb) +{ + return 1; +} +static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) +{ + return 1; +} +static inline int xfrm_decode_session_reverse(struct sk_buff *skb, + struct flowi *fl, + unsigned int family) +{ + return -ENOSYS; +} +static inline int xfrm4_policy_check_reverse(struct sock *sk, int dir, + struct sk_buff *skb) +{ + return 1; +} +static inline int xfrm6_policy_check_reverse(struct sock *sk, int dir, + struct sk_buff *skb) +{ + return 1; +} +#endif + +static __inline__ +xfrm_address_t *xfrm_flowi_daddr(struct flowi *fl, unsigned short family) +{ + switch (family){ + case AF_INET: + return (xfrm_address_t *)&fl->fl4_dst; + case AF_INET6: + return (xfrm_address_t *)&fl->fl6_dst; + } + return NULL; +} + +static __inline__ +xfrm_address_t *xfrm_flowi_saddr(struct flowi *fl, unsigned short family) +{ + switch (family){ + case AF_INET: + return (xfrm_address_t *)&fl->fl4_src; + case AF_INET6: + return (xfrm_address_t *)&fl->fl6_src; + } + return NULL; +} + +static __inline__ +void xfrm_flowi_addr_get(struct flowi *fl, + xfrm_address_t *saddr, xfrm_address_t *daddr, + unsigned short family) +{ + switch(family) { + case AF_INET: + memcpy(&saddr->a4, &fl->fl4_src, sizeof(saddr->a4)); + memcpy(&daddr->a4, &fl->fl4_dst, sizeof(daddr->a4)); + break; + case AF_INET6: + ipv6_addr_copy((struct in6_addr *)&saddr->a6, &fl->fl6_src); + ipv6_addr_copy((struct in6_addr *)&daddr->a6, &fl->fl6_dst); + break; + } +} + +static __inline__ int +__xfrm4_state_addr_check(struct xfrm_state *x, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + if (daddr->a4 == x->id.daddr.a4 && + (saddr->a4 == x->props.saddr.a4 || !saddr->a4 || !x->props.saddr.a4)) + return 1; + return 0; +} + +static __inline__ int +__xfrm6_state_addr_check(struct xfrm_state *x, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + if (!ipv6_addr_cmp((struct in6_addr *)daddr, (struct in6_addr *)&x->id.daddr) && + (!ipv6_addr_cmp((struct in6_addr *)saddr, (struct in6_addr *)&x->props.saddr)|| + ipv6_addr_any((struct in6_addr *)saddr) || + ipv6_addr_any((struct in6_addr *)&x->props.saddr))) + return 1; + return 0; +} + +static __inline__ int +xfrm_state_addr_check(struct xfrm_state *x, + xfrm_address_t *daddr, xfrm_address_t *saddr, + unsigned short family) +{ + switch (family) { + case AF_INET: + return __xfrm4_state_addr_check(x, daddr, saddr); + case AF_INET6: + return __xfrm6_state_addr_check(x, daddr, saddr); + } + return 0; +} + +static __inline__ int +xfrm_state_addr_flow_check(struct xfrm_state *x, struct flowi *fl, + unsigned short family) +{ + switch (family) { + case AF_INET: + return __xfrm4_state_addr_check(x, + (xfrm_address_t *)&fl->fl4_dst, + (xfrm_address_t *)&fl->fl4_src); + case AF_INET6: + return __xfrm6_state_addr_check(x, + (xfrm_address_t *)&fl->fl6_dst, + (xfrm_address_t *)&fl->fl6_src); + } + return 0; +} + +static inline int xfrm_state_kern(struct xfrm_state *x) +{ + return atomic_read(&x->tunnel_users); +} + +static inline int xfrm_id_proto_match(u8 proto, u8 userproto) +{ + return (!userproto || proto == userproto || + (userproto == IPSEC_PROTO_ANY && (proto == IPPROTO_AH || + proto == IPPROTO_ESP || + proto == IPPROTO_COMP))); +} + +/* + * xfrm algorithm information + */ +struct xfrm_algo_aead_info { + u16 icv_truncbits; +}; + +struct xfrm_algo_auth_info { + u16 icv_truncbits; + u16 icv_fullbits; +}; + +struct xfrm_algo_encr_info { + u16 blockbits; + u16 defkeybits; +}; + +struct xfrm_algo_comp_info { + u16 threshold; +}; + +struct xfrm_algo_desc { + char *name; + char *compat; + u8 available:1; + union { + struct xfrm_algo_aead_info aead; + struct xfrm_algo_auth_info auth; + struct xfrm_algo_encr_info encr; + struct xfrm_algo_comp_info comp; + } uinfo; + struct sadb_alg desc; +}; + +/* XFRM tunnel handlers. */ +struct xfrm_tunnel { + int (*handler)(struct sk_buff *skb); + int (*err_handler)(struct sk_buff *skb, u32 info); + + struct xfrm_tunnel *next; + int priority; +}; + +struct xfrm6_tunnel { + int (*handler)(struct sk_buff *skb); + int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info); + struct xfrm6_tunnel *next; + int priority; +}; + +extern void xfrm_init(void); +extern void xfrm4_init(int rt_hash_size); +extern int xfrm_state_init(struct net *net); +extern void xfrm_state_fini(struct net *net); +extern void xfrm4_state_init(void); +#ifdef CONFIG_XFRM +extern int xfrm6_init(void); +extern void xfrm6_fini(void); +extern int xfrm6_state_init(void); +extern void xfrm6_state_fini(void); +#else +static inline int xfrm6_init(void) +{ + return 0; +} +static inline void xfrm6_fini(void) +{ + ; +} +#endif + +#ifdef CONFIG_XFRM_STATISTICS +extern int xfrm_proc_init(struct net *net); +extern void xfrm_proc_fini(struct net *net); +#endif + +extern int xfrm_sysctl_init(struct net *net); +#ifdef CONFIG_SYSCTL +extern void xfrm_sysctl_fini(struct net *net); +#else +static inline void xfrm_sysctl_fini(struct net *net) +{ +} +#endif + +extern void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto); +extern int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, + int (*func)(struct xfrm_state *, int, void*), void *); +extern void xfrm_state_walk_done(struct xfrm_state_walk *walk); +extern struct xfrm_state *xfrm_state_alloc(struct net *net); +extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, + struct flowi *fl, struct xfrm_tmpl *tmpl, + struct xfrm_policy *pol, int *err, + unsigned short family); +extern struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, + xfrm_address_t *daddr, + xfrm_address_t *saddr, + unsigned short family, + u8 mode, u8 proto, u32 reqid); +extern int xfrm_state_check_expire(struct xfrm_state *x); +extern void xfrm_state_insert(struct xfrm_state *x); +extern int xfrm_state_add(struct xfrm_state *x); +extern int xfrm_state_update(struct xfrm_state *x); +extern struct xfrm_state *xfrm_state_lookup(struct net *net, u32 mark, + xfrm_address_t *daddr, __be32 spi, + u8 proto, unsigned short family); +extern struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark, + xfrm_address_t *daddr, + xfrm_address_t *saddr, + u8 proto, + unsigned short family); +#ifdef CONFIG_XFRM_SUB_POLICY +extern int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, + int n, unsigned short family); +extern int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, + int n, unsigned short family); +#else +static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, + int n, unsigned short family) +{ + return -ENOSYS; +} + +static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, + int n, unsigned short family) +{ + return -ENOSYS; +} +#endif + +struct xfrmk_sadinfo { + u32 sadhcnt; /* current hash bkts */ + u32 sadhmcnt; /* max allowed hash bkts */ + u32 sadcnt; /* current running count */ +}; + +struct xfrmk_spdinfo { + u32 incnt; + u32 outcnt; + u32 fwdcnt; + u32 inscnt; + u32 outscnt; + u32 fwdscnt; + u32 spdhcnt; + u32 spdhmcnt; +}; + +extern struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, + u32 seq); +extern int xfrm_state_delete(struct xfrm_state *x); +extern int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info); +extern void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si); +extern void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si); +extern int xfrm_replay_check(struct xfrm_state *x, + struct sk_buff *skb, __be32 seq); +extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq); +extern void xfrm_replay_notify(struct xfrm_state *x, int event); +extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); +extern int xfrm_init_state(struct xfrm_state *x); +extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, + int encap_type); +extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr); +extern int xfrm_output_resume(struct sk_buff *skb, int err); +extern int xfrm_output(struct sk_buff *skb); +extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm4_extract_header(struct sk_buff *skb); +extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, + int encap_type); +extern int xfrm4_transport_finish(struct sk_buff *skb, int async); +extern int xfrm4_rcv(struct sk_buff *skb); + +static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) +{ + return xfrm4_rcv_encap(skb, nexthdr, spi, 0); +} + +extern int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm4_output(struct sk_buff *skb); +extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); +extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); +extern int xfrm6_extract_header(struct sk_buff *skb); +extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); +extern int xfrm6_transport_finish(struct sk_buff *skb, int async); +extern int xfrm6_rcv(struct sk_buff *skb); +extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, + xfrm_address_t *saddr, u8 proto); +extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); +extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); +extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); +extern void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr); +extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr); +extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm6_output(struct sk_buff *skb); +extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, + u8 **prevhdr); + +#ifdef CONFIG_XFRM +extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); +extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen); +#else +static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) +{ + return -ENOPROTOOPT; +} + +static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) +{ + /* should not happen */ + kfree_skb(skb); + return 0; +} +#endif + +struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); + +extern void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type); +extern int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, + int (*func)(struct xfrm_policy *, int, int, void*), void *); +extern void xfrm_policy_walk_done(struct xfrm_policy_walk *walk); +int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); +struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, + u8 type, int dir, + struct xfrm_selector *sel, + struct xfrm_sec_ctx *ctx, int delete, + int *err); +struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, u32 id, int delete, int *err); +int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info); +u32 xfrm_get_acqseq(void); +extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); +struct xfrm_state *xfrm_find_acq(struct net *net, struct xfrm_mark *mark, + u8 mode, u32 reqid, u8 proto, + xfrm_address_t *daddr, + xfrm_address_t *saddr, int create, + unsigned short family); +extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); +extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, + struct flowi *fl, int family, int strict); + +#ifdef CONFIG_XFRM_MIGRATE +extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_bundles, + struct xfrm_kmaddress *k); +extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m); +extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, + struct xfrm_migrate *m); +extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_bundles, + struct xfrm_kmaddress *k); +#endif + +extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); +extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid); +extern int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); + +extern void xfrm_input_init(void); +extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq); + +extern void xfrm_probe_algs(void); +extern int xfrm_count_auth_supported(void); +extern int xfrm_count_enc_supported(void); +extern struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx); +extern struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx); +extern struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id); +extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe); +extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe); +extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe); +extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len, + int probe); + +struct hash_desc; +struct scatterlist; +typedef int (icv_update_fn_t)(struct hash_desc *, struct scatterlist *, + unsigned int); + +static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b, + int family) +{ + switch (family) { + default: + case AF_INET: + return (__force u32)a->a4 - (__force u32)b->a4; + case AF_INET6: + return ipv6_addr_cmp((struct in6_addr *)a, + (struct in6_addr *)b); + } +} + +static inline int xfrm_policy_id2dir(u32 index) +{ + return index & 7; +} + +#ifdef CONFIG_XFRM +static inline int xfrm_aevent_is_on(struct net *net) +{ + struct sock *nlsk; + int ret = 0; + + rcu_read_lock(); + nlsk = rcu_dereference(net->xfrm.nlsk); + if (nlsk) + ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS); + rcu_read_unlock(); + return ret; +} +#endif + +static inline int xfrm_alg_len(struct xfrm_algo *alg) +{ + return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); +} + +static inline int xfrm_alg_auth_len(struct xfrm_algo_auth *alg) +{ + return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); +} + +#ifdef CONFIG_XFRM_MIGRATE +static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig) +{ + return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL); +} + +static inline struct xfrm_algo_auth *xfrm_algo_auth_clone(struct xfrm_algo_auth *orig) +{ + return kmemdup(orig, xfrm_alg_auth_len(orig), GFP_KERNEL); +} + +static inline void xfrm_states_put(struct xfrm_state **states, int n) +{ + int i; + for (i = 0; i < n; i++) + xfrm_state_put(*(states + i)); +} + +static inline void xfrm_states_delete(struct xfrm_state **states, int n) +{ + int i; + for (i = 0; i < n; i++) + xfrm_state_delete(*(states + i)); +} +#endif + +#ifdef CONFIG_XFRM +static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb) +{ + return skb->sp->xvec[skb->sp->len - 1]; +} +#endif + +static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m) +{ + if (attrs[XFRMA_MARK]) + memcpy(m, nla_data(attrs[XFRMA_MARK]), sizeof(struct xfrm_mark)); + else + m->v = m->m = 0; + + return m->v & m->m; +} + +static inline int xfrm_mark_put(struct sk_buff *skb, struct xfrm_mark *m) +{ + if (m->m | m->v) + NLA_PUT(skb, XFRMA_MARK, sizeof(struct xfrm_mark), m); + return 0; + +nla_put_failure: + return -1; +} + +#endif /* _NET_XFRM_H */ |