N: Tim Waugh
E: tim@cyberelk.demon.co.uk
D: Co-architect of the parallel-port sharing system
-S: 12 Station Road
-S: Park Gate
-S: Southampton SO31 7GJ
+S: 110 Twyford Road
+S: EASTLEIGH
+S: SO50 4HN
S: United Kingdom
N: Juergen Weigert
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
-Last updated: May 9, 1998
+Last updated: May 12, 1998
Current Author: Chris Ricker (kaboom@gatech.edu).
Current Minimal Requirements
- Linux C Library 5.4.44 ; ls -l /lib/libc.so.*
- Dynamic Linker (ld.so) 1.9.5 ; ldd --version
- Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.*
-- Procps 1.2.5 ; ps --version
+- Procps 1.2.7 ; ps --version
- Procinfo 13 ; procinfo -v
- Mount 2.7l ; mount --version
-- Net-tools 1.41 ; hostname -V
+- Net-tools 1.45 ; hostname -V
- Loadlin 1.6a
- Sh-utils 1.16 ; basename --v
- Autofs 0.3.11 ; automount --version
- NFS 0.4.21 ; showmount --version
- Bash 1.14.7 ; bash -version
-- Ncpfs 2.1.1 ; ncpmount -v
-- Pcmcia-cs May 4, 1998
+- Ncpfs 2.2.0 ; ncpmount -v
+- Pcmcia-cs 3.0.1
- PPP 2.3.5 ; pppd -v
Upgrade notes
the corresponding ttyS* device instead (e.g., cua0 -> ttyS0, cua1 ->
ttyS1, etc.).
+ In addition, some software still works, but needs to be compiled
+against 2.1 headers for complete functionality. Fdutils binaries
+compiled under 2.0 or earlier kernels should be replaced with ones
+compiled under 2.1, for example.
+
Libc
====
The 0.4.21 release:
ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
-ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz
+ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
Net-tools
=========
Ncpfs
=====
-The 2.1.1 release:
-ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.1.1.tgz
+The 2.2.0 release:
+ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.2.0.tgz
Pcmcia-cs
=========
-The May 4, 1998 release:
-ftp://hyper.stanford.edu/pub/pcmcia/NEW/pcmcia-cs.04-May-98.tar.gz
+The 3.0.1 release:
+ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.1.tar.gz
PPP
===
IP: firewalling
CONFIG_IP_FIREWALL
- If you want to configure your Linux box as a packet filter firewall
- for a local TCP/IP based network, say Y here. This will enlarge your
- kernel by about 2kB. You may need to read the FIREWALL-HOWTO,
- available via ftp (user: anonymous) in
- ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
-
- Also, you will need the ipfwadm tool (available via ftp (user:
- anonymous) from ftp://ftp.xos.nl/pub/linux/ipfwadm/) to allow selective
- blocking of Internet traffic based on type, origin and destination;
- this type of firewall is called a "packet filter". The other type of
- firewall, "proxy-based" ones, is more secure but more intrusive and
- more bothersome to set up; it inspects the network traffic much more
- closely, modifies it and has knowledge about the higher level
- protocols, which a packet filter lacks. Moreover, proxy-based
- firewalls often require changes to the programs running on the local
- clients. Proxy-based firewalls don't need support by the kernel, but
- they are often combined with a packet filter, which only works if
- you say Y here.
-
- The firewalling code will only work if IP forwarding is enabled in
- your kernel. You can do that by saying Y to "/proc filesystem
- support" and "Sysctl support" below and executing the line
-
- echo "1" > /proc/sys/net/ipv4/ip_forward
-
- at boot time after the /proc filesystem has been mounted.
-
- You need to say Y to "IP firewalling" in order to be able to use IP
- masquerading (masquerading means that local computers can chat with
- an outside host, but that outside host is made to think that it is
- talking to the firewall box -- makes the local network completely
- invisible to the outside world and avoids the need to allocate
- globally valid IP host addresses for the machines on the local net)
- and IP packet accounting (keeping track of what is using all your
- network bandwidth) and IP transparent proxying (makes the computers
- on the local network think they're talking to a remote computer,
- while in reality the traffic is redirected by your Linux firewall to
- a local proxy server).
+ Complete rewrite of IP firewalling support. Requires new ipfwadm.
+ This was previously called CONFIG_IP_FIREWALL_CHAINS in patch sets
+ released by the author, but now it is and will be the standard
+ firewalling implementation for 2.1.x and onward.
+
+ More powerful than the old IP firewalling but also provides similar
+ structure to original firewalling for experienced users. IP
+ accounting and packet logging are automatically included with firewall
+ chains, so you don't need them them if you say Y here. See
+ http://www.adelaide.net.au/~rustcorp for new ipfwadm (called ipchains).
+ If in doubt, say N here.
IP: firewall packet netlink device
CONFIG_IP_FIREWALL_NETLINK
/dev with major number 36 and minor number 3 using mknod ("man
mknod"), and you need (to write) a program that reads from that
device and takes appropriate action.
-
-IP: accounting
-CONFIG_IP_ACCT
- This keeps track of your IP network traffic and produces some
- statistics. Usually, you only want to say Y here if your box will be
- a router or a firewall for some local network. For the latter, you
- need to say Y to "IP firewalling". The data is accessible with "cat
- /proc/net/ip_acct", so you want to say Y to the /proc filesystem
- below, if you say Y here. To specify what exactly should be
- recorded, you need the tool ipfwadm (available via ftp (user:
- anonymous) from ftp://ftp.xos.nl/pub/linux/ipfwadm/).
+ With the current generic firewalling chains you can specify which
+ packets go to this device, as well as how many bytes.
IP: kernel level autoconfiguration
CONFIG_IP_PNP
The module will be called ip_masq_autofw.o. If you want to compile
it as a module, say M here and read Documentation/modules.txt.
+IP: ipportfw masquerade support
+CONFIG_IP_MASQUERADE_IPPORTFW
+ ipportfw is an addition to IP Masquerading written by Steven Clarke
+ to allow some forwarding of packets from outside to inside a
+ firewall on given ports. Information and source for ipportfw is
+ available from
+ http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html
+ The portfw code is still under development and so is currently
+ marked EXPERIMENTAL.
+ If you want this, say Y.
+
+IP: ICMP masquerading
+CONFIG_IP_MASQUERADE_ICMP
+ The basic masquerade code described for CONFIG_IP_MASQUERADE only
+ handles TCP or UDP packets (and ICMP errors for existing
+ connections). This option adds additional support for masquerading
+ ICMP packets, such as ping or the probes used by the Windows 95
+ tracert program.
+ If you want this, say Y.
+
+IP: ipautofw masquerade support
+CONFIG_IP_MASQUERADE_IPAUTOFW (Experimental)
+ ipautofw is a program by Richard Lynch allowing additional
+ support for masquerading protocols which do not (as yet)
+ have additional protocol helpers.
+ Information and source for ipautofw is available from
+ ftp://ftp.netis.com/pub/members/rlynch/
+ The ipautofw code is still under development and so is currently
+ marked EXPERIMENTAL.
+ If you want this, say Y.
+
IP: ipportfw masquerade support
CONFIG_IP_MASQUERADE_IPPORTFW
ipportfw is an addition to IP Masquerading written by Steven Clarke
as a module, say M here and read Documentation/modules.txt. If you
try building this as a module and you are running kerneld, be sure
to add 'alias net-pf-1 unix' to your /etc/conf.module file. If
- unsure, say Y.
+ unsure, say Y. (NOTE: X Windows and syslog probably won't work
+ if you say N to this or fail to configure it correctly)
The IPv6 protocol
CONFIG_IPV6
some problems caused by the presence of two link-local addresses on
an interface.
-IPv6: routing messages via old netlink
-CONFIG_IPV6_NETLINK
- You can say Y here to receive routing messages from the IPv6 code
- through the old netlink interface. However, a better option is to
- say Y to "Kernel/User network link driver" and to "Routing
- messages" instead.
-
-The IPX protocol
+IPX networking
CONFIG_IPX
This is support for the Novell networking protocol, IPX, commonly
used for local networks of Windows machines. You need it if you want
to access Novell NetWare file or print servers using the Linux
Novell client ncpfs (available via ftp (user: anonymous) from
- ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within
- the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
- ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the
- former, you'll also have to say Y to "NCP filesystem support",
- below.
-
- IPX is similar in scope to IP, while SPX, which runs on top of IPX,
- is similar to TCP. There is also experimental support for SPX in
- Linux (see "SPX networking", below).
-
- To turn your Linux box into a fully featured NetWare file server and
+ sunsite.unc.edu:/pub/Linux/system/filesystems/) or from within the
+ Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
+ sunsite.unc.edu:/pub/Linux/docs/HOWTO). In order to do the former,
+ you'll also have to say Y to "NCP filesystem support", below. To
+ turn your Linux box into a fully featured NetWare file server and
IPX router, say Y here and fetch either lwared from
- ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from
- ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, read the
- IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
- General information about how to connect Linux, Windows machines and
- Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
- browse the WWW, you need to have access to a machine on the Internet
- that has a program like lynx or netscape).
-
- The IPX driver would enlarge your kernel by about 5 kB. This driver
- is also available as a module ( = code which can be inserted in and
- removed from the running kernel whenever you want). The module will
- be called ipx.o. If you want to compile it as a module, say M here
- and read Documentation/modules.txt. Unless you want to integrate
+ sunsite.unc.edu:/pub/Linux/system/network/daemons/ or mars_nwe from
+ ftp.gwdg.de:/pub/linux/misc/ncpfs. For more information, read the
+ IPX-HOWTO in sunsite.unc.edu:/pub/Linux/docs/howto. The IPX driver
+ would enlarge your kernel by about 5 kB. This driver is also
+ available as a module ( = code which can be inserted in and removed
+ from the running kernel whenever you want). The module will be
+ called ipx.o. If you want to compile it as a module, say M here
+ and read Documentation/modules.txt. Unless you want to integrate
your Linux box with a local Novell network, say N.
IPX: Full internal IPX network
Every IPX network has an address that identifies it. Sometimes it is
useful to give an IPX "network" address to your Linux box as well
(for example if your box is acting as a fileserver for different IPX
- networks: it will then be accessible from everywhere using the same
+ networks: it will then be accessible form everywhere using the same
address). The way this is done is to create a virtual internal
"network" inside your box and to assign an IPX address to this
network. Say Y here if you want to do this; read the IPX-HOWTO at
sunsite.unc.edu:/pub/Linux/docs/howto for details.
-
The full internal IPX network enables you to allocate sockets on
different virtual nodes of the internal network. This is done by
evaluating the field sipx_node of the socket address given to the
'special' sockets to sockets listening on the primary network is
disabled. This might break existing applications, especially RIP/SAP
daemons. A RIP/SAP daemon that works well with the full internal net
- can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. If you don't
+ can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs. If you don't
know what you are doing, say N.
IPX: SPX networking (EXPERIMENTAL)
CONFIG_SPX
- The Sequenced Packet eXchange protocol is a transport layer protocol
- built on top of IPX. It is used in Novell NetWare systems for
- client-server applications and is similar to TCP (which runs on top
- of IP).
-
- Note that Novell NetWare file sharing does not use SPX; it uses a
- protocol called NCP, for which separate Linux support is available
- ("NCP filesystem support" below for the client side, and the user
- space programs lwared or mars_nwe for the server side).
-
- Say Y here if you have use for SPX; read the IPX-HOWTO at
- sunsite.unc.edu:/pub/Linux/docs/howto for details.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called af_spx.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt.
+ The (SPP-derived) Sequenced Packet eXchange (SPX) protocol. Novell's
+ networking protocol which monitors transmissions to guarantee
+ successful delivery. An example server/client program (SPX-0.0x.tar.gz)
+ is available at ftp://ftp.spacs.k12.wi.us/users/jschlst/SPX-0.0x.tar.gz.
+ It is safe to say Y/M here.
Appletalk DDP
CONFIG_ATALK
Appletalk is the way Apple computers speak to each other on a
- network. If your Linux box is connected to such a network and you
+ network. If your linux box is connected to such a network and you
want to join the conversation, say Y. You will need to use the
netatalk package so that your Linux box can act as a print and file
server for macs as well as access appletalk printers. Check out
- http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW
- for details (to browse the WWW, you need to have access to a machine
- on the Internet that has a program like lynx or netscape). EtherTalk
- is the name used for appletalk over Ethernet and the cheaper and
- slower LocalTalk is appletalk over a proprietary apple network using
- serial links. Ethertalk and Localtalk are fully supported by Linux.
- The NET-2-HOWTO, available via ftp (user: anonymous) in
- ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO contains valuable
- information as well.
-
- General information about how to connect Linux, Windows machines and
- Macs is on the WWW at http://www.eats.com/linux_mac_win.html
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module is called appletalk.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt. I hear that
- the GNU boycott of Apple is over, so even politically correct people
- are allowed to say Y here.
+ http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
+ WWW for details (to browse the WWW, you need to have access to a
+ machine on the Internet that has a program like lynx or
+ netscape). EtherTalk is the name used for appletalk over Ethernet
+ and the cheaper and slower LocalTalk is appletalk over a proprietary
+ apple network using serial links. Ethertalk and Localtalk are fully
+ supported by Linux. The NET-2-HOWTO, available via ftp (user: anonymous)
+ in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
+ as well. This driver is also available as a module ( = code which
+ can be inserted in and removed from the running kernel whenever you
+ want). The module is called appletalk.o. If you want to compile
+ it as a module, say M here and read Documentation/modules.txt. I
+ hear that the GNU boycott of Apple is over, so even politically
+ correct people are allowed to say Y here.
Appletalk-IP driver support
CONFIG_IPDDP
This allows IP networking for users who only have Appletalk
- networking available. This feature is experimental. With this
+ networking available. This feature is experimental. With this
driver, you can either encapsulate IP inside Appletalk (e.g. if your
- Linux box is stuck on an Appletalk only network) or decapsulate
- (e.g. if you want your Linux box to act as an Internet gateway for a
+ Linux box is stuck on an appletalk only network) or decapsulate
+ (e.g. if you want your Linux box to act as a Internet gateway for a
zoo of appletalk connected Macs). You decide which one of the two
you want in the following two questions; you can say Y to only one
of them. Please see Documentation/networking/ipddp.txt for more
- information.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module is called ipddp.o. If you want to compile it as a module,
- say M here and read Documentation/modules.txt.
+ information. This driver is also available as a module ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). The module is called ipddp.o. If you want to
+ compile it as a module, say M here and read
+ Documentation/modules.txt.
IP to Appletalk-IP Encapsulation support
CONFIG_IPDDP_ENCAP
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
+Mylex EISA LNE390A/LNE390B support
+CONFIG_LNE390
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available via ftp (user: anonymous) in
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called lne390.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt as well as
+ Documentation/networking/net-modules.txt.
+
Apricot Xen-II on board Ethernet
CONFIG_APRICOT
If you have a network (Ethernet) controller of this type, say Y and
-/proc/sys/net/ipv4/* variables:
+/proc/sys/net/ipv4/* Variables:
-ip_forwarding - "SNMP" BOOLEAN
- 2 - disabled (default)
- 1 - enabled
+ip_forward - BOOLEAN
+ 0 - disabled (default)
+ not 0 - enabled
+
+ Forward Packets between interfaces.
This variable is special, its change resets all configuration
parameters to their default state (RFC1122 for hosts, RFC1812
ip_default_ttl - INTEGER
default 64
-ip_log_martians - BOOLEAN
- log packets with strange or impossible addresses.
- default TRUE (router)
- FALSE (host)
-
-ip_accept_redirects - BOOLEAN
- Accept ICMP redirect messages.
- default TRUE (host)
- FALSE (router)
-
-ip_secure_redirects - BOOLEAN
- Accept ICMP redirect messages only for gateways,
- listed in default gateway list.
- default TRUE
-
ip_addrmask_agent - BOOLEAN
Reply to ICMP ADDRESS MASK requests.
default TRUE (router)
FALSE (host)
-ip_rfc1620_redirects - BOOLEAN
- Send(router) or accept(host) RFC1620 shared media redirects.
- Overrides ip_secure_redirects.
- default TRUE (should be FALSE for distributed version,
- but I use it...)
-
ip_bootp_agent - BOOLEAN
Accept packets with source address of sort 0.b.c.d
and destined to this host, broadcast or multicast.
default FALSE
-ip_bootp_relay - BOOLEAN
- Accept packets with source address 0.b.c.d destined
- not to this host as local ones. It is supposed, that
- BOOTP relay deamon will catch and forward such packets.
-
- default FALSE
- Not Implemented Yet.
-
-
-ip_source_route - BOOLEAN
- Accept packets with SRR option.
- default TRUE (router)
- FALSE (host)
-
-
ip_no_pmtu_disc - BOOLEAN
Disable Path MTU Discovery.
default FALSE
-ip_rfc1812_filter - INTEGER
- 2 - do source validation by reversed path, as specified in RFC1812
- Recommended option for single homed hosts and stub network
- routers. Could cause troubles for complicated (not loop free)
- networks running a slow unreliable protocol (sort of RIP),
- or using static routes.
-
- 1 - (DEFAULT) Weaker form of RP filtering: drop all the packets
- that look as sourced at a directly connected interface, but
- were input from another interface.
-
- 0 - No source validation.
-
- NOTE: do not disable this option! All BSD derived routing software
- (sort of gated, routed etc. etc.) is confused by such packets,
- even if they are valid.
-
- NOTE: this option is turned on per default only when ip_forwarding
- is on. For non-forwarding hosts it doesn't make much sense and
- makes some legal multihoming configurations impossible.
-
ip_fib_model - INTEGER
0 - (DEFAULT) Standard model. All routes are in class MAIN.
1 - default routes go to class DEFAULT. This mode should
tcp_max_delay_acks - INTEGER
tcp_fin_timeout - INTEGER
tcp_max_ka_probes - INTEGER
+tcp_hoe_retransmits - INTEGER
Undocumented for now.
tcp_syncookies - BOOLEAN
tcp_max_syn_backlog - INTEGER
Undocumented (work in progress)
+tcp_window_scaling - BOOLEAN
+ Enable window scaling as defined in RFC1323.
+
+tcp_timestamps - BOOLEAN
+ Enable timestamps as defined in RFC1323.
+
+tcp_sack - BOOLEAN
+ Enable select acknowledgements.
+
+tcp_retrans_collapse - BOOLEAN
+ Bug-to-bug compatibility with some broken printers.
+ On retransmit try to send bigger packets to work around bugs in
+ certain TCP stacks.
+
ip_local_port_range - 2 INTEGERS
Defines the local port range that is used by TCP and UDP to
choose the local port. The first number is the first, the
ICMP ECHO requests sent to it or just those to broadcast/multicast
addresses, respectively.
+icmp_destunreach_rate - INTEGER
+icmp_paramprob_rate - INTEGER
+icmp_timeexceed_rate - INTEGER
+icmp_echoreply_rate - INTEGER (not enabled per default)
+ Limit the maximal rates for sending ICMP packets to specifc targets.
+ 0 to disable any limiting, otherwise the maximal rate in jiffies(1)
+ See the source for more information.
+
+
+(1) Jiffie: internal timeunit for the kernel. On the i386 1/100s, on the
+Alpha 1/1024s. See the HZ define in /usr/include/asm/param.h for the exact
+value on your system.
+
+conf/interface/*:
+conf/all/* is special and changes the settings for all interfaces.
+ Change special settings per interface.
+
+log_martians - BOOLEAN
+ Log packets with impossible addresses to kernel log.
+
+accept_redirects - BOOLEAN
+ Accept ICMP redirect messages.
+ default TRUE (host)
+ FALSE (router)
+
+forwarding - BOOLEAN
+ Enable IP forwarding on this interface.
+
+mc_forwarding - BOOLEAN
+ Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
+ and a multicast routing daemon is required.
+
+proxy_arp - BOOLEAN
+ Do proxy arp.
+
+shared_media - BOOLEAN
+ undocumented.
+
+secure_redirects - BOOLEAN
+ Accept ICMP redirect messages only for gateways,
+ listed in default gateway list.
+ default TRUE
+
+redirects - BOOLEAN
+ Send(router) or accept(host) RFC1620 shared media redirects.
+ Overrides ip_secure_redirects.
+ default TRUE (should be FALSE for distributed version,
+ but I use it...)
+
+bootp_relay - BOOLEAN
+ Accept packets with source address 0.b.c.d destined
+ not to this host as local ones. It is supposed, that
+ BOOTP relay deamon will catch and forward such packets.
+
+ default FALSE
+ Not Implemented Yet.
+
+accept_source_route - BOOLEAN
+ Accept packets with SRR option.
+ default TRUE (router)
+ FALSE (host)
+
+rp_filter - INTEGER
+ 2 - do source validation by reversed path, as specified in RFC1812
+ Recommended option for single homed hosts and stub network
+ routers. Could cause troubles for complicated (not loop free)
+ networks running a slow unreliable protocol (sort of RIP),
+ or using static routes.
+
+ 1 - (DEFAULT) Weaker form of RP filtering: drop all the packets
+ that look as sourced at a directly connected interface, but
+ were input from another interface.
+
+ 0 - No source validation.
+
+ NOTE: do not disable this option! All BSD derived routing software
+ (sort of gated, routed etc. etc.) is confused by such packets,
+ even if they are valid. When enabled it also prevents ip spoofing
+ in some limited fashion.
+
+ NOTE: this option is turned on per default only when ip_forwarding
+ is on. For non-forwarding hosts it doesn't make much sense and
+ makes some legal multihoming configurations impossible.
+
Alexey Kuznetsov.
kuznet@ms2.inr.ac.ru
Updated by:
Andi Kleen
ak@muc.de
-$Id: ip-sysctl.txt,v 1.5 1997/10/17 03:58:23 tdyas Exp $
+$Id: ip-sysctl.txt,v 1.7 1998/05/02 12:05:00 davem Exp $
Classes
-------
- "Class" is complete routing table in common sence.
+ "Class" is a complete routing table in common sense.
I.e. it is tree of nodes (destination prefix, tos, metric)
with attached information: gateway, device etc.
This tree is looked up as specified in RFC1812 5.2.4.3
THROW - abort route lookup in this class.
- Currently number of classes is limited by 255
+ Currently the number of classes is limited to 255
(0 is reserved for "not specified class")
Three classes are builtin:
Rules
-----
- Rule is record of (src prefix, src interface, tos, dst prefix)
+ Rule is a record of (src prefix, src interface, tos, dst prefix)
with attached information.
Rule types:
----------------
We scan rules list, and if a rule is matched, apply it.
- If route is found, return it.
- If it is not found or THROW node was matched, continue
+ If a route is found, return it.
+ If it is not found or a THROW node was matched, continue
to scan rules.
Applications
------------
-1. Just ignore classes. All the routes are put to MAIN class
- (and/or to DEFAULT class).
+1. Just ignore classes. All the routes are put into MAIN class
+ (and/or into DEFAULT class).
HOWTO: iproute add PREFIX [ tos TOS ] [ gw GW ] [ dev DEV ]
[ metric METRIC ] [ reject ] ... (look at iproute utility)
[ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ]
[ dev OUTDEV ] .....
- Warning: just now size of routing table in this approach is
- limited by 256. If someone will like this model, I'll
+ Warning: As of now the size of the routing table in this
+ approach is limited to 256. If someone likes this model, I'll
relax this limitation.
3. OSPF classes (see RFC1583, RFC1812 E.3.3)
Very clean, stable and robust algorithm for OSPF routing
- domains. Unfortunately, it is not used widely in the Internet.
+ domains. Unfortunately, it is not widely used in the Internet.
Proposed setup:
255 local addresses
4. The Variant Router Requirements Algorithm (RFC1812 E.3.2)
Create 16 classes for different TOS values.
- It is funny, but pretty useless algorithm.
- I listed it just to show power of new routing code.
+ It is a funny, but pretty useless algorithm.
+ I listed it just to show the power of new routing code.
5. All the variety of combinations......
IMPORTANT NOTE
--------------
- route.c has compilation time switch CONFIG_IP_LOCAL_RT_POLICY.
+ route.c has a compilation time switch CONFIG_IP_LOCAL_RT_POLICY.
If it is set, locally originated packets are routed
- using all the policy list. It is not very convenient and
- pretty ambiguous, when used with NAT and masquerading.
+ using all the policy list. This is not very convenient and
+ pretty ambiguous when used with NAT and masquerading.
I set it to FALSE by default.
- New interface addressing paradigm.
Assignment of address ranges to interface,
multiple prefixes etc. etc.
- Do not bother, it is compatible with old one. Moreover:
-- You more need not do "route add aaa.bbb.ccc... eth0",
+ Do not bother, it is compatible with the old one. Moreover:
+- You don't need to do "route add aaa.bbb.ccc... eth0" anymore,
it is done automatically.
- "Abstract" UNIX sockets and security enhancements.
- It is necessary to use TIRPC and TLI emulation library.
+ This is necessary to use TIRPC and TLI emulation library.
NEWS for hacker.
- New destination cache. Flexible, robust and just beautiful.
- Network stack is reordered, simplified, optimized, a lot of bugs fixed.
- (well, and new bugs are introduced, but I haven't seen them yet 8))
+ (well, and new bugs were introduced, but I haven't seen them yet 8))
It is difficult to describe all the changes, look into source.
If you see this file, then this patch works 8)
# CONFIG_PNP is not set
#
-# Floppy, IDE, and other block devices
+# Block devices
#
CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_IDE=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ACCT is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
.long SYMBOL_NAME(sys_capget)
.long SYMBOL_NAME(sys_capset) /* 185 */
- .rept NR_syscalls-184
+ .rept NR_syscalls-185
.long SYMBOL_NAME(sys_ni_syscall)
.endr
int mpc_default_type = 0; /* non-0 if default (table-less)
MP configuration */
+
+/*
+ * This is performance-critical, we want to do it O(1)
+ */
+static int irq_2_pin[NR_IRQS];
+
unsigned int io_apic_read (unsigned int reg)
{
*IO_APIC_BASE = reg;
*(IO_APIC_BASE+4) = value;
}
-void enable_IO_APIC_irq (unsigned int irq)
+/*
+ * We disable IO-APIC IRQs by setting their 'destination CPU mask' to
+ * zero. Trick, trick.
+ */
+void disable_IO_APIC_irq(unsigned int irq)
{
+ int pin = irq_2_pin[irq];
struct IO_APIC_route_entry entry;
- /*
- * Enable it in the IO-APIC irq-routing table:
- */
- *(((int *)&entry)+0) = io_apic_read(0x10+irq*2);
- entry.mask = 0;
- io_apic_write(0x10+2*irq, *(((int *)&entry)+0));
+ if (pin != -1) {
+ *(((int *)&entry)+1) = io_apic_read(0x11+pin*2);
+ entry.dest.logical.logical_dest = 0x0;
+ io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
+ }
}
-/*
- * this function is just here to make things complete, otherwise it's
- * unused
- */
-void disable_IO_APIC_irq (unsigned int irq)
+void enable_IO_APIC_irq(unsigned int irq)
{
+ int pin = irq_2_pin[irq];
struct IO_APIC_route_entry entry;
- /*
- * Disable it in the IO-APIC irq-routing table:
- */
- *(((int *)&entry)+0) = io_apic_read(0x10+irq*2);
- entry.mask = 1;
- io_apic_write(0x10+2*irq, *(((int *)&entry)+0));
+ if (pin != -1) {
+ *(((int *)&entry)+1) = io_apic_read(0x11+pin*2);
+ entry.dest.logical.logical_dest = 0xff;
+ io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
+ }
}
void clear_IO_APIC_pin (unsigned int pin)
io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
}
+
/*
* support for broken MP BIOSes, enables hand-redirection of PIRQ0-7 to
* specific CPU-side IRQs.
return -1;
}
-static int irq_trigger(int idx)
+/*
+ * There are broken mptables which register ISA+high-active+level IRQs,
+ * these are illegal and are converted here to ISA+high-active+edge
+ * IRQ sources. Careful, ISA+low-active+level is another broken entry
+ * type, it represents PCI IRQs 'embedded into an ISA bus', they have
+ * to be accepted. Yes, ugh.
+ */
+
+static int MPBIOS_polarity(int idx)
{
int bus = mp_irqs[idx].mpc_srcbus;
- int trigger;
+ int polarity;
/*
- * Determine IRQ trigger mode (edge or level sensitive):
+ * Determine IRQ line polarity (high active or low active):
*/
- switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
+ switch (mp_irqs[idx].mpc_irqflag & 3)
{
- case 0: /* conforms, ie. bus-type dependent */
+ case 0: /* conforms, ie. bus-type dependent polarity */
{
switch (mp_bus_id_to_type[bus])
{
- case MP_BUS_ISA: /* ISA pin, edge */
+ case MP_BUS_ISA: /* ISA pin */
{
- trigger = 0;
+ polarity = 0;
break;
}
- case MP_BUS_PCI: /* PCI pin, level */
+ case MP_BUS_PCI: /* PCI pin */
{
- trigger = 1;
+ polarity = 1;
break;
}
default:
{
printk("broken BIOS!!\n");
- trigger = 1;
+ polarity = 1;
break;
}
}
break;
}
- case 1: /* edge */
+ case 1: /* high active */
{
- trigger = 0;
+ polarity = 0;
break;
}
case 2: /* reserved */
{
printk("broken BIOS!!\n");
- trigger = 1;
+ polarity = 1;
break;
}
- case 3: /* level */
+ case 3: /* low active */
{
- trigger = 1;
+ polarity = 1;
break;
}
default: /* invalid */
{
printk("broken BIOS!!\n");
- trigger = 0;
+ polarity = 1;
break;
}
}
- return trigger;
+ return polarity;
}
-__initfunc(static int irq_polarity(int idx))
+
+static int MPBIOS_trigger(int idx)
{
int bus = mp_irqs[idx].mpc_srcbus;
- int polarity;
+ int trigger;
/*
- * Determine IRQ line polarity (high active or low active):
+ * Determine IRQ trigger mode (edge or level sensitive):
*/
- switch (mp_irqs[idx].mpc_irqflag & 3)
+ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
{
- case 0: /* conforms, ie. bus-type dependent polarity */
+ case 0: /* conforms, ie. bus-type dependent */
{
switch (mp_bus_id_to_type[bus])
{
- case MP_BUS_ISA: /* ISA pin */
+ case MP_BUS_ISA: /* ISA pin, edge */
{
- polarity = 0;
+ trigger = 0;
break;
}
- case MP_BUS_PCI: /* PCI pin */
+ case MP_BUS_PCI: /* PCI pin, level */
{
- polarity = 1;
+ trigger = 1;
break;
}
default:
{
printk("broken BIOS!!\n");
- polarity = 1;
+ trigger = 1;
break;
}
}
break;
}
- case 1: /* high active */
+ case 1: /* edge */
{
- polarity = 0;
+ trigger = 0;
break;
}
case 2: /* reserved */
{
printk("broken BIOS!!\n");
- polarity = 1;
+ trigger = 1;
break;
}
- case 3: /* low active */
+ case 3: /* level */
{
- polarity = 1;
+ trigger = 1;
break;
}
default: /* invalid */
{
printk("broken BIOS!!\n");
- polarity = 1;
+ trigger = 0;
break;
}
}
- return polarity;
+ return trigger;
+}
+
+static int trigger_flag_broken (int idx)
+{
+ int bus = mp_irqs[idx].mpc_srcbus;
+ int polarity = MPBIOS_polarity(idx);
+ int trigger = MPBIOS_trigger(idx);
+
+ if ( (mp_bus_id_to_type[bus] == MP_BUS_ISA) &&
+ (polarity == 0) /* active-high */ &&
+ (trigger == 1) /* level */ )
+
+ return 1; /* broken */
+
+ return 0;
+}
+
+static int irq_polarity (int idx)
+{
+ /*
+ * There are no known BIOS bugs wrt polarity. yet.
+ */
+ return MPBIOS_polarity(idx);
}
-__initfunc(static int pin_2_irq (int idx, int pin))
+static int irq_trigger (int idx)
+{
+ int trigger = MPBIOS_trigger(idx);
+
+ if (trigger_flag_broken (idx))
+ trigger = 0;
+ return trigger;
+}
+
+static int pin_2_irq (int idx, int pin)
{
int irq;
int bus = mp_irqs[idx].mpc_srcbus;
+ /*
+ * Debugging check, we are in big trouble if this message pops up!
+ */
+ if (mp_irqs[idx].mpc_dstirq != pin)
+ printk("broken BIOS or MPTABLE parser, ayiee!!\n");
+
switch (mp_bus_id_to_type[bus])
{
case MP_BUS_ISA: /* ISA pin */
int IO_APIC_irq_trigger (int irq)
{
- int idx, i;
+ int idx, pin;
- for (i=0; i<nr_ioapic_registers; i++) {
- idx = find_irq_entry(i,mp_INT);
- if (irq == pin_2_irq(idx,i))
- return irq_trigger(idx);
+ for (pin=0; pin<nr_ioapic_registers; pin++) {
+ idx = find_irq_entry(pin,mp_INT);
+ if ((idx != -1) && (irq == pin_2_irq(idx,pin)))
+ return (irq_trigger(idx));
}
/*
* nonexistant IRQs are edge default
__initfunc(void setup_IO_APIC_irqs (void))
{
struct IO_APIC_route_entry entry;
- int i, idx, bus, irq, first_notcon=1;
+ int pin, idx, bus, irq, first_notcon=1;
printk("init IO_APIC IRQs\n");
- for (i=0; i<nr_ioapic_registers; i++) {
+ for (pin=0; pin<nr_ioapic_registers; pin++) {
/*
* add it to the IO-APIC irq-routing table:
entry.mask = 0; /* enable IRQ */
entry.dest.logical.logical_dest = 0xff; /* all CPUs */
- idx = find_irq_entry(i,mp_INT);
+ idx = find_irq_entry(pin,mp_INT);
if (idx == -1) {
if (first_notcon) {
- printk(" IO-APIC pin %d", i);
+ printk(" IO-APIC pin %d", pin);
first_notcon=0;
} else
- printk(", %d", i);
+ printk(", %d", pin);
continue;
}
entry.trigger = irq_trigger(idx);
entry.polarity = irq_polarity(idx);
- irq = pin_2_irq(idx,i);
+ irq = pin_2_irq(idx,pin);
+ irq_2_pin[irq] = pin;
if (!IO_APIC_IRQ(irq))
continue;
entry.vector = IO_APIC_VECTOR(irq);
- /*
- * There are broken mptables which register ISA+high-active+level IRQs,
- * these are illegal and are converted here to ISA+high-active+edge
- * IRQ sources. Careful, ISA+low-active+level is another broken entry
- * type, it represents PCI IRQs 'embedded into an ISA bus', they have
- * to be accepted. Yes, ugh.
- */
bus = mp_irqs[idx].mpc_srcbus;
- if ( (mp_bus_id_to_type[bus] == MP_BUS_ISA) &&
- (entry.polarity == 0) /* active-high */ &&
- (entry.trigger == 1) /* level */ )
- {
- printk("broken BIOS, changing pin %d to edge\n", i);
- entry.trigger = 0;
- }
+ if (trigger_flag_broken (idx))
+ printk("broken BIOS, changing pin %d to edge\n", pin);
- io_apic_write(0x10+2*i, *(((int *)&entry)+0));
- io_apic_write(0x11+2*i, *(((int *)&entry)+1));
+ io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
+ io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
}
if (!first_notcon)
io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
}
-__initfunc(void print_IO_APIC (void))
+void print_IO_APIC (void)
{
int i;
struct IO_APIC_reg_00 reg_00;
printk(".... IRQ redirection table:\n");
- printk(" NR Log Phy ");
+ printk(" NR Log Phy ");
printk("Mask Trig IRR Pol Stat Dest Deli Vect: \n");
for (i=0; i<=reg_01.entries; i++) {
*(((int *)&entry)+0) = io_apic_read(0x10+i*2);
*(((int *)&entry)+1) = io_apic_read(0x11+i*2);
- printk(" %02x %03X %02X ",
+ printk(" %02x %03X %02X ",
i,
entry.dest.logical.logical_dest,
entry.dest.physical.physical_dest
);
}
+ printk("IRQ to pin mappings:\n");
+ for (i=0; i<NR_IRQS; i++)
+ printk("%d->%d ", i, irq_2_pin[i]);
+ printk("\n");
+
printk(".................................... done.\n");
return;
__initfunc(static void init_sym_mode (void))
{
- int i;
+ int i, pin;
+ for (i=0; i<NR_IRQS; i++)
+ irq_2_pin[i] = -1;
if (!pirqs_enabled)
for (i=0; i<MAX_PIRQS; i++)
pirq_entries[i]=-1;
/*
* Do not trust the IO-APIC being empty at bootup
*/
- for (i=0; i<nr_ioapic_registers; i++)
- clear_IO_APIC_pin (i);
+ for (pin=0; pin<nr_ioapic_registers; pin++)
+ clear_IO_APIC_pin (pin);
}
/*
/*
* Level and edge triggered IO-APIC interrupts need different handling,
- * so we use two separate irq descriptors:
+ * so we use two separate irq descriptors. edge triggered IRQs can be
+ * handled with the level-triggered descriptor, but that one has slightly
+ * more overhead. Level-triggered interrupts cannot be handled with the
+ * edge-triggered handler, without risking IRQ storms and other ugly
+ * races.
*/
static void do_edge_ioapic_IRQ (unsigned int irq, int cpu,
}
}
-void unmask_generic_irq(unsigned int irq)
-{
- irq_desc[irq].status = 0;
- if (IO_APIC_IRQ(irq))
- enable_IO_APIC_irq(irq);
- else {
- cached_irq_mask &= ~(1 << irq);
- set_8259A_irq_mask(irq);
- }
-}
-
/*
* This builds up the IRQ handler stubs using some ugly macros in irq.h
*
BUILD_SMP_INTERRUPT(invalidate_interrupt)
BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_INTERRUPT(mtrr_interrupt)
+BUILD_SMP_INTERRUPT(spurious_interrupt)
/*
* every pentium local APIC has two 'local interrupts', with a
p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
#ifdef __SMP__
p += sprintf(p, "IPI: %10lu\n", ipi_count);
+ print_IO_APIC();
#endif
return p - buf;
}
set_8259A_irq_mask(irq);
}
+int i8259A_irq_pending (unsigned int irq)
+{
+ unsigned int mask = 1<<irq;
+
+ if (irq < 8)
+ return (inb(0x20) & mask);
+ return (inb(0xA0) & (mask >> 8));
+}
+
+
void make_8259A_irq (unsigned int irq)
{
io_apic_irqs &= ~(1<<irq);
{
}
-/*
- * if we enable this, why does it cause a hang in the BusLogic
- * driver, when level triggered PCI IRQs are used?
- */
-#define NOT_BROKEN 0
-
static void enable_level_ioapic_irq(unsigned int irq)
{
-#if NOT_BROKEN
enable_IO_APIC_irq(irq);
-#endif
self_IPI(irq);
}
static void disable_level_ioapic_irq(unsigned int irq)
{
-#if NOT_BROKEN
disable_IO_APIC_irq(irq);
-#endif
}
/*
- * Has to be called with the irq controller locked
+ * Has to be called with the irq controller locked, and has to exit
+ * with with the lock held as well.
*/
static void handle_ioapic_event (unsigned int irq, int cpu,
struct pt_regs * regs)
while (test_bit(0,&global_irq_lock)) barrier();
for (;;) {
- int pending;
+ int pending, handler;
- /* If there is no IRQ handler, exit early, leaving the irq "in progress" */
- if (!handle_IRQ_event(irq, regs))
- goto no_handler;
+ /*
+ * If there is no IRQ handler, exit early, leaving the irq
+ * "in progress"
+ */
+ handler = handle_IRQ_event(irq, regs);
spin_lock(&irq_controller_lock);
+ if (!handler)
+ goto no_handler;
+
pending = desc->events;
desc->events = 0;
if (!pending)
spin_unlock(&irq_controller_lock);
}
desc->status &= IRQ_DISABLED;
- spin_unlock(&irq_controller_lock);
no_handler:
}
}
handle_ioapic_event(irq,cpu,regs);
+ spin_unlock(&irq_controller_lock);
hardirq_exit(cpu);
release_irqlock(cpu);
spin_lock(&irq_controller_lock);
/*
- * in the level triggered case we first disable the IRQ
+ * In the level triggered case we first disable the IRQ
* in the IO-APIC, then we 'early ACK' the IRQ, then we
* handle it and enable the IRQ when finished.
+ *
+ * disable has to happen before the ACK, to avoid IRQ storms.
+ * So this all has to be within the spinlock.
*/
-#if NOT_BROKEN
disable_IO_APIC_irq(irq);
-#endif
ack_APIC_irq();
desc->ipi = 0;
}
handle_ioapic_event(irq,cpu,regs);
+ /* we still have the spinlock held here */
+
+ enable_IO_APIC_irq(irq);
+ spin_unlock(&irq_controller_lock);
hardirq_exit(cpu);
release_irqlock(cpu);
struct irqaction *old, **p;
unsigned long flags;
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&irq_controller_lock,flags);
p = &irq_desc[irq].action;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ))
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
return -EBUSY;
+ }
/* add new interrupt at end of irq queue */
do {
shared = 1;
}
- if (new->flags & SA_SAMPLE_RANDOM)
- rand_initialize_irq(irq);
-
- save_flags(flags);
- cli();
*p = new;
if (!shared) {
- spin_lock(&irq_controller_lock);
#ifdef __SMP__
if (IO_APIC_IRQ(irq)) {
if (IO_APIC_VECTOR(irq) > 0xfe)
* First disable it in the 8259A:
*/
cached_irq_mask |= 1 << irq;
- if (irq < 16)
+ if (irq < 16) {
set_8259A_irq_mask(irq);
+ /*
+ * transport pending ISA IRQs to
+ * the new descriptor
+ */
+ if (i8259A_irq_pending(irq))
+ irq_desc[irq].events = 1;
+ }
}
#endif
- unmask_generic_irq(irq);
- spin_unlock(&irq_controller_lock);
+ irq_desc[irq].handler->enable(irq);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
return 0;
}
struct irqaction * action, **p;
unsigned long flags;
- if (irq >= NR_IRQS) {
- printk("Trying to free IRQ%d\n",irq);
+ if (irq >= NR_IRQS)
return;
- }
+
+ spin_lock_irqsave(&irq_controller_lock,flags);
for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;
/* Found it - now free it */
- save_flags(flags);
- cli();
*p = action->next;
- restore_flags(flags);
kfree(action);
- return;
+ irq_desc[irq].handler->disable(irq);
+ goto out;
}
printk("Trying to free free IRQ%d\n",irq);
+out:
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
}
/*
spin_lock_irq(&irq_controller_lock);
for (i = NR_IRQS-1; i > 0; i--) {
if (!irq_desc[i].action) {
- unmask_generic_irq(i);
+ irq_desc[i].handler->enable(i);
irqs |= (1 << i);
}
}
(IO_APIC_IRQ(i))) {
if (IO_APIC_irq_trigger(i))
irq_desc[i].handler = &ioapic_level_irq_type;
- else
- irq_desc[i].handler = &ioapic_edge_irq_type;
+ else /* edge */
+ irq_desc[i].handler = &ioapic_level_irq_type;
/*
* disable it in the 8259A:
*/
/* IPI for MTRR control */
set_intr_gate(0x50, mtrr_interrupt);
+ /* IPI vector for APIC spurious interrupts */
+ set_intr_gate(0xff, spurious_interrupt);
#endif
request_region(0x20,0x20,"pic1");
request_region(0xa0,0x20,"pic2");
void unmask_irq(unsigned int irq);
void enable_IO_APIC_irq (unsigned int irq);
void disable_IO_APIC_irq (unsigned int irq);
-void set_8259A_irq_mask(unsigned int irq);
+void set_8259A_irq_mask (unsigned int irq);
+int i8259A_irq_pending (unsigned int irq);
void ack_APIC_irq (void);
void setup_IO_APIC (void);
void init_IO_APIC_traps(void);
void make_8259A_irq (unsigned int irq);
void send_IPI (int dest, int vector);
void init_pic_mode (void);
+void print_IO_APIC (void);
extern unsigned int io_apic_irqs;
*/
p->tss.bitmap = sizeof(struct thread_struct);
+/*
+ * This tried to copy the FPU state, but I wonder whether we really
+ * want this at all. It is probably nicer to just have a newly started
+ * process start with a clean slate wrt the fpu. - Linus
+ */
+#if 1
+ current->used_math = 0;
+ current->flags &= ~PF_USEDFPU;
+#else
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
+#endif
return 0;
}
int nr = c->x86_model;
char *buf = c->x86_model_id;
+ /* Cyrix claims they have a TSC, but it is broken */
+ c->x86_capability &= ~16;
+
/* Note that some of the possibilities this decoding allows
* have never actually been manufactured - but those that
* do actually exist are correctly decoded.
value = apic_read(APIC_SPIV);
value |= (1<<8); /* Enable APIC (bit==1) */
value &= ~(1<<9); /* Enable focus processor (bit==0) */
+ value |= 0xff; /* Set spurious IRQ vector to 0xff */
apic_write(APIC_SPIV,value);
+ value = apic_read(APIC_TASKPRI);
+ value &= ~APIC_TPRI_MASK; /* Set Task Priority to 'accept all' */
+ apic_write(APIC_TASKPRI,value);
+
udelay(100); /* B safe */
+ ack_APIC_irq();
+ udelay(100);
}
__initfunc(void smp_callin(void))
__restore_flags(flags);
}
-void funny (void)
-{
- send_IPI(APIC_DEST_ALLBUT,0x30 /*IO_APIC_VECTOR(11)*/);
- for(;;)__cli();
-}
-
/*
* A non wait message cannot pass data or cpu source info. This current setup
* is only safe because the kernel lock owner is the only person who can send
}
/*
- * Reschedule call back
+ * Reschedule call back (not used currently)
*/
+
asmlinkage void smp_reschedule_interrupt(void)
{
int cpu = smp_processor_id();
ack_APIC_irq();
- for (;;) __cli();
/*
* This looks silly, but we actually do need to wait
* for the global interrupt lock.
*/
- printk("huh, this is used, where???\n");
irq_enter(cpu, 0);
need_resched = 1;
irq_exit(cpu, 0);
if (mtrr_hook) (*mtrr_hook) ();
}
+/*
+ * This interrupt should _never_ happen with our APIC/SMP architecture
+ */
+asmlinkage void smp_spurious_interrupt(void)
+{
+ ack_APIC_irq ();
+ printk("spurious APIC interrupt, ayiee, should never happen.\n");
+}
+
/*
* This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts
* per second. We assume that the caller has already set up the local
xtime.tv_usec = 0;
/* If we have the CPU hardware time counters, use them */
-#ifndef CONFIG_APM
- /* Don't use them if a suspend/resume could
- corrupt the timer value. This problem
- needs more debugging. */
if (boot_cpu_data.x86_capability & 16) {
do_gettimeoffset = do_fast_gettimeoffset;
do_get_fast_time = do_x86_get_fast_time;
"=d" (init_timer_cc.high));
irq0.handler = pentium_timer_interrupt;
}
-#endif
setup_x86_irq(0, &irq0);
}
tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
endif
endif
+ifeq ($(CONFIG_LNE390),y)
+L_OBJS += lne390.o
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_LNE390),m)
+ CONFIG_8390_MODULE = y
+ M_OBJS += lne390.o
+ endif
+endif
ifeq ($(CONFIG_PLIP),y)
L_OBJS += plip.o
extern int elplus_probe(struct device *);
extern int ac3200_probe(struct device *);
extern int es_probe(struct device *);
+extern int lne390_probe(struct device *);
extern int e2100_probe(struct device *);
extern int ni5010_probe(struct device *);
extern int ni52_probe(struct device *);
#ifdef CONFIG_ES3210
&& es_probe(dev)
#endif
+#ifdef CONFIG_LNE390
+ && lne390_probe(dev)
+#endif
#ifdef CONFIG_E2100 /* Cabletron E21xx series. */
&& e2100_probe(dev)
#endif
--- /dev/null
+/*
+ lne390.c
+
+ Linux driver for Mylex LNE390 EISA Network Adapter
+
+ Copyright (C) 1996-1998, Paul Gortmaker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Information and Code Sources:
+
+ 1) Based upon framework of es3210 driver.
+ 2) The existing myriad of other Linux 8390 drivers by Donald Becker.
+ 3) Russ Nelson's asm packet driver provided additional info.
+ 4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
+
+ The LNE390 is an EISA shared memory NS8390 implementation. Note
+ that all memory copies to/from the board must be 32bit transfers.
+ There are two versions of the card: the lne390a and the lne390b.
+ Going by the EISA cfg files, the "a" has jumpers to select between
+ BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU.
+ The shared memory address selection is also slightly different.
+ Note that shared memory address > 1MB are supported with this driver.
+
+ You can try <http://www.mylex.com> if you want more info, as I've
+ never even seen one of these cards. :)
+
+*/
+
+static const char *version =
+ "lne390.c: Driver revision v0.99, 12/05/98\n";
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+int lne390_probe(struct device *dev);
+int lne390_probe1(struct device *dev, int ioaddr);
+
+static int lne390_open(struct device *dev);
+static int lne390_close(struct device *dev);
+
+static void lne390_reset_8390(struct device *dev);
+
+static void lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
+static void lne390_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset);
+static void lne390_block_output(struct device *dev, int count, const unsigned char *buf, const start_page);
+
+#define LNE390_START_PG 0x00 /* First page of TX buffer */
+#define LNE390_STOP_PG 0x80 /* Last page +1 of RX ring */
+
+#define LNE390_ID_PORT 0xc80 /* Same for all EISA cards */
+#define LNE390_IO_EXTENT 0x20
+#define LNE390_SA_PROM 0x16 /* Start of e'net addr. */
+#define LNE390_RESET_PORT 0xc84 /* From the pkt driver source */
+#define LNE390_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
+
+#define LNE390_ADDR0 0x00 /* 3 byte vendor prefix */
+#define LNE390_ADDR1 0x80
+#define LNE390_ADDR2 0xe5
+
+#define LNE390_ID0 0x10009835 /* 0x3598 = 01101 01100 11000 = mlx */
+#define LNE390_ID1 0x11009835 /* above is the 390A, this is 390B */
+
+#define LNE390_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
+#define LNE390_CFG2 0xc90
+
+/*
+ * You can OR any of the following bits together and assign it
+ * to LNE390_DEBUG to get verbose driver info during operation.
+ * Currently only the probe one is implemented.
+ */
+
+#define LNE390_D_PROBE 0x01
+#define LNE390_D_RX_PKT 0x02
+#define LNE390_D_TX_PKT 0x04
+#define LNE390_D_IRQ 0x08
+
+#define LNE390_DEBUG 0
+
+static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
+static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
+static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
+
+/*
+ * Probe for the card. The best way is to read the EISA ID if it
+ * is known. Then we can check the prefix of the station address
+ * PROM for a match against the value assigned to Mylex.
+ */
+
+__initfunc(int lne390_probe(struct device *dev))
+{
+ unsigned short ioaddr = dev->base_addr;
+
+ if (ioaddr > 0x1ff) /* Check a single specified location. */
+ return lne390_probe1(dev, ioaddr);
+ else if (ioaddr > 0) /* Don't probe at all. */
+ return ENXIO;
+
+ if (!EISA_bus) {
+#if LNE390_DEBUG & LNE390_D_PROBE
+ printk("lne390-debug: Not an EISA bus. Not probing high ports.\n");
+#endif
+ return ENXIO;
+ }
+
+ /* EISA spec allows for up to 16 slots, but 8 is typical. */
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+ if (check_region(ioaddr , LNE390_IO_EXTENT))
+ continue;
+ if (lne390_probe1(dev, ioaddr) == 0)
+ return 0;
+ }
+
+ return ENODEV;
+}
+
+__initfunc(int lne390_probe1(struct device *dev, int ioaddr))
+{
+ int i, revision;
+ unsigned long eisa_id;
+
+ if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
+
+#if LNE390_DEBUG & LNE390_D_PROBE
+ printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT));
+ printk("lne390-debug: config regs: %#x %#x\n",
+ inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2));
+#endif
+
+
+/* Check the EISA ID of the card. */
+ eisa_id = inl(ioaddr + LNE390_ID_PORT);
+ if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) {
+ return ENODEV;
+ }
+
+ revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */
+
+#if 0
+/* Check the Mylex vendor ID as well. Not really required. */
+ if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
+ || inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
+ || inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
+ printk("lne390.c: card not found");
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
+ printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
+ printk(" (invalid prefix).\n");
+ return ENODEV;
+ }
+#endif
+
+ /* We should have a "dev" from Space.c or the static module table. */
+ if (dev == NULL) {
+ printk("lne390.c: Passed a NULL device.\n");
+ dev = init_etherdev(0, 0);
+ }
+
+ printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
+ printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i)));
+ printk(".\nlne390.c: ");
+
+ /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
+ if (dev->irq == 0) {
+ unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3;
+ dev->irq = irq_map[irq_reg & 0x07];
+ printk("using");
+ } else {
+ /* This is useless unless we reprogram the card here too */
+ if (dev->irq == 2) dev->irq = 9; /* Doh! */
+ printk("assigning");
+ }
+ printk(" IRQ %d,", dev->irq);
+
+ if (request_irq(dev->irq, ei_interrupt, 0, "lne390", NULL)) {
+ printk (" unable to get IRQ %d.\n", dev->irq);
+ return EAGAIN;
+ }
+
+ if (dev->mem_start == 0) {
+ unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07;
+
+ if (revision) /* LNE390B */
+ dev->mem_start = shmem_mapB[mem_reg] * 0x10000;
+ else /* LNE390A */
+ dev->mem_start = shmem_mapA[mem_reg] * 0x10000;
+ printk(" using ");
+ } else {
+ /* Should check for value in shmem_map and reprogram the card to use it */
+ dev->mem_start &= 0xfff0000;
+ printk(" assigning ");
+ }
+
+ printk("%dkB memory at physical address %#lx\n",
+ LNE390_STOP_PG/4, dev->mem_start);
+
+ /*
+ BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
+ the card mem within the region covered by `normal' RAM !!!
+ */
+ if (dev->mem_start > 1024*1024) { /* phys addr > 1MB */
+ if (dev->mem_start < (unsigned long)high_memory) {
+ printk(KERN_CRIT "lne390.c: Card RAM overlaps with normal memory!!!\n");
+ printk(KERN_CRIT "lne390.c: Use EISA SCU to set card memory below 1MB,\n");
+ printk(KERN_CRIT "lne390.c: or to an address above %p.\n", high_memory);
+ printk(KERN_CRIT "lne390.c: Driver NOT installed.\n");
+ free_irq(dev->irq, dev);
+ return EINVAL;
+ }
+ dev->mem_start = (unsigned long)ioremap(dev->mem_start, LNE390_STOP_PG*0x100);
+ if (dev->mem_start == 0) {
+ printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n");
+ printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n");
+ printk(KERN_ERR "lne390.c: Driver NOT installed.\n");
+ free_irq(dev->irq, dev);
+ return EAGAIN;
+ }
+ printk("lne390.c: remapped %dkB card memory to virtual address %#lx\n",
+ LNE390_STOP_PG/4, dev->mem_start);
+ }
+
+ dev->mem_end = dev->rmem_end = dev->mem_start
+ + (LNE390_STOP_PG - LNE390_START_PG)*256;
+ dev->rmem_start = dev->mem_start + TX_PAGES*256;
+
+ /* Allocate dev->priv and fill in 8390 specific dev fields. */
+ if (ethdev_init(dev)) {
+ printk ("lne390.c: unable to allocate memory for dev->priv!\n");
+ free_irq(dev->irq, dev);
+ return -ENOMEM;
+ }
+
+ /* The 8390 offset is zero for the LNE390 */
+ dev->base_addr = ioaddr;
+ request_region(dev->base_addr, LNE390_IO_EXTENT, "lne390");
+
+ ei_status.name = "LNE390";
+ ei_status.tx_start_page = LNE390_START_PG;
+ ei_status.rx_start_page = LNE390_START_PG + TX_PAGES;
+ ei_status.stop_page = LNE390_STOP_PG;
+ ei_status.word16 = 1;
+
+ if (ei_debug > 0)
+ printk(version);
+
+ ei_status.reset_8390 = &lne390_reset_8390;
+ ei_status.block_input = &lne390_block_input;
+ ei_status.block_output = &lne390_block_output;
+ ei_status.get_8390_hdr = &lne390_get_8390_hdr;
+
+ dev->open = &lne390_open;
+ dev->stop = &lne390_close;
+ NS8390_init(dev, 0);
+ return 0;
+}
+
+/*
+ * Reset as per the packet driver method. Judging by the EISA cfg
+ * file, this just toggles the "Board Enable" bits (bit 2 and 0).
+ */
+
+static void lne390_reset_8390(struct device *dev)
+{
+ unsigned short ioaddr = dev->base_addr;
+
+ outb(0x04, ioaddr + LNE390_RESET_PORT);
+ if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name);
+
+ udelay(2*1000);
+
+ ei_status.txing = 0;
+ outb(0x01, ioaddr + LNE390_RESET_PORT);
+ if (ei_debug > 1) printk("reset done\n");
+
+ return;
+}
+
+/*
+ * Note: In the following three functions is the implicit assumption
+ * that the associated memcpy will only use "rep; movsl" as long as
+ * we keep the counts as some multiple of doublewords. This is a
+ * requirement of the hardware, and also prevents us from using
+ * eth_io_copy_and_sum() since we can't guarantee it will limit
+ * itself to doubleword access.
+ */
+
+/*
+ * Grab the 8390 specific header. Similar to the block_input routine, but
+ * we don't need to be concerned with ring wrap as the header will be at
+ * the start of a page, so we optimize accordingly. (A single doubleword.)
+ */
+
+static void
+lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+ unsigned long hdr_start = dev->mem_start + ((ring_page - LNE390_START_PG)<<8);
+ memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+ hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
+}
+
+/*
+ * Block input and output are easy on shared memory ethercards, the only
+ * complication is when the ring buffer wraps. The count will already
+ * be rounded up to a doubleword value via lne390_get_8390_hdr() above.
+ */
+
+static void lne390_block_input(struct device *dev, int count, struct sk_buff *skb,
+ int ring_offset)
+{
+ unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8);
+
+ if (xfer_start + count > dev->rmem_end) {
+ /* Packet wraps over end of ring buffer. */
+ int semi_count = dev->rmem_end - xfer_start;
+ memcpy_fromio(skb->data, xfer_start, semi_count);
+ count -= semi_count;
+ memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ } else {
+ /* Packet is in one chunk. */
+ memcpy_fromio(skb->data, xfer_start, count);
+ }
+}
+
+static void lne390_block_output(struct device *dev, int count,
+ const unsigned char *buf, int start_page)
+{
+ unsigned long shmem = dev->mem_start + ((start_page - LNE390_START_PG)<<8);
+
+ count = (count + 3) & ~3; /* Round up to doubleword */
+ memcpy_toio(shmem, buf, count);
+}
+
+static int lne390_open(struct device *dev)
+{
+ ei_open(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int lne390_close(struct device *dev)
+{
+
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+
+ ei_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#ifdef MODULE
+#define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */
+#define NAMELEN 8 /* # of chars for storing dev->name */
+static char namelist[NAMELEN * MAX_LNE_CARDS] = { 0, };
+static struct device dev_lne[MAX_LNE_CARDS] = {
+ {
+ NULL, /* assign a chunk of namelist[] below */
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, NULL
+ },
+};
+
+static int io[MAX_LNE_CARDS] = { 0, };
+static int irq[MAX_LNE_CARDS] = { 0, };
+static int mem[MAX_LNE_CARDS] = { 0, };
+
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
+MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
+
+int init_module(void)
+{
+ int this_dev, found = 0;
+
+ for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
+ struct device *dev = &dev_lne[this_dev];
+ dev->name = namelist+(NAMELEN*this_dev);
+ dev->irq = irq[this_dev];
+ dev->base_addr = io[this_dev];
+ dev->mem_start = mem[this_dev];
+ dev->init = lne390_probe;
+ /* Default is to only install one card. */
+ if (io[this_dev] == 0 && this_dev != 0) break;
+ if (register_netdev(dev) != 0) {
+ printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
+ if (found != 0) return 0; /* Got at least one. */
+ return -ENXIO;
+ }
+ found++;
+ }
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int this_dev;
+
+ for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
+ struct device *dev = &dev_lne[this_dev];
+ if (dev->priv != NULL) {
+ kfree(dev->priv);
+ dev->priv = NULL;
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, LNE390_IO_EXTENT);
+ unregister_netdev(dev);
+ }
+ }
+}
+#endif /* MODULE */
+
idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
u8 *scsi_buf;
+ unsigned long flags;
if (rq->cmd != IDESCSI_PC_RQ) {
ide_end_request (uptodate, hwgroup);
} else printk("\n");
}
}
+ spin_lock_irqsave(&io_request_lock,flags);
pc->done(pc->scsi_cmd);
+ spin_unlock_irqrestore(&io_request_lock,flags);
idescsi_free_bh (rq->bh);
kfree(pc); kfree(rq);
scsi->pc = NULL;
rq->buffer = (char *) pc;
rq->bh = idescsi_dma_bh (drive, pc);
rq->cmd = IDESCSI_PC_RQ;
+ spin_unlock(&io_request_lock);
(void) ide_do_drive_cmd (drive, rq, ide_end);
+ spin_lock(&io_request_lock);
return 0;
abort:
if (pc) kfree (pc);
unsigned char *buffer;
int the_result, retries;
Scsi_Cmnd * SCpnt;
+ unsigned long flags;
buffer = (unsigned char *) scsi_malloc(512);
SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
+ spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd (SCpnt,
(void *) cmd, (void *) buffer,
512, sr_init_done, SR_TIMEOUT,
MAX_RETRIES);
+ spin_unlock_irqrestore(&io_request_lock, flags);
down(&sem);
}
Scsi_Cmnd * SCpnt;
Scsi_Device * SDev;
int result, err = 0, retries = 0;
+ unsigned long flags;
SDev = scsi_CDs[target].device;
SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1);
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
+ spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd(SCpnt,
(void *) sr_cmd, buffer, buflength, sr_ioctl_done,
IOCTL_TIMEOUT, IOCTL_RETRIES);
+ spin_unlock_irqrestore(&io_request_lock, flags);
down(&sem);
SCpnt->request.sem = NULL;
}
-dep_tristate 'ProAudioSpectrum 16 support' CONFIG_PAS $CONFIG_SOUND
-if [ "$CONFIG_PAS" = "y" ]; then
+# drivers/sound/Config.in
+#
+# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
+# More hacking for modularisation.
+#
+# See drivers/sound/README.CONFIG for more information.
+
+
+
+# Prompt user for primary drivers.
+
+dep_tristate 'ProAudioSpectrum 16 support' CONFIG_SOUND_PAS $CONFIG_SOUND
+if [ "$CONFIG_SOUND_PAS" = "y" ]; then
int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10
int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3
bool 'Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK
fi
-dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND
-if [ "$CONFIG_SB" = "y" ]; then
+dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND
+if [ "$CONFIG_SOUND_SB" = "y" ]; then
hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220
int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7
int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1
int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1
fi
-dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB $CONFIG_SOUND
+dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND
-dep_tristate 'Gravis Ultrasound support' CONFIG_GUS $CONFIG_SOUND
-if [ "$CONFIG_GUS" != "n" ]; then
+dep_tristate 'Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND
+if [ "$CONFIG_SOUND_GUS" = "y" -o "$CONFIG_SOUND_GUS" = "m" ]; then
bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16
bool 'GUS MAX support' CONFIG_GUSMAX
- if [ "$CONFIG_GUS" = "y" ]; then
- hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220
- int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15
- int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6
- int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1
- if [ "$CONFIG_GUS16" = "y" ]; then
- hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530
- int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7
- int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3
- fi
+fi
+if [ "$CONFIG_SOUND_GUS" = "y" ]; then
+ hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220
+ int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15
+ int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6
+ int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1
+ if [ "$CONFIG_GUS16" = "y" ]; then
+ hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530
+ int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7
+ int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3
fi
fi
-dep_tristate 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 $CONFIG_SOUND
-if [ "$CONFIG_MPU401" = "y" ]; then
+dep_tristate 'MPU-401 support (NOT for SB16)' CONFIG_SOUND_MPU401 $CONFIG_SOUND
+if [ "$CONFIG_SOUND_MPU401" = "y" ]; then
hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330
int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9
fi
-dep_tristate 'PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_PSS $CONFIG_SOUND
-if [ "$CONFIG_PSS" = "y" ]; then
+dep_tristate 'PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_SOUND_PSS $CONFIG_SOUND
+if [ "$CONFIG_SOUND_PSS" = "y" ]; then
hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220
hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530
int 'PSS audio IRQ 7, 9, 10 or 11' CONFIG_PSS_MSS_IRQ 11
string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE
fi
fi
-if [ "$CONFIG_PSS" = "m" ] || [ "$CONFIG_PSS" = "y" ]; then
+if [ "$CONFIG_SOUND_PSS" = "y" -o "$CONFIG_SOUND_PSS" = "m" ]; then
bool ' Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER
fi
-dep_tristate 'Microsoft Sound System support' CONFIG_MSS $CONFIG_SOUND
-if [ "$CONFIG_MSS" = "y" ]; then
+dep_tristate 'Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND
+if [ "$CONFIG_SOUND_MSS" = "y" ]; then
hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530
int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11
int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3
int 'MSS/WSS second DMA (if possible) 0, 1 or 3' CONFIG_MSS_DMA2 -1
fi
-dep_tristate 'Ensoniq SoundScape support' CONFIG_SSCAPE $CONFIG_SOUND
-if [ "$CONFIG_SSCAPE" = "y" ]; then
+dep_tristate 'Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND
+if [ "$CONFIG_SOUND_SSCAPE" = "y" ]; then
hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' CONFIG_SSCAPE_BASE 330
int 'SoundScape MIDI IRQ ' CONFIG_SSCAPE_IRQ 9
int 'SoundScape initialization DMA 0, 1 or 3' CONFIG_SSCAPE_DMA 3
int 'SoundScape audio IRQ 7, 9, 10 or 11' CONFIG_SSCAPE_MSS_IRQ 11
fi
-dep_tristate 'MediaTrix AudioTrix Pro support' CONFIG_TRIX $CONFIG_SOUND
-if [ "$CONFIG_TRIX" = "y" ]; then
+dep_tristate 'MediaTrix AudioTrix Pro support' CONFIG_SOUND_TRIX $CONFIG_SOUND
+if [ "$CONFIG_SOUND_TRIX" = "y" ]; then
hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_TRIX_BASE 530
int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_TRIX_IRQ 11
int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_TRIX_DMA 0
fi
fi
-dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 $CONFIG_SOUND
-dep_tristate 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD $CONFIG_MAD16
-if [ "$CONFIG_MAD16" = "y" ]; then
+dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND
+dep_tristate 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD $CONFIG_SOUND_MAD16
+if [ "$CONFIG_SOUND_MAD16" = "y" ]; then
hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530
int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11
int 'MAD16 audio DMA 0, 1 or 3' CONFIG_MAD16_DMA 3
int 'MAD16 MIDI IRQ 5, 7, 9 or 10' CONFIG_MAD16_MPU_IRQ 9
fi
-dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 $CONFIG_SOUND
-if [ "$CONFIG_CS4232" = "y" ]; then
+dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND
+if [ "$CONFIG_SOUND_CS4232" = "y" ]; then
hex 'CS4232 audio I/O base 530, 604, E80 or F40' CONFIG_CS4232_BASE 530
int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_IRQ 11
int 'CS4232 audio DMA 0, 1 or 3' CONFIG_CS4232_DMA 0
int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9
fi
-dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI $CONFIG_SOUND
-if [ "$CONFIG_MAUI" = "y" ]; then
+dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND
+if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330
int 'Maui IRQ 5, 9, 12 or 15' CONFIG_MAUI_IRQ 9
bool ' Have OSWF.MOT firmware file' CONFIG_MAUI_HAVE_BOOT
fi
fi
-dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1 $CONFIG_SOUND
-if [ "$CONFIG_OPL3SA1" = "y" ]; then
+dep_tristate 'Support for Aztech Sound Galaxy (non-PnP) cards' CONFIG_SGALAXY $CONFIG_SOUND
+if [ "$CONFIG_SGALAXY" = "y" ]; then
+ hex 'SGALAXY audio I/O base 530, 604, E80 or F40' CONFIG_SGALAXY_BASE 530
+ int 'SGALAXY audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_SGALAXY_IRQ 11
+ int 'SGALAXY audio DMA 0, 1 or 3' CONFIG_SGALAXY_DMA 0
+ int 'SGALAXY second (duplex) DMA 0, 1 or 3' CONFIG_SGALAXY_DMA2 3
+ hex 'SGALAXY SB I/O base 220 or 240' CONFIG_SGALAXY_SGBASE 220
+fi
+
+dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND
+if [ "$CONFIG_SOUND_OPL3SA1" = "y" ]; then
hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA1_BASE 530
int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_OPL3SA1_IRQ 11
int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA 0
int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_OPL3SA1_MPU_IRQ 9
fi
-dep_tristate 'SoftOSS software wave table engine' CONFIG_SOFTOSS $CONFIG_SOUND
-if [ "$CONFIG_SOFTOSS" = "y" ]; then
+dep_tristate 'SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND
+if [ "$CONFIG_SOUND_SOFTOSS" = "y" ]; then
int 'Sampling rate for SoftOSS 8000 to 48000' CONFIG_SOFTOSS_RATE 22050
int 'Max # of concurrent voices for SoftOSS 4 to 32' CONFIG_SOFTOSS_VOICES 32
fi
-dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 $CONFIG_SOUND
-dep_tristate 'Loopback MIDI device support' CONFIG_VMIDI $CONFIG_SOUND
+dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND
-dep_tristate '6850 UART support' CONFIG_UART6850 $CONFIG_SOUND
+dep_tristate 'Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND
+
+dep_tristate '6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND
if [ "$CONFIG_UART6850" = "y" ]; then
hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0
int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1
fi
-
-bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
-
-if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
- dep_tristate 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND
- dep_tristate 'AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND
- dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND
-
- if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
- hex ' I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- fi
-
- if [ "$CONFIG_AEDSP16" = "y" ]; then
- comment 'SC-6600 Audio Cards have no jumper switches at all'
- bool 'SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600
-
- if [ "$CONFIG_SB" = "y" -o "$CONFIG_SB" = "m" -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
- bool 'Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO
- if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then
- comment 'Audio Excel DSP 16 [Sound Blaster Pro]'
- hex 'I/O base for Audio Excel DSP 16 220 or 240' \
- CONFIG_AEDSP16_BASE $CONFIG_SB_BASE
- int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
- CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ
- int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA
- fi
- fi
-
- if [ "$CONFIG_MSS" = "y" -o "$CONFIG_MSS" = "m" -a "$CONFIG_AEDSP16_SBPRO" != "y" ]; then
- bool 'Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
- if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then
- comment 'Audio Excel DSP 16 [Microsoft Sound System]'
- hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
- CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ
- int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA
- fi
- fi
-
- if [ "$CONFIG_MPU401" = "y" -o "$CONFIG_MPU401" = "m" ]; then
- bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
- if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then
- comment 'Audio Excel DSP 16 [MPU-401]'
- if [ "$CONFIG_AEDSP16_SBPRO" != "y" \
- -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
- hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- fi
- int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' \
- CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ
- fi
- fi
- fi
-
- if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
- comment 'SC-6600 Audio Cards have no jumper switches at all'
- bool 'SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600
-
- if [ "$CONFIG_SC6600" = "y" ]; then
- comment 'SC-6600 specific configuration'
- bool 'Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY
- int 'SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' \
- CONFIG_SC6600_CDROM 4
- hex 'SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0
- fi
- fi
+if [ "$CONFIG_ARM" = "y" ]; then
+ bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND
fi
-if [ "$CONFIG_ARM" = "y" ]; then
- bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND
+
+
+# Additional low level drivers.
+
+mainmenu_option next_comment
+comment 'Additional low level sound drivers'
+dep_tristate 'Additional low level sound drivers' CONFIG_LOWLEVEL_SOUND $CONFIG_SOUND
+if [ "$CONFIG_LOWLEVEL_SOUND" != "n" ]; then
+ source drivers/sound/lowlevel/Config.in
fi
+endmenu
+++ /dev/null
-# This used to be a computer generated file, but it's not any more.
-# Edit all you need!
-
-ifdef CONFIG_PSS
-ifneq ($(CONFIG_MPU_EMU),Y)
-CONFIG_MPU_EMU=y
-endif
-endif
-
-ifdef CONFIG_SSCAPE
-ifneq ($(CONFIG_MPU_EMU),Y)
-CONFIG_MPU_EMU=y
-endif
-endif
-
-ifdef CONFIG_CS4232
-ifneq ($(CONFIG_MPU_EMU),Y)
-CONFIG_MPU_EMU=y
-endif
-endif
-
-ifdef CONFIG_MAUI
-ifneq ($(CONFIG_MPU_EMU),Y)
-CONFIG_MPU_EMU=y
-endif
-endif
-
-ifdef CONFIG_PSS
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_GUS16
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_GUSMAX
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_MSS
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_SSCAPE
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_TRIX
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_MAD16
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_CS4232
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_OPL3SA1
-ifneq ($(CONFIG_AD1848),Y)
-CONFIG_AD1848=y
-endif
-endif
-
-ifdef CONFIG_SB
-ifneq ($(CONFIG_SBDSP),Y)
-CONFIG_SBDSP=y
-endif
-endif
-
-ifdef CONFIG_TRIX
-ifneq ($(CONFIG_SBDSP),Y)
-CONFIG_SBDSP=y
-endif
-endif
-
-ifdef CONFIG_MAD16
-ifneq ($(CONFIG_SBDSP),Y)
-CONFIG_SBDSP=y
-endif
-endif
-
-
-
-ifdef CONFIG_SB
- ifeq ($(CONFIG_SB),m)
- ifneq ($(CONFIG_UART401),Y)
- CONFIG_UART401=m
- endif
- else
- ifneq ($(CONFIG_UART401),Y)
- CONFIG_UART401=y
- endif
- endif
-endif
-
-ifdef CONFIG_TRIX
-ifneq ($(CONFIG_UART401),Y)
-CONFIG_UART401=y
-endif
-endif
-
-ifdef CONFIG_MAD16
-ifneq ($(CONFIG_UART401),Y)
-CONFIG_UART401=y
-endif
-endif
-
-ifdef CONFIG_OPL3SA1
-ifneq ($(CONFIG_UART401),Y)
-CONFIG_UART401=y
-endif
-endif
-
-ifdef CONFIG_PAS
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_SB
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_ADLIB
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_GUS
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_MPU401
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_PSS
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_GUS16
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_GUSMAX
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_MSS
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_SSCAPE
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_TRIX
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_MAD16
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_CS4232
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_MAUI
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_OPL3SA1
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_SOFTOSS
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_YM3812_AUTO
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_VIDC_SOUND
-ifneq ($(CONFIG_SEQUENCER),Y)
-CONFIG_SEQUENCER=y
-endif
-endif
-
-ifdef CONFIG_PAS
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_SB
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_GUS
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_PSS
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_GUS16
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_GUSMAX
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_MSS
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_SSCAPE
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_TRIX
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_MAD16
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_CS4232
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_OPL3SA1
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_SOFTOSS
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_VIDC_SOUND
-ifneq ($(CONFIG_AUDIO),Y)
-CONFIG_AUDIO=y
-endif
-endif
-
-ifdef CONFIG_PAS
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_SB
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_GUS
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_MPU401
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_PSS
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_GUS16
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_GUSMAX
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_SSCAPE
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_TRIX
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_MAD16
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_CS4232
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_MAUI
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_OPL3SA1
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-ifdef CONFIG_SOFTOSS
-ifneq ($(CONFIG_MIDI),Y)
-CONFIG_MIDI=y
-endif
-endif
-
-BUILDCODE=s
# Makefile for the Linux sound card driver
#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes. (hopefully)
-#
-#
-#
-#
-ifeq ($(ARCH),m68k)
- L_TARGET := sound.a
- L_OBJS :=
- M_OBJS :=
- ifeq ($(CONFIG_DMASOUND),y)
- L_OBJS += dmasound.o
- else
- ifeq ($(CONFIG_DMASOUND),m)
- M_OBJS += dmasound.o
- endif
- endif
-
- include $(TOPDIR)/Rules.make
-
- clean:
- rm -f core *.o *.a *.s
+# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
+# Rewritten to use lists instead of if-statements.
-else
-include Defines
-ifndef TOPDIR
-TOPDIR=/usr/src/linux
+# My subdirectories.
+
+SUB_DIRS :=
+MOD_SUB_DIRS :=
+MOD_IN_SUB_DIRS :=
+ALL_SUB_DIRS := $(SUB_DIRS) lowlevel
+
+ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
+ SUB_DIRS += lowlevel
+ MOD_IN_SUB_DIRS += lowlevel
endif
-SUB_DIRS := lowlevel
-MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-L_TARGET := sound.a
-M_OBJS :=
-L_OBJS :=
-ifeq ($(CONFIG_SOUND),y)
- L_OBJS += soundcard.o dev_table.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o audio.o dmabuf.o
-else
- ifeq ($(CONFIG_SOUND),m)
- M_OBJS += sound.o
- MIX_OBJS += sound_syms.o
- endif
-endif
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
-ifeq ($(CONFIG_MIDI),y)
- L_OBJS += midibuf.o
- LX_OBJS += midi_synth.o
-endif
+export-objs := ad1848.o mpu401.o opl3.o sb_card.o uart401.o \
+ audio_syms.o midi_syms.o sequencer_syms.o sound_syms.o
-#ifeq ($(CONFIG_AUDIO),y)
-#L_OBJS += dmabuf.o
-#endif
-ifeq ($(CONFIG_YM3812),y)
-LX_OBJS += adlib_card.o opl3.o
-else
- ifeq ($(CONFIG_YM3812),m)
- MX_OBJS += adlib_card.o opl3.o
- endif
-endif
-ifeq ($(CONFIG_PAS),y)
-L_OBJS += pas2.o
-else
- ifeq ($(CONFIG_PAS),m)
- M_OBJS += pas2.o
- endif
-endif
+# Object file lists.
-ifeq ($(CONFIG_GUS),y)
-L_OBJS += gus.o
- ifeq ($(CONFIG_GUSMAX),y)
- CONFIG_MSS = y
- endif
-else
- ifeq ($(CONFIG_GUS),m)
- M_OBJS += gus.o
- endif
- ifeq ($(CONFIG_GUSMAX),y)
- ifneq ($(CONFIG_MSS),y)
- CONFIG_MSS = m
- endif
- endif
-endif
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
-ifeq ($(CONFIG_SB),y)
-L_OBJS += sb_audio.o sb_common.o sb_midi.o sb_mixer.o
-LX_OBJS += sb_card.o
-CONFIG_UART401 = y
-else
- ifeq ($(CONFIG_SB),m)
- M_OBJS += sb.o
- MIX_OBJS += sb_card.o
- ifneq ($(CONFIG_UART401),y)
- CONFIG_UART401 = m
- endif
- endif
-endif
-ifeq ($(CONFIG_MSS),y)
-LX_OBJS += ad1848.o
-else
- ifeq ($(CONFIG_MSS),m)
- MX_OBJS += ad1848.o
- endif
-endif
-ifeq ($(CONFIG_ADLIB),y)
-LX_OBJS += adlib_card.o
-else
- ifeq ($(CONFIG_ADLIB),m)
- MX_OBJS += adlib_card.o
- endif
-endif
+# Each configuration option enables a list of files.
-ifeq ($(CONFIG_MPU401),y)
-LX_OBJS += mpu401.o
-else
- ifeq ($(CONFIG_MPU401),m)
- MX_OBJS += mpu401.o
- else
- ifeq ($(CONFIG_MPU_EMU),y)
- LX_OBJS += mpu401.o
- else
- ifeq ($(CONFIG_MPU_EMU),m)
- MX_OBJS += mpu401.o
- endif
- endif
- endif
-endif
+ifeq ($(ARCH),m68k)
-ifeq ($(CONFIG_UART401),y)
-LX_OBJS += uart401.o
-else
- ifeq ($(CONFIG_UART401),m)
- MX_OBJS += uart401.o
- endif
-endif
+obj-$(CONFIG_DMASOUND) += dmasound.o
-ifeq ($(CONFIG_UART6850),y)
-LX_OBJS += uart6850.o
else
- ifeq ($(CONFIG_UART6850),m)
- MX_OBJS += uart6850.o
- endif
-endif
-ifeq ($(CONFIG_PSS),y)
-L_OBJS += pss.o
-else
- ifeq ($(CONFIG_PSS),m)
- M_OBJS += pss.o
- endif
-endif
+obj-$(CONFIG_SOUND) += sound.o
+obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o
+obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o uart401.o
+obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o
+obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o
+obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
+obj-$(CONFIG_SOUND_MPU401) += mpu401.o
+obj-$(CONFIG_SOUND_MSS) += ad1848.o
+obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
+obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o
+obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
+obj-$(CONFIG_SOUND_SB) += sb.o uart401.o
+obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o
+obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o
+obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
+obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o
+obj-$(CONFIG_SOUND_UART6850) += uart6850.c
+obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
+obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o
+obj-$(CONFIG_VIDC_SOUND) += vidc_mod.o
-ifeq ($(CONFIG_SSCAPE),y)
-L_OBJS += sscape.o
-else
- ifeq ($(CONFIG_SSCAPE),m)
- M_OBJS += sscape.o
- endif
endif
-ifeq ($(CONFIG_TRIX),y)
-L_OBJS += trix.o
-else
- ifeq ($(CONFIG_TRIX),m)
- M_OBJS += trix.o
- endif
-endif
-ifeq ($(CONFIG_MAD16),y)
-L_OBJS += mad16.o
-else
- ifeq ($(CONFIG_MAD16),m)
- M_OBJS += mad16.o sb.o uart401.o
- MX_OBJS += sb_card.o ad1848.o
- endif
-endif
-ifeq ($(CONFIG_CS4232),y)
-LX_OBJS += cs4232.o
-else
- ifeq ($(CONFIG_CS4232),m)
- MX_OBJS += cs4232.o
- endif
-endif
+# Declare multi-part drivers.
-ifeq ($(CONFIG_MAUI),y)
-L_OBJS += maui.o
-else
- ifeq ($(CONFIG_MAUI),m)
- M_OBJS += maui.o
- endif
-endif
+list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o
-ifeq ($(CONFIG_SOFTOSS),y)
-L_OBJS += softoss.o softoss_rs.o
-else
- ifeq ($(CONFIG_SOFTOSS),m)
- M_OBJS += softoss2.o
- endif
-endif
+sound-objs := \
+ dev_table.o soundcard.o sound_firmware.o sound_syms.o \
+ audio.o audio_syms.o dmabuf.o \
+ midi_syms.o midi_synth.o midibuf.o \
+ sequencer.o sequencer_syms.o sound_timer.o sys_timer.o
-ifeq ($(CONFIG_OPL3SA1),y)
-L_OBJS += opl3sa.o
-LX_OBJS += ad1848.o
-else
- ifeq ($(CONFIG_OPL3SA1),m)
- M_OBJS += opl3sa.o
- MX_OBJS += ad1848.o
- endif
-endif
+gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
+pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
+sb-objs := sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o
+softoss2-objs := softoss.o softoss_rs.o
+vidc_mod-objs := vidc.o vidc_audio.o vidc_fill.o vidc_mixer.o vidc_synth.o
-ifeq ($(CONFIG_VMIDI),y)
-L_OBJS += v_midi.o
-else
- ifeq ($(CONFIG_VMIDI),m)
- M_OBJS += v_midi.o
- endif
-endif
-ifeq ($(CONFIG_VIDC_SOUND),y)
- L_OBJS += vidc.o vidc_audio.o vidc_mixer.o vidc_synth.o vidc_fill.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y := $(filter $(list-multi), $(obj-y))
+multi-m := $(filter $(list-multi), $(obj-m))
+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+int-m := $(filter-out $(int-y), $(int-m))
+
+
+
+# Set flags for secondary drivers.
+# I have to do this before I reduce obj-y to components.
+
+EXTRA_CFLAGS := $(sort \
+ $(patsubst ad1848.o, -DCONFIG_SOUND_AD1848, \
+ $(patsubst mpu401.o, -DCONFIG_SOUND_MPU_EMU, \
+ $(patsubst sb.o, -DCONFIG_SOUND_SBDSP, \
+ $(patsubst uart401.o, -DCONFIG_SOUND_UART401, \
+ $(filter ad1848.o mpu401.o sb.o uart401.o, $(obj-y)) \
+ )))))
+
+
+
+# Take multi-part drivers out of obj-y and put components in.
+
+obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+
+
+# Translate to Rules.make lists.
+
+L_TARGET := sound.a
+MOD_LIST_NAME := SOUND_MODULES
+
+L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
+LX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
+
+ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
+ L_OBJS += lowlevel/lowlevel.o
endif
include $(TOPDIR)/Rules.make
-softoss2.o: softoss.o softoss_rs.o
- $(LD) -r -o softoss2.o softoss.o softoss_rs.o
-pas2.o: pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
- $(LD) -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
-sb.o: sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o
- $(LD) -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o
+# Link rules for multi-part drivers.
+
+sound.o: $(sound-objs)
+ $(LD) -r -o $@ $(sound-objs)
+
+gus.o: $(gus-objs)
+ $(LD) -r -o $@ $(gus-objs)
+
+pas2.o: $(pas2-objs)
+ $(LD) -r -o $@ $(pas2-objs)
-lowlevel/lowlevel.o:
- cd lowlevel; make
+sb.o: $(sb-objs)
+ $(LD) -r -o $@ $(sb-objs)
+
+softoss2.o: $(softoss2-objs)
+ $(LD) -r -o $@ $(softoss2-objs)
+
+vidc_mod.o: $(vidc_mod-objs)
+ $(LD) -r -o $@ $(vidc_mod-objs)
-sound.o: soundcard.o dev_table.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o sound_syms.o
- $(LD) -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \
- sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \
- midi_synth.o midibuf.o sound_firmware.o sound_syms.o
-gus.o: gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
- $(LD) -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
# Firmware files that need translation
#
# The translated files are protected by a file that keeps track
# of what name was used to build them. If the name changes, they
# will be forced to be remade.
+#
+# First make the utilities.
bin2hex: bin2hex.c
$(HOSTCC) -o bin2hex bin2hex.c
hex2hex: hex2hex.c
$(HOSTCC) -o hex2hex hex2hex.c
-ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
-CONFIG_MAUI_BOOT_FILE := $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE))
+
+
+# Turtle Beach Maui / Tropez
maui.o: maui_boot.h
-maui_boot.h: $(CONFIG_MAUI_BOOT_FILE) bin2hex
- bin2hex -i maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@
+ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
+ maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) bin2hex
+ bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@
+else
+ maui_boot.h:
+ ( \
+ echo 'static unsigned char * maui_os = NULL;'; \
+ echo 'static int maui_osLen = 0;'; \
+ ) > $@
+endif
@ ( \
- echo 'ifeq ($(strip $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_BOOT_FILE)))'; \
+ echo 'ifeq ($(strip $(CONFIG_MAUI_HAVE_BOOT) $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_HAVE_BOOT) $$(CONFIG_MAUI_BOOT_FILE)))'; \
echo 'FILES_BOOT_UP_TO_DATE += $@'; \
echo 'endif' \
) > .$@.boot
-endif
-ifeq ($(CONFIG_PSS_HAVE_BOOT),y)
-CONFIG_PSS_BOOT_FILE := $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE))
+# PSS (ECHO-ADI2111)
pss.o: pss_boot.h
-pss_boot.h: $(CONFIG_PSS_BOOT_FILE) bin2hex
- bin2hex pss_synth < "$(CONFIG_PSS_BOOT_FILE)" > $@
+ifeq ($(CONFIG_PSS_HAVE_BOOT),y)
+ pss_boot.h: $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE)) bin2hex
+ bin2hex pss_synth < $(CONFIG_PSS_BOOT_FILE) > $@
+else
+ pss_boot.h:
+ ( \
+ echo 'static unsigned char * pss_synth = NULL;'; \
+ echo 'static int pss_synthLen = 0;'; \
+ ) > $@
+endif
@ ( \
- echo 'ifeq ($(strip $(CONFIG_PSS_BOOT_FILE)),$$(strip $$(CONFIG_PSS_BOOT_FILE)))'; \
+ echo 'ifeq ($(strip $(CONFIG_PSS_HAVE_BOOT) $(CONFIG_PSS_BOOT_FILE)),$$(strip $$(CONFIG_PSS_HAVE_BOOT) $$(CONFIG_PSS_BOOT_FILE)))'; \
echo 'FILES_BOOT_UP_TO_DATE += $@'; \
echo 'endif' \
) > .$@.boot
-endif
-ifeq ($(CONFIG_TRIX_HAVE_BOOT),y)
-CONFIG_TRIX_BOOT_FILE := $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE))
+# MediaTrix AudioTrix Pro
trix.o: trix_boot.h
-trix_boot.h: $(CONFIG_TRIX_BOOT_FILE) hex2hex
- hex2hex -i trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@
+ifeq ($(CONFIG_TRIX_HAVE_BOOT),y)
+ trix_boot.h: $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) hex2hex
+ hex2hex -i trix_boot < $(CONFIG_TRIX_BOOT_FILE) > $@
+else
+ trix_boot.h:
+ ( \
+ echo 'static unsigned char * trix_boot = NULL;'; \
+ echo 'static int trix_boot_len = 0;'; \
+ ) > $@
+endif
@ ( \
- echo 'ifeq ($(strip $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_BOOT_FILE)))'; \
+ echo 'ifeq ($(strip $(CONFIG_TRIX_HAVE_BOOT) $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_HAVE_BOOT) $$(CONFIG_TRIX_BOOT_FILE)))'; \
echo 'FILES_BOOT_UP_TO_DATE += $@'; \
echo 'endif' \
) > .$@.boot
-endif
+
# Find boot files whose source file names have changed and force rebuild.
ifneq ($(FILES_BOOT_CHANGED),)
$(FILES_BOOT_CHANGED): dummy
endif
-endif
--- /dev/null
+Sound Driver Configuration Notes
+Michael Chastain, <mailto:mec@shout.net>
+18 Apr 1998
+
+The Linux sound driver is derived from OSS/Free, a multi-platform
+Unix sound driver by Hannu Savolainen. You can find out
+more about OSS/Free and the commercial version, OSS/Linux, at
+<http://www.opensound.com/ossfree>.
+
+OSS/Free comes with the configuration program 'configure.c'. We have
+discarded that program in favor of a standard Linux configuration file
+Config.in.
+
+Config.in defines a set of symbols with the form CONFIG_SOUND_*.
+These are the -native symbols-. Here is a description:
+
+ CONFIG_SOUND
+
+ This is the master symbol. It controls whether the basic
+ sound-driver code is resident, modular, or not present at all.
+
+ If the basic driver is resident, each primary and secondary
+ driver can be resident, modular, or not present.
+
+ If the basic driver is modular, each primary and secondary driver
+ can be modular or not present.
+
+ And if the basic driver is not present, all other drivers are
+ not present, too.
+
+ Primary drivers
+
+ These are symbols such as CONFIG_SOUND_SB, CONFIG_SOUND_SB_MODULE,
+ CONFIG_SOUND_TRIX, or CONFIG_SOUND_TRIX_MODULE. Each driver
+ that the user can directly select is a primary driver and has
+ the usual pair of symbols: one resident and one modular.
+
+ Each primary driver can be either resident or modular.
+
+ Secondary drivers
+
+ Primary drivers require the support of secondary drivers, such
+ as ad1848.o and uart401.o.
+
+ In Makefile, each primary driver has a list of required secondary
+ drivers. The secondary driver requirements are merged and a
+ single definition is emitted at the end.
+
+ For each secondary driver: if any resident primary driver
+ requires it, that secondary driver will be resident. If no
+ resident primary driver requires it but some modular primary
+ driver requires it, then that secondary driver will be modular.
+ Otherwise that secondary driver will be not present.
+
+ OSS/Free also contains tests for secondary drivers. The Makefile
+ defines symbols for these drivers in EXTRA_CFLAGS.
+
+ CONFIG_AUDIO, CONFIG_MIDI, CONFIG_SEQUENCER
+
+ These three drivers are like secondary drivers, but not quite.
+ They can not yet be separated into modules. They are always
+ linked into the basic sound driver, whether they are needed
+ or not. (This is in case a primary driver is added to the
+ system later, as a module, and needs these facilities. If it
+ were possible to modularise them, then they would get built as
+ additional modules at that time).
+
+The OSS/Free code does not use the native symbols directly, primarily
+because it does not know about modules. I could edit the code, but that
+would make it harder to upgrade to new versions of OSS/Free. Instead,
+the OSS/Free code continues to use -legacy symbols-.
+
+legacy.h defines all the legacy symbols to 1. This is because, whenever
+OSS/Free tests a symbol, the Makefile has already arranged for that
+driver to be included.
-1, -1, -1, -1, -1, -1, -1, -1, -1
};
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
+#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) || defined(MODULE)
static int timer_installed = -1;
static void ad1848_halt_output(int dev);
static void ad1848_trigger(int dev, int bits);
-#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE)
+#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
static int ad1848_tmr_install(int dev);
static void ad1848_tmr_reprogram(int dev);
restore_flags(flags);
devc->xfer_count = 0;
-#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE)
+#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
if (dev == timer_installed && devc->timer_running)
if ((fs & 0x01) != (old_fs & 0x01))
{
}
audio_devs[my_dev]->portc = portc;
+ audio_devs[my_dev]->mixer_dev = -1;
memset((char *) portc, 0, sizeof(*portc));
nr_ad1848_devs++;
} else if (irq < 0)
irq2dev[-irq] = devc->dev_no = my_dev;
-#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE)
+#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
if (devc->model != MD_1848 &&
devc->model != MD_C930 && devc->irq_ok)
ad1848_tmr_install(my_dev);
if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */
{
devc->timer_ticks++;
-#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE)
+#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
if (timer_installed == dev && devc->timer_running)
sound_timer_interrupt();
#endif
release_region(hw_config->io_base, 4);
}
-#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE)
+#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
/*
* Timer stuff (for /dev/music).
if(loaded)
unload_ms_sound(&hw_config);
}
+
#endif
#endif
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_YM3812) || defined(MODULE)
+#ifdef CONFIG_YM3812
void attach_adlib_card(struct address_info *hw_config)
{
#include "sound_config.h"
-#if defined(CONFIG_AUDIO) || defined(MODULE)
+#ifdef CONFIG_AUDIO
#include "ulaw.h"
#include "coproc.h"
--- /dev/null
+/*
+ * Exported symbols for audio driver.
+ * __NO_VERSION__ because this is still part of sound.o.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+char audio_syms_symbol;
+
+#include "sound_config.h"
+#include "sound_calls.h"
+
+EXPORT_SYMBOL(DMAbuf_start_dma);
+EXPORT_SYMBOL(DMAbuf_open_dma);
+EXPORT_SYMBOL(DMAbuf_close_dma);
+EXPORT_SYMBOL(DMAbuf_inputintr);
+EXPORT_SYMBOL(DMAbuf_outputintr);
+EXPORT_SYMBOL(dma_ioctl);
+EXPORT_SYMBOL(audio_open);
+EXPORT_SYMBOL(audio_release);
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_CS4232) || defined (MODULE)
+#ifdef CONFIG_CS4232
#define KEY_PORT 0x279 /* Same as LPT1 status port */
#define CSN_NUM 0x99 /* Just a random number */
{
int base = hw_config->io_base, irq = hw_config->irq;
int dma1 = hw_config->dma, dma2 = hw_config->dma2;
- int old_num_mixers = num_mixers;
if (dma2 == -1)
dma2 = dma1;
0,
hw_config->osp);
- if (num_mixers > old_num_mixers)
+ if (hw_config->slots[0] != -1 &&
+ audio_devs[hw_config->slots[0]]->mixer_dev!=-1)
{
/* Assume the mixer map is as suggested in the CS4232 databook */
AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
struct driver_info sound_drivers[] =
{
-#if defined(CONFIG_PSS) && !defined(CONFIG_PSS_MODULE)
+#ifdef CONFIG_SOUND_PSS
{"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss},
{"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu},
{"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss},
#endif
-#if defined(CONFIG_GUS) && !defined(CONFIG_GUS_MODULE)
+#ifdef CONFIG_SOUND_GUS
#ifdef CONFIG_GUS16
{"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16},
#endif
#endif
#endif
-#if defined(CONFIG_MSS) && !defined(CONFIG_MSS_MODULE)
+#ifdef CONFIG_SOUND_MSS
{"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound},
/* Compaq Deskpro XL */
{"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound},
#endif
-#ifdef CONFIG_MAD16
+
+#ifdef CONFIG_SOUND_MAD16
{"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16},
{"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)", attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu},
#endif
-#ifdef CONFIG_CS4232
+
+#ifdef CONFIG_SOUND_CS4232
{"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232},
{"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu},
#endif
-#if defined(CONFIG_YM3812) && !defined(CONFIG_YM3812_MODULE)
+
+#ifdef CONFIG_SGALAXY
+ {"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy},
+#endif
+
+#ifdef CONFIG_SOUND_YM3812
{"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib},
#endif
-#if defined(CONFIG_PAS) && !defined(CONFIG_PAS_MODULE)
+
+#ifdef CONFIG_SOUND_PAS
{"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas},
#endif
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) && !defined(CONFIG_MPU401_MODULE)
+
+#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) && defined(CONFIG_MIDI)
{"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401},
#endif
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) && !defined(CONFIG_UART401_MODULE)
+
+#if defined(CONFIG_SOUND_UART401) && defined(CONFIG_MIDI)
{"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)",
attach_uart401, probe_uart401, unload_uart401},
#endif
-#if defined(CONFIG_MAUI) && !defined(CONFIG_MAUI_MODULE)
+
+#if defined(CONFIG_SOUND_MAUI)
{"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui},
#endif
-#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) && !defined(CONFIG_UART6850_MODULE)
+
+#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI)
{"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850},
#endif
-#if defined(CONFIG_SBDSP) && !defined(CONFIG_SBDSP_MODULE)
+#ifdef CONFIG_SOUND_SBDSP
{"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb},
{"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb},
#endif
#endif
-#ifdef CONFIG_SSCAPE
+#ifdef CONFIG_SOUND_SSCAPE
{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape},
{"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound},
#endif
-#ifdef CONFIG_OPL3SA1
+#ifdef CONFIG_SOUND_OPL3SA1
{"OPL3SA", 0, SNDCARD_OPL3SA1, "Yamaha OPL3-SA", attach_opl3sa_wss, probe_opl3sa_wss, unload_opl3sa_wss},
/* {"OPL3SASB", 0, SNDCARD_OPL3SA1_SB, "OPL3-SA (SB mode)", attach_opl3sa_sb, probe_opl3sa_sb, unload_opl3sa_sb}, */
{"OPL3SAMPU", 0, SNDCARD_OPL3SA1_MPU, "OPL3-SA MIDI", attach_opl3sa_mpu, probe_opl3sa_mpu, unload_opl3sa_mpu},
#endif
-#if defined (CONFIG_TRIX) && !defined(CONFIG_TRIX_MODULE)
+#ifdef CONFIG_SOUND_TRIX
{"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss},
{"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb},
{"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu},
#endif
-#if defined(CONFIG_SOFTOSS) && !defined(CONFIG_SOFTOSS_MODULE)
+#ifdef CONFIG_SOUND_SOFTOSS
{"SOFTSYN", 0, SNDCARD_SOFTOSS, "SoftOSS Virtual Wave Table",
attach_softsyn_card, probe_softsyn, unload_softsyn},
#endif
-#if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) && !defined(CONFIG_VMIDI_MODULE)
+#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI)
{"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi},
#endif
#ifdef CONFIG_VIDC_SOUND
struct card_info snd_installed_cards[] =
{
-#ifdef CONFIG_PSS
+#ifdef CONFIG_SOUND_PSS
{SNDCARD_PSS, {CONFIG_PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE},
#ifdef CONFIG_PSS_MPU_BASE
{SNDCARD_PSS_MPU, {CONFIG_PSS_MPU_BASE, CONFIG_PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
{SNDCARD_PSS_MSS, {CONFIG_PSS_MSS_BASE, CONFIG_PSS_MSS_IRQ, CONFIG_PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
#endif
-#ifdef CONFIG_TRIX
+
+#ifdef CONFIG_SOUND_TRIX
#ifndef CONFIG_TRIX_DMA2
#define CONFIG_TRIX_DMA2 CONFIG_TRIX_DMA
#endif
#endif
#endif
-#ifdef CONFIG_OPL3SA1
+#ifdef CONFIG_SOUND_OPL3SA1
{SNDCARD_OPL3SA1, {CONFIG_OPL3SA1_BASE, CONFIG_OPL3SA1_IRQ, CONFIG_OPL3SA1_DMA, CONFIG_OPL3SA1_DMA2}, SND_DEFAULT_ENABLE},
#ifdef CONFIG_OPL3SA1_MPU_BASE
{SNDCARD_OPL3SA1_MPU, {CONFIG_OPL3SA1_MPU_BASE, CONFIG_OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
#endif
-#ifdef CONFIG_SOFTOSS
+#ifdef CONFIG_SOUND_SOFTOSS
{SNDCARD_SOFTOSS, {0, 0, -1, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifdef CONFIG_SSCAPE
+#ifdef CONFIG_SOUND_SSCAPE
{SNDCARD_SSCAPE, {CONFIG_SSCAPE_BASE, CONFIG_SSCAPE_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
{SNDCARD_SSCAPE_MSS, {CONFIG_SSCAPE_MSS_BASE, CONFIG_SSCAPE_MSS_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifdef CONFIG_MAD16
+
+#ifdef CONFIG_SOUND_MAD16
#ifndef CONFIG_MAD16_DMA2
#define CONFIG_MAD16_DMA2 CONFIG_MAD16_DMA
#endif
#endif
#endif
-#ifdef CONFIG_CS4232
+#ifdef CONFIG_SOUND_CS4232
#ifndef CONFIG_CS4232_DMA2
#define CONFIG_CS4232_DMA2 CONFIG_CS4232_DMA
#endif
{SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE},
#endif
+#ifdef CONFIG_SGALAXY
+#ifndef CONFIG_SGALAXY_DMA2
+#define CONFIG_SGALAXY_DMA2 CONFIG_SGALAXY_DMA
+#endif
+ {SNDCARD_SGALAXY, {CONFIG_SGALAXY_BASE, CONFIG_SGALAXY_IRQ, CONFIG_SGALAXY_DMA, CONFIG_SGALAXY_DMA2, 0, NULL, CONFIG_SGALAXY_SGBASE}, SND_DEFAULT_ENABLE},
+#endif
+
-#ifdef CONFIG_MSS
+#ifdef CONFIG_SOUND_MSS
#ifndef CONFIG_MSS_DMA2
#define CONFIG_MSS_DMA2 -1
#endif
#else
{SNDCARD_MSS, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE},
#endif
+
#ifdef MSS2_BASE
{SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, MSS2_DMA2}, SND_DEFAULT_ENABLE},
#endif
#endif
-
-#ifdef CONFIG_PAS
+#ifdef CONFIG_SOUND_PAS
{SNDCARD_PAS, {CONFIG_PAS_BASE, CONFIG_PAS_IRQ, CONFIG_PAS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifdef CONFIG_SB
+#ifdef CONFIG_SOUND_SB
#ifndef CONFIG_SB_DMA
#define CONFIG_SB_DMA 1
#endif
{SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE},
#endif
#endif
-#if defined(CONFIG_MAUI)
+
+#ifdef CONFIG_SOUND_MAUI
{SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
+#if defined(CONFIG_SOUND_MPU401) && defined(CONFIG_MIDI)
{SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#ifdef MPU2_BASE
{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
#endif
-#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
+#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI)
{SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#if defined(CONFIG_SB)
+#ifdef CONFIG_SOUND_SB
#if defined(CONFIG_MIDI) && defined(CONFIG_SB_MPU_BASE)
{SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
#endif
-#ifdef CONFIG_GUS
+#ifdef CONFIG_SOUND_GUS
#ifndef CONFIG_GUS_DMA2
#define CONFIG_GUS_DMA2 CONFIG_GUS_DMA
#endif
{SNDCARD_GUS, {CONFIG_GUS_BASE, CONFIG_GUS_IRQ, CONFIG_GUS_DMA, CONFIG_GUS_DMA2}, SND_DEFAULT_ENABLE},
#endif
-#if defined(CONFIG_YM3812)
+#ifdef CONFIG_SOUND_YM3812
{SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI)
+#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI)
{SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
* NOTE! This routine could be called several times.
*/
+ /* drag in audio_syms.o */
+ {
+ extern char audio_syms_symbol;
+ audio_syms_symbol = 0;
+ }
+
if (adev && adev->dmap_out == NULL) {
if (adev->d == NULL)
panic("OSS: audio_devs[%d]->d == NULL\n", dev);
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_GUS) || defined(MODULE)
+#ifdef CONFIG_GUS
#include "gus_hw.h"
if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
if (sound_alloc_dma(hw_config->dma2, "GUS(2)"))
printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2);
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
gus_midi_init(hw_config);
#endif
}
}
if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
{
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
gus_midi_interrupt(0);
#endif
}
if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
{
-#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE)
+#ifdef CONFIG_SEQUENCER
if (gus_timer_enabled)
sound_timer_interrupt();
gus_write8(0x45, 0); /* Ack IRQ */
void attach_gus_db16(struct address_info *hw_config)
{
-#if defined(CONFIG_GUS) || defined(MODULE)
+#ifdef CONFIG_GUS
gus_pcm_volume = 100;
gus_wave_volume = 90;
#endif
#include "gus_hw.h"
-#if ( defined(CONFIG_GUS) && defined(CONFIG_MIDI) ) || defined (MODULE)
+#ifdef CONFIG_GUS
+#ifdef CONFIG_MIDI
static int midi_busy = 0, input_opened = 0;
static int my_dev;
}
#endif
+#endif
#include <linux/config.h>
#include "sound_config.h"
-#if defined(CONFIG_GUS) || defined(MODULE)
+#ifdef CONFIG_GUS
#include "gus_linearvol.h"
#define GUS_VOLUME gus_wave_volume
#include <linux/ultrasound.h>
#include "gus_hw.h"
-#if defined(CONFIG_GUS) || defined(MODULE)
+#ifdef CONFIG_GUS
#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
hw_config->slots[0] = sdev;
synth_devs[sdev] = &guswave_operations;
sequencer_init();
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
gus_tmr_install(gus_base + 8);
#endif
}
}
}
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
/*
* Timer stuff
fprintf(stderr,"hex2hex: [-i] filename\n");
exit(1);
}
- varline = argv[1\1d;
+ varline = argv[1];
l = loadhex(stdin, buf);
printf("/*\n *\t Computer generated file. Do not edit.\n */\n");
#include "sound_config.h"
-#if defined(CONFIG_GUS) || defined(MODULE)
+#ifdef CONFIG_GUS
#include <linux/ultrasound.h>
#include "gus_hw.h"
--- /dev/null
+#ifndef _SOUND_LEGACY_H_
+#define _SOUND_LEGACY_H_
+
+/*
+ * Force on additional support
+ */
+
+#define __SGNXPRO__
+#define DESKPROXL
+/* #define SM_GAMES */
+#define SM_WAVE
+
+/*
+ * Define legacy options.
+ */
+
+#define SELECTED_SOUND_OPTIONS 0x0
+
+#define HAVE_MAUI_BOOT
+#define PSS_HAVE_LD
+#define INCLUDE_TRIX_BOOT
+
+#define CONFIG_CS4232
+#define CONFIG_GUS
+#define CONFIG_MAD16
+#define CONFIG_MAUI
+#define CONFIG_MPU401
+#define CONFIG_MSS
+#define CONFIG_OPL3SA1
+#define CONFIG_PAS
+#define CONFIG_PSS
+#define CONFIG_SB
+#define CONFIG_SOFTOSS
+#define CONFIG_SSCAPE
+#define CONFIG_TRIX
+#define CONFIG_VMIDI
+#define CONFIG_YM3812
+
+#define CONFIG_AUDIO
+#define CONFIG_MIDI
+#define CONFIG_SEQUENCER
+
+#define CONFIG_AD1848
+#define CONFIG_MPU_EMU
+#define CONFIG_SBDSP
+#define CONFIG_UART401
+
+#endif /* _SOUND_LEGACY_H */
+++ /dev/null
-/* Computer generated file. Please don't edit! */
-
-#include <linux/config.h>
-
-#define KERNEL_COMPATIBLE_CONFIG
-
-#define SELECTED_SOUND_OPTIONS 0x00000000
-
-#if \
- defined(CONFIG_PSS) || defined(CONFIG_SSCAPE) || \
- defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \
- defined(CONFIG_PSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \
- defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE)
-# define CONFIG_MPU_EMU
-#endif
-
-#if \
- defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \
- defined(CONFIG_GUSMAX) || defined(CONFIG_MSS) || \
- defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \
- defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \
- defined(CONFIG_OPL3SA1) || \
- defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \
- defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_MSS_MODULE) || \
- defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \
- defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \
- defined(CONFIG_OPL3SA1_MODULE)
-# define CONFIG_AD1848
-#endif
-
-#if \
- defined(CONFIG_PAS) || defined(CONFIG_SB) || \
- defined(CONFIG_GUS) || defined(CONFIG_PSS) || \
- defined(CONFIG_GUS16) || defined(CONFIG_GUSMAX) || \
- defined(CONFIG_MSS) || defined(CONFIG_SSCAPE) || \
- defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \
- defined(CONFIG_CS4232) || defined(CONFIG_OPL3SA1) || \
- defined(CONFIG_SOFTOSS) || \
- defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \
- defined(CONFIG_GUS_MODULE) || defined(CONFIG_PSS_MODULE) || \
- defined(CONFIG_GUS16_MODULE) || defined(CONFIG_GUSMAX_MODULE) || \
- defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \
- defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \
- defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \
- defined(CONFIG_SOFTOSS_MODULE) || defined(CONFIG_VIDC_SOUND)
-# define CONFIG_AUDIO
-#endif
-
-#if \
- defined(CONFIG_PAS) || defined(CONFIG_SB) || \
- defined(CONFIG_GUS) || defined(CONFIG_MPU401) || \
- defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \
- defined(CONFIG_GUSMAX) || defined(CONFIG_SSCAPE) || \
- defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \
- defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \
- defined(CONFIG_OPL3SA1) || defined(CONFIG_SOFTOSS) || \
- defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \
- defined(CONFIG_GUS_MODULE) || defined(CONFIG_MPU401_MODULE) || \
- defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \
- defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \
- defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \
- defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) || \
- defined(CONFIG_OPL3SA1_MODULE) || defined(CONFIG_SOFTOSS_MODULE)
-# define CONFIG_MIDI
-#endif
-
-#if \
- defined(CONFIG_SB) || defined(CONFIG_TRIX) || \
- defined(CONFIG_MAD16) || \
- defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \
- defined(CONFIG_MAD16_MODULE)
-# define CONFIG_SBDSP
-#endif
-#if \
- defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \
- defined(CONFIG_MAD16_MODULE)
-# define CONFIG_SBDSP_MODULE
-#endif
-
-#if \
- defined(CONFIG_SB) || defined(CONFIG_TRIX) || \
- defined(CONFIG_MAD16) || defined(CONFIG_SB_MODULE) || \
- defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE)
-# define CONFIG_UART401
-#endif
-
-#if \
- defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \
- defined(CONFIG_MAD16_MODULE)
-#ifndef CONFIG_UART401_MODULE
-#define CONFIG_UART401_MODULE
-#endif
-#endif
-
-#if \
- defined(CONFIG_PAS) || defined(CONFIG_SB) || \
- defined(CONFIG_ADLIB) || defined(CONFIG_GUS) || \
- defined(CONFIG_MPU401) || defined(CONFIG_PSS) || \
- defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \
- defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \
- defined(CONFIG_MAUI) || defined(CONFIG_OPL3SA1) || \
- defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \
- defined(CONFIG_ADLIB_MODULE) || defined(CONFIG_GUS_MODULE) || \
- defined(CONFIG_MPU401_MODULE) || defined(CONFIG_PSS_MODULE) || \
- defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \
- defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \
- defined(CONFIG_MAUI_MODULE) || defined(CONFIG_OPL3SA1_MODULE)
-# define CONFIG_SEQUENCER
-#endif
-
-/*
- * Force on additional support
- */
-
-#define SM_WAVE
-#define __SGNXPRO__
-/* #define SM_GAMES */
-#define DESKPROXL
+++ /dev/null
-bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
-
-if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
- bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER
- bool 'AWE32 synth' CONFIG_AWE32_SYNTH
- bool 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16
-
- if [ "$CONFIG_AEDSP16" = "y" ]; then
- comment 'SC-6600 Audio Cards have no jumper switches at all'
- bool 'SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600
-
- if [ "$CONFIG_SB" = "y" -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
- bool 'Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO
- if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then
- comment 'Audio Excel DSP 16 [Sound Blaster Pro]'
- hex 'I/O base for Audio Excel DSP 16 220 or 240' \
- CONFIG_AEDSP16_BASE $CONFIG_SB_BASE
- int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
- CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ
- int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA
- fi
- fi
-
- if [ "$CONFIG_MSS" = "y" -a "$CONFIG_AEDSP16_SBPRO" != "y" ]; then
- bool 'Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
- if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then
- comment 'Audio Excel DSP 16 [Microsoft Sound System]'
- hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
- CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ
- int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA
- fi
- fi
-
- if [ "$CONFIG_MPU401" = "y" ]; then
- bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
- if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then
- comment 'Audio Excel DSP 16 [MPU-401]'
- if [ "$CONFIG_AEDSP16_SBPRO" != "y" \
- -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
- hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- fi
- int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' \
- CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ
- fi
- fi
-
- if [ "$CONFIG_SC6600" = "y" ]; then
- comment 'SC-6600 specific configuration'
- bool 'Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY
- int 'SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' \
- CONFIG_SC6600_CDROM 4
- hex 'SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0
- fi
-
- fi
-fi
#include "lowlevel.h"
#include <linux/config.h>
+#include <linux/module.h>
#include "../soundvers.h"
-#ifdef CONFIG_LOWLEVEL_SOUND
-
#ifdef LOWLEVEL_MODULE
char *lowlevel_version = SOUND_VERSION_STRING;
#endif
#endif
}
-#endif
+
+EXPORT_SYMBOL(sound_init_lowlevel_drivers);
+EXPORT_SYMBOL(sound_unload_lowlevel_drivers);
#endif
-#if defined(CONFIG_MAD16) || defined(MODULE)
+#ifdef CONFIG_MAD16
#include "sb.h"
mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */
#ifdef MAD16_CDSEL
if(MAD16_CDSEL & 0x20)
- mad_write(MC4_PORT, 0x66); /* opl4 */
+ mad_write(MC4_PORT, 0x62); /* opl4 */
else
- mad_write(MC4_PORT, 0x56); /* opl3 */
+ mad_write(MC4_PORT, 0x52); /* opl3 */
#else
- mad_write(MC4_PORT, 0x56);
+ mad_write(MC4_PORT, 0x52);
#endif
mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */
mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */
#include "soundmodule.h"
#include "sound_firmware.h"
-#if defined(CONFIG_MAUI) || defined(MODULE)
+#ifdef CONFIG_MAUI
static int maui_base = 0x330;
static int (*orig_load_patch) (int dev, int format, const char *addr,
int offs, int count, int pmgr_flag) = NULL;
-#ifdef CONFIG_MAUI_HAVE_BOOT
+#ifdef HAVE_MAUI_BOOT
#include "maui_boot.h"
#else
static unsigned char *maui_os = NULL;
--- /dev/null
+/*
+ * Exported symbols for midi driver.
+ * __NO_VERSION__ because this is still part of sound.o.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+char midi_syms_symbol;
+
+#include "sound_config.h"
+#define _MIDI_SYNTH_C_
+#include "midi_synth.h"
+
+EXPORT_SYMBOL(do_midi_msg);
+EXPORT_SYMBOL(midi_synth_open);
+EXPORT_SYMBOL(midi_synth_close);
+EXPORT_SYMBOL(midi_synth_ioctl);
+EXPORT_SYMBOL(midi_synth_kill_note);
+EXPORT_SYMBOL(midi_synth_start_note);
+EXPORT_SYMBOL(midi_synth_set_instr);
+EXPORT_SYMBOL(midi_synth_reset);
+EXPORT_SYMBOL(midi_synth_hw_control);
+EXPORT_SYMBOL(midi_synth_aftertouch);
+EXPORT_SYMBOL(midi_synth_controller);
+EXPORT_SYMBOL(midi_synth_panning);
+EXPORT_SYMBOL(midi_synth_setup_voice);
+EXPORT_SYMBOL(midi_synth_send_sysex);
+EXPORT_SYMBOL(midi_synth_bender);
+EXPORT_SYMBOL(midi_synth_load_patch);
+EXPORT_SYMBOL(MIDIbuf_avail);
#include "sound_config.h"
-#if defined(CONFIG_MIDI) || defined (MODULE)
+#ifdef CONFIG_MIDI
#define _MIDI_SYNTH_C_
{0};
static unsigned char prev_out_status[MAX_MIDI_DEV];
-#if !defined(CONFIG_SEQUENCER) && !defined(MODULE)
+#ifndef CONFIG_SEQUENCER
#define STORE(cmd)
#else
#define STORE(cmd) \
void MIDIbuf_init(void)
{
+ /* drag in midi_syms.o */
+ {
+ extern char midi_syms_symbol;
+ midi_syms_symbol = 0;
+ }
}
int MIDIbuf_avail(int dev)
#include "sound_config.h"
#include "soundmodule.h"
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) || defined(MODULE)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
#include "coproc.h"
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
#endif
0 /* Fx */
};
-#if !defined(CONFIG_SEQUENCER) && !defined(MODULE)
+#ifndef CONFIG_SEQUENCER
#define STORE(cmd)
#else
#define STORE(cmd) \
* Timer stuff
****************************************************/
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#if defined(CONFIG_SEQUENCER)
static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0;
static volatile int curr_tempo, curr_timebase, hw_timebase;
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_YM3812) || defined(MODULE)
+#ifdef CONFIG_YM3812
#include "opl3.h"
SOUND_LOCK_END;
}
-#else
-
-#endif
#endif
EXPORT_SYMBOL(opl3_init);
EXPORT_SYMBOL(opl3_detect);
MODULE_PARM(io, "i");
+
+#endif
/*
- * sound/Xopl3sa.c
+ * sound/opl3sa.c
*
* Low level driver for Yamaha YMF701B aka OPL3-SA chip
*
*/
#include <linux/config.h>
+#include <linux/module.h>
#undef SB_OK
#include "sound_config.h"
+#include "soundmodule.h"
#ifdef SB_OK
#include "sb.h"
static int sb_initialized = 0;
struct address_info cfg;
struct address_info mpu_cfg;
+static int found_mpu;
int init_module(void)
{
if (probe_opl3sa_wss(&cfg) == 0)
return -ENODEV;
- found_mpu=probe_opl3_mpu(&mpu_cfg);
+ found_mpu=probe_opl3sa_mpu(&mpu_cfg);
attach_opl3sa_wss(&cfg);
if(found_mpu)
{
if(found_mpu)
unload_opl3sa_mpu(&mpu_cfg);
- unload_opl3sa(&cfg);
+ unload_opl3sa_wss(&cfg);
SOUND_LOCK_END;
}
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_PAS) || defined(MODULE)
+#ifdef CONFIG_PAS
static unsigned char dma_bits[] = {
4, 1, 2, 3, 0, 5, 6, 7
}
if (status & 0x10)
{
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
pas_midi_interrupt();
#endif
status &= ~0x10;
mix_write(0x80 | 5, 0x078B);
mix_write(5, 0x078B);
-#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE))
+#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
{
struct address_info *sb_config;
if ((pas_model = pas_read(0xFF88)))
{
- char temp[100];
+ char temp[100];
sprintf(temp,
"%s rev %d", pas_model_names[(int) pas_model],
pas_pcm_init(hw_config);
#endif
-#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE))
+#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */
#endif
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
pas_midi_init();
#endif
pas_init_mixer();
#include "sound_config.h"
-#if ( defined(MODULE) || defined(CONFIG_PAS) ) && defined(CONFIG_MIDI)
+#ifdef CONFIG_PAS
+#ifdef CONFIG_MIDI
static int midi_busy = 0, input_opened = 0;
static int my_dev;
}
#endif
+#endif
#include "sound_config.h"
-#if defined(CONFIG_PAS) || defined(MODULE)
+#ifdef CONFIG_PAS
#ifndef DEB
#define DEB(what) /* (what) */
#include "sound_config.h"
-#if defined(MODULE) || ( defined(CONFIG_PAS) && defined(CONFIG_AUDIO) )
+#ifdef CONFIG_PAS
+#ifdef CONFIG_AUDIO
#ifndef DEB
#define DEB(WHAT)
}
#endif
+#endif
#include "sound_firmware.h"
#include "soundmodule.h"
-#if (defined(CONFIG_PSS) && defined(CONFIG_AUDIO))||defined(MODULE)
+#ifdef CONFIG_PSS
+#ifdef CONFIG_AUDIO
/*
* PSS registers.
#include "coproc.h"
-#ifdef CONFIG_PSS_HAVE_BOOT
+#ifdef PSS_HAVE_LD
#include "pss_boot.h"
#else
-static unsigned char *pss_synth = NULL;
static int pss_synthLen = 0;
+static unsigned char *pss_synth =
+NULL;
#endif
unsigned char pss_mixer = 1;
}
#endif
#endif
+#endif
#include <linux/config.h>
+#include "legacy.h"
#ifdef CONFIG_SBDSP
#define DSP_RESET (devc->base + 0x6)
int input_opened;
int midi_broken;
void (*midi_input_intr) (int dev, unsigned char data);
+ void *midi_irq_cookie; /* IRQ cookie for the midi */
} sb_devc;
int sb_dsp_command (sb_devc *devc, unsigned char val);
int ess_read (sb_devc *devc, unsigned char reg);
extern int acer;
+extern sb_devc *last_sb;
#endif
#include <linux/config.h>
#include "sound_config.h"
-#if defined(CONFIG_SBDSP) || defined(MODULE)
+#ifdef CONFIG_SBDSP
#include "sb_mixer.h"
#include "sb.h"
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_SBDSP) || defined (MODULE)
+#ifdef CONFIG_SBDSP
#include "sb_mixer.h"
#include "sb.h"
int acer = 0;
#endif
#endif
-#endif
EXPORT_SYMBOL(sb_dsp_init);
EXPORT_SYMBOL(sb_dsp_detect);
EXPORT_SYMBOL(probe_sb);
EXPORT_SYMBOL(unload_sb);
EXPORT_SYMBOL(sb_be_quiet);
+
+#endif
#include "sound_config.h"
#include "sound_firmware.h"
-#if defined(CONFIG_SBDSP) || defined(MODULE)
+#ifdef CONFIG_SBDSP
#ifndef CONFIG_AUDIO
#error You will need to configure the sound driver with CONFIG_AUDIO option.
#endif
+sb_devc *last_sb = NULL; /* Last sb loaded */
int sb_dsp_command(sb_devc * devc, unsigned char val)
{
{
src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */
-#if defined(CONFIG_MIDI)&& (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE))
+#if defined(CONFIG_MIDI)&& defined(CONFIG_UART401)
if (src & 4)
- uart401intr(devc->irq, NULL, NULL); /* MPU401 interrupt */
+ uart401intr(devc->irq, devc->midi_irq_cookie, NULL); /* MPU401 interrupt */
#endif
if (!(src & 3))
break;
case IMODE_MIDI:
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
sb_midi_interrupt(devc);
#endif
break;
} /* IRQ setup */
request_region(hw_config->io_base, 16, "soundblaster");
+ last_sb = devc;
+
switch (devc->major)
{
case 1: /* SB 1.0 or 1.5 */
if (devc->major == 3 || devc->major == 4)
sb_mixer_init(devc);
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
if (!(devc->caps & SB_NO_MIDI))
sb_dsp_midi_init(devc);
#endif
{
free_irq(devc->irq, devc);
sound_unload_mixerdev(devc->my_mixerdev);
- sound_unload_mididev(devc->my_mididev);
+ /* We don't have to do this bit any more the UART401 is its own
+ master -- Krzystof Halasa */
+ /* sound_unload_mididev(devc->my_mididev); */
sound_unload_audiodev(devc->my_dev);
}
kfree(devc);
return val;
}
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
/*
* MPU401 MIDI initialization.
void attach_sbmpu(struct address_info *hw_config)
{
-#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE))
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
attach_uart401(hw_config);
+ last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]];
#endif
}
int probe_sbmpu(struct address_info *hw_config)
{
-#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE))
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
sb_devc *devc = last_devc;
if (last_devc == NULL)
void unload_sbmpu(struct address_info *hw_config)
{
-#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE))
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
unload_uart401(hw_config);
#endif
}
#include <linux/config.h>
#include "sound_config.h"
-#if defined(CONFIG_SBDSP) || defined(MODULE)
+#ifdef CONFIG_SBDSP
#define __SB_MIXER_C__
#include "sb.h"
*
*/
#include <linux/config.h>
+#include "legacy.h"
#ifdef CONFIG_SBDSP
#define SEQUENCER_C
#include "sound_config.h"
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
#include "softoss.h"
int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL;
void sequencer_init(void)
{
+ /* drag in sequencer_syms.o */
+ {
+ extern char sequencer_syms_symbol;
+ sequencer_syms_symbol = 0;
+ }
+
if (sequencer_ok)
return;
#ifdef CONFIG_MIDI
--- /dev/null
+/*
+ * Exported symbols for sequencer driver.
+ * __NO_VERSION__ because this is still part of sound.o.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+char sequencer_syms_symbol;
+
+#include "sound_config.h"
+
+#include "sound_calls.h"
+
+EXPORT_SYMBOL(note_to_freq);
+EXPORT_SYMBOL(compute_finetune);
+EXPORT_SYMBOL(seq_copy_to_input);
+EXPORT_SYMBOL(seq_input_event);
+EXPORT_SYMBOL(sequencer_init);
+EXPORT_SYMBOL(sequencer_timer);
+
+EXPORT_SYMBOL(sound_timer_init);
+EXPORT_SYMBOL(sound_timer_interrupt);
+EXPORT_SYMBOL(sound_timer_syncinterval);
+EXPORT_SYMBOL(reprogram_timer);
+
+#include "softoss.h"
+
+EXPORT_SYMBOL(softsynthp);
+
+/* Tuning */
+
+#define _SEQUENCER_C_
+#include "tuning.h"
+
+EXPORT_SYMBOL(cent_tuning);
+EXPORT_SYMBOL(semitone_tuning);
--- /dev/null
+/*
+ * sound/sgalaxy.c
+ *
+ * Low level driver for Aztech Sound Galaxy cards.
+ * Copyright 1998 Artur Skawina
+ *
+ * Supported cards:
+ * Aztech Sound Galaxy Waverider Pro 32 - 3D
+ * Aztech Sound Galaxy Washington 16
+ *
+ * Based on cs4232.c by Hannu Savolainen and Alan Cox.
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1997
+ *
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include "sound_config.h"
+#include "soundmodule.h"
+
+#if defined(CONFIG_SGALAXY) || defined (MODULE)
+
+static void sleep( unsigned howlong )
+{
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + howlong;
+ schedule();
+ current->timeout = 0;
+}
+
+#define DPORT 0x80
+
+/* Sound Blaster regs */
+
+#define SBDSP_RESET 0x6
+#define SBDSP_READ 0xA
+#define SBDSP_COMMAND 0xC
+#define SBDSP_STATUS SBDSP_COMMAND
+#define SBDSP_DATA_AVAIL 0xE
+
+static int sb_rst(int base)
+{
+ int i;
+
+ outb( 1, base+SBDSP_RESET ); /* reset the DSP */
+ outb( 0, base+SBDSP_RESET );
+
+ for ( i=0; i<500; i++ ) /* delay */
+ inb(DPORT);
+
+ for ( i=0; i<100000; i++ )
+ {
+ if ( inb( base+SBDSP_DATA_AVAIL )&0x80 )
+ break;
+ }
+
+ if ( inb( base+SBDSP_READ )!=0xAA )
+ return 0;
+
+ return 1;
+}
+
+static int sb_cmd( int base, unsigned char val )
+{
+ int i;
+
+ for ( i=100000; i; i-- )
+ {
+ if ( (inb( base+SBDSP_STATUS )&0x80)==0 )
+ {
+ outb( val, base+SBDSP_COMMAND );
+ break;
+ }
+ }
+ return i; /* i>0 == success */
+}
+
+
+#define ai_sgbase driver_use_1
+
+int probe_sgalaxy( struct address_info *ai )
+{
+ if ( check_region( ai->io_base, 8 ) )
+ {
+ printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
+ return 0;
+ }
+
+ if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) )
+ return 1; /* The card is already active */
+
+ if ( check_region( ai->ai_sgbase, 0x10 ) )
+ {
+ printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
+ return 0;
+ }
+
+ /* switch to MSS/WSS mode */
+
+ sb_rst( ai->ai_sgbase );
+
+ sb_cmd( ai->ai_sgbase, 9 );
+ sb_cmd( ai->ai_sgbase, 0 );
+
+ sleep( HZ/10 );
+
+ if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) )
+ return 1;
+ return 0;
+}
+
+void attach_sgalaxy( struct address_info *ai )
+{
+ int n;
+
+ request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB" );
+
+ n=attach_ms_sound( ai );
+ if (n!=-1 && audio_devs[n]->mixer_dev != -1 )
+ {
+ AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */
+ AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/
+ AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */
+ }
+}
+
+void unload_sgalaxy( struct address_info *ai )
+{
+ unload_ms_sound( ai );
+ release_region( ai->ai_sgbase, 0x10 );
+}
+
+#ifdef MODULE
+
+int io = -1;
+int irq = -1;
+int dma = -1;
+int dma2 = -1;
+int sgbase = -1;
+
+MODULE_PARM(io,"i");
+MODULE_PARM(irq,"i");
+MODULE_PARM(dma,"i");
+MODULE_PARM(dma2,"i");
+MODULE_PARM(sgbase,"i");
+
+EXPORT_NO_SYMBOLS;
+
+struct address_info ai;
+
+
+int init_module(void)
+{
+ if ( io==-1 || irq==-1 || dma==-1 || sgbase==-1 )
+ {
+ printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
+ return -EINVAL;
+ }
+
+ ai.io_base = io;
+ ai.irq = irq;
+ ai.dma = dma;
+ ai.dma2 = dma2;
+ ai.ai_sgbase = sgbase;
+
+ if ( probe_sgalaxy( &ai )==0 )
+ return -ENODEV;
+
+ attach_sgalaxy( &ai );
+
+ SOUND_LOCK;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unload_sgalaxy( &ai );
+ SOUND_LOCK_END;
+}
+
+#endif
+#endif
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_SOFTOSS) || defined(MODULE)
+#ifdef CONFIG_SOFTOSS
#include "softoss.h"
#include <linux/ultrasound.h>
#include "sound_config.h"
-#if defined(CONFIG_SOFTOSS) || defined(MODULE)
+#ifdef CONFIG_SOFTOSS
#include "softoss.h"
void softsynth_resample_loop(short *buf, int loops)
* for more info.
*/
-#include <linux/fs.h>
-#include "local.h.master"
+
+#ifndef _SOUND_CONFIG_H_
+#define _SOUND_CONFIG_H_
+
#include <linux/config.h>
+#include <linux/fs.h>
+
+#include "legacy.h"
#include "os.h"
#include "soundvers.h"
-
#ifndef SND_DEFAULT_ENABLE
#define SND_DEFAULT_ENABLE 1
#endif
#define TIMER_ARMED 121234
#define TIMER_NOT_ARMED 1
+
+#endif
#include <linux/module.h>
#include "sound_config.h"
-#define _MIDI_SYNTH_C_
-#include "midi_synth.h"
-#define _SEQUENCER_C_
-#include "tuning.h"
-#include <linux/notifier.h>
-#include "sound_firmware.h"
-
-extern struct notifier_block *sound_locker;
-extern void sound_notifier_chain_register(struct notifier_block *);
+#include "sound_calls.h"
+char sound_syms_symbol;
EXPORT_SYMBOL(mixer_devs);
EXPORT_SYMBOL(audio_devs);
EXPORT_SYMBOL(num_mixers);
EXPORT_SYMBOL(num_audiodevs);
-EXPORT_SYMBOL(note_to_freq);
-EXPORT_SYMBOL(compute_finetune);
-EXPORT_SYMBOL(seq_copy_to_input);
-EXPORT_SYMBOL(seq_input_event);
-EXPORT_SYMBOL(sequencer_init);
-EXPORT_SYMBOL(sequencer_timer);
+EXPORT_SYMBOL(midi_devs);
+EXPORT_SYMBOL(num_midis);
+EXPORT_SYMBOL(synth_devs);
+EXPORT_SYMBOL(num_synths);
+
+EXPORT_SYMBOL(sound_timer_devs);
+EXPORT_SYMBOL(num_sound_timers);
EXPORT_SYMBOL(sound_install_audiodrv);
EXPORT_SYMBOL(sound_install_mixer);
EXPORT_SYMBOL(load_mixer_volumes);
-EXPORT_SYMBOL(DMAbuf_start_dma);
-EXPORT_SYMBOL(DMAbuf_open_dma);
-EXPORT_SYMBOL(DMAbuf_close_dma);
-EXPORT_SYMBOL(DMAbuf_inputintr);
-EXPORT_SYMBOL(DMAbuf_outputintr);
-EXPORT_SYMBOL(dma_ioctl);
-
EXPORT_SYMBOL(conf_printf);
EXPORT_SYMBOL(conf_printf2);
-EXPORT_SYMBOL(sound_timer_init);
-EXPORT_SYMBOL(sound_timer_interrupt);
-EXPORT_SYMBOL(sound_timer_syncinterval);
-EXPORT_SYMBOL(sound_timer_devs);
+#include "sound_firmware.h"
+EXPORT_SYMBOL(mod_firmware_load);
+
+extern int softoss_dev;
+EXPORT_SYMBOL(softoss_dev);
/* Locking */
+#include "soundmodule.h"
EXPORT_SYMBOL(sound_locker);
EXPORT_SYMBOL(sound_notifier_chain_register);
-/* MIDI symbols */
-EXPORT_SYMBOL(midi_devs);
-EXPORT_SYMBOL(num_midis);
-EXPORT_SYMBOL(synth_devs);
-EXPORT_SYMBOL(num_synths);
-
-EXPORT_SYMBOL(do_midi_msg);
-EXPORT_SYMBOL(midi_synth_open);
-EXPORT_SYMBOL(midi_synth_close);
-EXPORT_SYMBOL(midi_synth_ioctl);
-EXPORT_SYMBOL(midi_synth_kill_note);
-EXPORT_SYMBOL(midi_synth_start_note);
-EXPORT_SYMBOL(midi_synth_set_instr);
-EXPORT_SYMBOL(midi_synth_reset);
-EXPORT_SYMBOL(midi_synth_hw_control);
-EXPORT_SYMBOL(midi_synth_aftertouch);
-EXPORT_SYMBOL(midi_synth_controller);
-EXPORT_SYMBOL(midi_synth_panning);
-EXPORT_SYMBOL(midi_synth_setup_voice);
-EXPORT_SYMBOL(midi_synth_send_sysex);
-EXPORT_SYMBOL(midi_synth_bender);
-EXPORT_SYMBOL(midi_synth_load_patch);
-
-/* Firmware */
-
-EXPORT_SYMBOL(mod_firmware_load);
-
-/* Tuning */
-
-EXPORT_SYMBOL(cent_tuning);
-EXPORT_SYMBOL(semitone_tuning);
-
MODULE_DESCRIPTION("Sound subsystem");
MODULE_AUTHOR("Hannu Savolainen, et al.");
#include "sound_config.h"
-#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE)
+#if defined(CONFIG_SEQUENCER)
static volatile int initialized = 0, opened = 0, tmr_running = 0;
static volatile time_t tmr_offs, tmr_ctr;
#include <linux/delay.h>
#include <linux/proc_fs.h>
-#define SOUND_CORE
-
#include "soundmodule.h"
+struct notifier_block *sound_locker=(struct notifier_block *)0;
+static int lock_depth = 0;
#include <linux/major.h>
+
#ifdef MODULE
#define modular 1
#else
return -ENXIO;
}
in_use++;
-#ifdef MODULE
- SOUND_INC_USE_COUNT;
+
+#ifdef CONFIG_MODULES
+ notifier_call_chain(&sound_locker, 1, 0);
+ lock_depth++;
#endif
+
return 0;
}
printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
}
in_use--;
-#ifdef MODULE
- SOUND_DEC_USE_COUNT;
+
+#ifdef CONFIG_MODULES
+ notifier_call_chain(&sound_locker, 0, 0);
+ lock_depth--;
#endif
+
return 0;
}
DEB(printk("sound_poll(dev=%d)\n", dev));
switch (dev & 0x0f) {
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_poll(dev, file, wait);
#endif
-#if defined(CONFIG_MIDI)
+#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
return MIDIbuf_poll(dev, file, wait);
#endif
-#if defined(CONFIG_AUDIO) || defined(MODULE)
+#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
#endif
soundcard_init(void)
{
+ /* drag in sound_syms.o */
+ {
+ extern char sound_syms_symbol;
+ sound_syms_symbol = 0;
+ }
+
#ifndef MODULE
register_chrdev(sound_major, "sound", &sound_fops);
chrdev_registered = 1;
return; /* No cards detected */
#endif
-#if defined(CONFIG_AUDIO)
+#ifdef CONFIG_AUDIO
if (num_audiodevs || modular) /* Audio devices present */
{
audio_init_devices();
0
};
+#ifdef MODULE
+
int init_module(void)
{
int err;
return 0;
}
-#ifdef MODULE
-
-
void cleanup_module(void)
{
int i;
if (chrdev_registered)
unregister_chrdev(sound_major, "sound");
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
sound_stop_timer();
#endif
restore_flags(flags);
}
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
static void do_sequencer_timer(unsigned long dummy)
{
* Module and lock management
*/
-struct notifier_block *sound_locker=(struct notifier_block *)0;
-static int lock_depth = 0;
-
-#define SOUND_INC_USE_COUNT do { notifier_call_chain(&sound_locker, 1, 0); lock_depth++; } while(0);
-#define SOUND_DEC_USE_COUNT do { notifier_call_chain(&sound_locker, 0, 0); lock_depth--; } while(0);
-
/*
* When a sound module is registered we need to bring it to the current
* lock level...
extern struct notifier_block *sound_locker;
extern void sound_notifier_chain_register(struct notifier_block *);
-extern int lock_depth;
#ifdef MODULE
-#ifdef SOUND_CORE
-
-#define SOUND_INC_USE_COUNT do { notifier_call_chain(&sound_locker, 1, 0); lock_depth++; } while(0);
-#define SOUND_DEC_USE_COUNT do { notifier_call_chain(&sound_locker, 0, 0); lock_depth--; } while(0);
-
-#else
-
-
#define SOUND_LOCK sound_notifier_chain_register(&sound_notifier);
#define SOUND_LOCK_END notifier_chain_unregister(&sound_locker, &sound_notifier)
-
-
static int my_notifier_call(struct notifier_block *b, unsigned long foo, void *bar)
{
if(foo)
#endif
#endif
-#endif
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_SSCAPE) || defined(MODULE)
+#ifdef CONFIG_SSCAPE
#include "coproc.h"
#include "sound_config.h"
-#if defined(CONFIG_SEQUENCER) || defined(MODULE)
+#ifdef CONFIG_SEQUENCER
static volatile int opened = 0, tmr_running = 0;
static volatile time_t tmr_offs, tmr_ctr;
#include "sb.h"
#include "sound_firmware.h"
-#if defined(CONFIG_TRIX) || defined (MODULE)
+#ifdef CONFIG_TRIX
-#if defined(CONFIG_UART401) || defined(CONFIG_UART401_MODULE)
-#if defined(CONFIG_MIDI)
-#define DO_MIDI
-#endif
-#endif
-
-#ifdef CONFIG_TRIX_HAVE_BOOT
+#ifdef INCLUDE_TRIX_BOOT
#include "trix_boot.h"
#else
static unsigned char *trix_boot = NULL;
int probe_trix_mpu(struct address_info *hw_config)
{
-#ifdef DO_MIDI
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unsigned char conf;
static char irq_bits[] = {
-1, -1, -1, 1, 2, 3, -1, 4, -1, 5
void unload_trix_mpu(struct address_info *hw_config)
{
-#ifdef DO_MIDI
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unload_uart401(hw_config);
#endif
}
#include "sound_config.h"
#include "soundmodule.h"
-#if (defined(CONFIG_UART401)||defined(CONFIG_MIDI)) || defined(MODULE)
+#ifdef CONFIG_UART401
+#ifdef CONFIG_MIDI
typedef struct uart401_devc
{
SOUND_LOCK_END;
}
-#else
-
-#endif
-
#endif
EXPORT_SYMBOL(attach_uart401);
EXPORT_SYMBOL(probe_uart401);
EXPORT_SYMBOL(unload_uart401);
EXPORT_SYMBOL(uart401intr);
+
+#endif
+#endif
*/
#include "sound_config.h"
+
+#ifdef CONFIG_SOUND_UART6850
+#ifdef CONFIG_MIDI
#include "soundmodule.h"
-#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) || defined(MODULE)
static int uart6850_base = 0x330;
}
#endif
#endif
+#endif
#include <linux/config.h>
#include <linux/module.h>
-
+#ifdef CONFIG_VMIDI
#include "sound_config.h"
#include "soundmodule.h"
-
-#if defined(CONFIG_VMIDI) || defined(MODULE)
-
#include "v_midi.h"
static vmidi_devc *v_devc[2] = { NULL, NULL};
break;
}
- n -= copy_to_user(buf, start, n); /* BUG ??? */
+ /* This is a hack to allow mangling of file pos independent
+ * of actual bytes read. Simply place the data at page,
+ * return the bytes, and set `start' to the desired offset
+ * as an unsigned int. - Paul.Russell@rustcorp.com.au
+ */
+ n -= copy_to_user(buf, start < page ? page : start, n);
if (n == 0) {
if (retval == 0)
retval = -EFAULT;
break;
}
-
- *ppos += n; /* Move down the file */
+
+ *ppos += start < page ? (long)start : n; /* Move down the file */
nbytes -= n;
buf += n;
retval += n;
/*
- * IP firewalling code. This is taken from 4.4BSD. Please note the
- * copyright message below. As per the GPL it must be maintained
- * and the licenses thus do not conflict. While this port is subject
- * to the GPL I also place my modifications under the original
- * license in recognition of the original copyright.
+ * This code is heavily based on the code in ip_fw.h; see that file for
+ * copyrights and attributions. This code is basically GPL.
*
- * Ported from BSD to Linux,
- * Alan Cox 22/Nov/1994.
- * Merged and included the FreeBSD-Current changes at Ugen's request
- * (but hey it's a lot cleaner now). Ugen would prefer in some ways
- * we waited for his final product but since Linux 1.2.0 is about to
- * appear it's not practical - Read: It works, it's not clean but please
- * don't consider it to be his standard of finished work.
- * Alan.
- *
- * Fixes:
- * Pauline Middelink : Added masquerading.
- * Jos Vos : Separate input and output firewall
- * chains, new "insert" and "append"
- * commands to replace "add" commands,
- * add ICMP header to struct ip_fwpkt.
- * Jos Vos : Add support for matching device names.
- * Willy Konynenberg : Add transparent proxying support.
- * Jos Vos : Add options for input/output accounting.
- *
- * All the real work was done by .....
- */
-
-/*
- * Copyright (c) 1993 Daniel Boulet
- * Copyright (c) 1994 Ugen J.S.Antsilevich
- *
- * Redistribution and use in source forms, with and without modification,
- * are permitted provided that this entire comment appears intact.
- *
- * Redistribution in binary form may occur without any restrictions.
- * Obviously, it would be nice if you gave credit where credit is due
- * but requiring it would be too onerous.
- *
- * This software is provided ``AS IS'' without any warranties of any kind.
+ * 15-Feb-1997: Major changes to allow graphs for firewall rules.
+ * Paul Russell <Paul.Russell@rustcorp.com.au> and
+ * Michael Neuling <Michael.Neuling@rustcorp.com.au>
+ * 2-Nov-1997: Changed types to __u16, etc.
+ * Removed IP_FW_F_TCPACK & IP_FW_F_BIDIR.
+ * Added inverse flags field.
+ * Removed multiple port specs.
*/
/*
* Format of an IP firewall descriptor
*
* src, dst, src_mask, dst_mask are always stored in network byte order.
- * flags and num_*_ports are stored in host byte order (of course).
+ * flags are stored in host byte order (of course).
* Port numbers are stored in HOST byte order.
*/
-#ifndef _IP_FW_H
-#define _IP_FW_H
+#ifndef _IP_FWCHAINS_H
+#define _IP_FWCHAINS_H
-#ifdef __KERNEL__
#include <linux/icmp.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
-#endif
+#define IP_FW_MAX_LABEL_LENGTH 8
+typedef char ip_chainlabel[IP_FW_MAX_LABEL_LENGTH+1];
struct ip_fw
{
- struct ip_fw *fw_next; /* Next firewall on chain */
struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
- struct in_addr fw_via; /* IP address of interface "via" */
- struct device *fw_viadev; /* device of interface "via" */
- __u16 fw_flg; /* Flags word */
- __u16 fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */
- /* in ports array (dst ports follow */
- /* src ports; max of 10 ports in all; */
- /* count of 0 means match all ports) */
-#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */
- __u16 fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
- unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */
- __u8 fw_tosand, fw_tosxor; /* Revised packet priority */
+ __u32 fw_mark; /* ID to stamp on packet */
+ __u16 fw_proto; /* Protocol, 0 = ANY */
+ __u16 fw_flg; /* Flags word */
+ __u16 fw_invflg; /* Inverse flags */
+ __u16 fw_spts[2]; /* Source port range. */
+ __u16 fw_dpts[2]; /* Destination port range. */
+ __u16 fw_redirpt; /* Port to redirect to. */
+ __u16 fw_outputsize; /* Max amount to output to
+ NETLINK */
char fw_vianame[IFNAMSIZ]; /* name of interface "via" */
+ __u8 fw_tosand, fw_tosxor; /* Revised packet priority */
};
-/*
- * Values for "flags" field .
- */
+struct ip_fwuser
+{
+ struct ip_fw ipfw;
+ ip_chainlabel label;
+};
-#define IP_FW_F_ALL 0x0000 /* This is a universal packet firewall*/
-#define IP_FW_F_TCP 0x0001 /* This is a TCP packet firewall */
-#define IP_FW_F_UDP 0x0002 /* This is a UDP packet firewall */
-#define IP_FW_F_ICMP 0x0003 /* This is a ICMP packet firewall */
-#define IP_FW_F_KIND 0x0003 /* Mask to isolate firewall kind */
-#define IP_FW_F_ACCEPT 0x0004 /* This is an accept firewall (as *
- * opposed to a deny firewall)*
- * */
-#define IP_FW_F_SRNG 0x0008 /* The first two src ports are a min *
- * and max range (stored in host byte *
- * order). *
- * */
-#define IP_FW_F_DRNG 0x0010 /* The first two dst ports are a min *
- * and max range (stored in host byte *
- * order). *
- * (ports[0] <= port <= ports[1]) *
- * */
-#define IP_FW_F_PRN 0x0020 /* In verbose mode print this firewall*/
-#define IP_FW_F_BIDIR 0x0040 /* For bidirectional firewalls */
-#define IP_FW_F_TCPSYN 0x0080 /* For tcp packets-check SYN only */
-#define IP_FW_F_ICMPRPL 0x0100 /* Send back icmp unreachable packet */
-#define IP_FW_F_MASQ 0x0200 /* Masquerading */
-#define IP_FW_F_TCPACK 0x0400 /* For tcp-packets match if ACK is set*/
-#define IP_FW_F_REDIR 0x0800 /* Redirect to local port fw_pts[n] */
-#define IP_FW_F_ACCTIN 0x1000 /* Account incoming packets only. */
-#define IP_FW_F_ACCTOUT 0x2000 /* Account outgoing packets only. */
-
-#define IP_FW_F_MASK 0x3FFF /* All possible flag bits mask */
+/* Values for "fw_flg" field . */
+#define IP_FW_F_PRN 0x0001 /* Print packet if it matches */
+#define IP_FW_F_TCPSYN 0x0002 /* For tcp packets-check SYN only */
+#define IP_FW_F_FRAG 0x0004 /* Set if rule is a fragment rule */
+#define IP_FW_F_MARKABS 0x0008 /* Set the mark to fw_mark, not add. */
+#define IP_FW_F_WILDIF 0x0010 /* Need only match start of interface name. */
+#define IP_FW_F_NETLINK 0x0020 /* Redirect to netlink: 2.1.x only */
+#define IP_FW_F_MASK 0x002F /* All possible flag bits mask */
+
+/* Values for "fw_invflg" field. */
+#define IP_FW_INV_SRCIP 0x0001 /* Invert the sense of fw_src. */
+#define IP_FW_INV_DSTIP 0x0002 /* Invert the sense of fw_dst. */
+#define IP_FW_INV_PROTO 0x0004 /* Invert the sense of fw_proto. */
+#define IP_FW_INV_SRCPT 0x0008 /* Invert the sense of source ports. */
+#define IP_FW_INV_DSTPT 0x0010 /* Invert the sense of destination ports. */
+#define IP_FW_INV_VIA 0x0020 /* Invert the sense of fw_vianame. */
+#define IP_FW_INV_SYN 0x0040 /* Invert the sense of IP_FW_F_TCPSYN. */
+#define IP_FW_INV_FRAG 0x0080 /* Invert the sense of IP_FW_F_FRAG. */
/*
* New IP firewall options for [gs]etsockopt at the RAW IP level.
* Unlike BSD Linux inherits IP options so you don't have to use
- * a raw socket for this. Instead we check rights in the calls.
- */
+ * a raw socket for this. Instead we check rights in the calls. */
#define IP_FW_BASE_CTL 64 /* base for firewall socket options */
-#define IP_FW_COMMAND 0x00FF /* mask for command without chain */
-#define IP_FW_TYPE 0x0300 /* mask for type (chain) */
-#define IP_FW_SHIFT 8 /* shift count for type (chain) */
-
-#define IP_FW_FWD 0
-#define IP_FW_IN 1
-#define IP_FW_OUT 2
-#define IP_FW_ACCT 3
-#define IP_FW_CHAINS 4 /* total number of ip_fw chains */
-#define IP_FW_MASQ 5
-
-#define IP_FW_INSERT (IP_FW_BASE_CTL)
-#define IP_FW_APPEND (IP_FW_BASE_CTL+1)
-#define IP_FW_DELETE (IP_FW_BASE_CTL+2)
-#define IP_FW_FLUSH (IP_FW_BASE_CTL+3)
-#define IP_FW_ZERO (IP_FW_BASE_CTL+4)
-#define IP_FW_POLICY (IP_FW_BASE_CTL+5)
-#define IP_FW_CHECK (IP_FW_BASE_CTL+6)
-#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+7)
-
-#define IP_FW_INSERT_FWD (IP_FW_INSERT | (IP_FW_FWD << IP_FW_SHIFT))
-#define IP_FW_APPEND_FWD (IP_FW_APPEND | (IP_FW_FWD << IP_FW_SHIFT))
-#define IP_FW_DELETE_FWD (IP_FW_DELETE | (IP_FW_FWD << IP_FW_SHIFT))
-#define IP_FW_FLUSH_FWD (IP_FW_FLUSH | (IP_FW_FWD << IP_FW_SHIFT))
-#define IP_FW_ZERO_FWD (IP_FW_ZERO | (IP_FW_FWD << IP_FW_SHIFT))
-#define IP_FW_POLICY_FWD (IP_FW_POLICY | (IP_FW_FWD << IP_FW_SHIFT))
-#define IP_FW_CHECK_FWD (IP_FW_CHECK | (IP_FW_FWD << IP_FW_SHIFT))
-
-#define IP_FW_INSERT_IN (IP_FW_INSERT | (IP_FW_IN << IP_FW_SHIFT))
-#define IP_FW_APPEND_IN (IP_FW_APPEND | (IP_FW_IN << IP_FW_SHIFT))
-#define IP_FW_DELETE_IN (IP_FW_DELETE | (IP_FW_IN << IP_FW_SHIFT))
-#define IP_FW_FLUSH_IN (IP_FW_FLUSH | (IP_FW_IN << IP_FW_SHIFT))
-#define IP_FW_ZERO_IN (IP_FW_ZERO | (IP_FW_IN << IP_FW_SHIFT))
-#define IP_FW_POLICY_IN (IP_FW_POLICY | (IP_FW_IN << IP_FW_SHIFT))
-#define IP_FW_CHECK_IN (IP_FW_CHECK | (IP_FW_IN << IP_FW_SHIFT))
-
-#define IP_FW_INSERT_OUT (IP_FW_INSERT | (IP_FW_OUT << IP_FW_SHIFT))
-#define IP_FW_APPEND_OUT (IP_FW_APPEND | (IP_FW_OUT << IP_FW_SHIFT))
-#define IP_FW_DELETE_OUT (IP_FW_DELETE | (IP_FW_OUT << IP_FW_SHIFT))
-#define IP_FW_FLUSH_OUT (IP_FW_FLUSH | (IP_FW_OUT << IP_FW_SHIFT))
-#define IP_FW_ZERO_OUT (IP_FW_ZERO | (IP_FW_OUT << IP_FW_SHIFT))
-#define IP_FW_POLICY_OUT (IP_FW_POLICY | (IP_FW_OUT << IP_FW_SHIFT))
-#define IP_FW_CHECK_OUT (IP_FW_CHECK | (IP_FW_OUT << IP_FW_SHIFT))
-
-#define IP_ACCT_INSERT (IP_FW_INSERT | (IP_FW_ACCT << IP_FW_SHIFT))
-#define IP_ACCT_APPEND (IP_FW_APPEND | (IP_FW_ACCT << IP_FW_SHIFT))
-#define IP_ACCT_DELETE (IP_FW_DELETE | (IP_FW_ACCT << IP_FW_SHIFT))
-#define IP_ACCT_FLUSH (IP_FW_FLUSH | (IP_FW_ACCT << IP_FW_SHIFT))
-#define IP_ACCT_ZERO (IP_FW_ZERO | (IP_FW_ACCT << IP_FW_SHIFT))
-
-#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT))
-#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT))
-#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT))
-#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT))
-
-#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT))
-#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT))
-#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT))
-#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT))
+#define IP_FW_APPEND (IP_FW_BASE_CTL) /* Takes ip_fwchange */
+#define IP_FW_REPLACE (IP_FW_BASE_CTL+1) /* Takes ip_fwnew */
+#define IP_FW_DELETE_NUM (IP_FW_BASE_CTL+2) /* Takes ip_fwdelnum */
+#define IP_FW_DELETE (IP_FW_BASE_CTL+3) /* Takes ip_fwchange */
+#define IP_FW_INSERT (IP_FW_BASE_CTL+4) /* Takes ip_fwnew */
+#define IP_FW_FLUSH (IP_FW_BASE_CTL+5) /* Takes ip_chainlabel */
+#define IP_FW_ZERO (IP_FW_BASE_CTL+6) /* Takes ip_chainlabel */
+#define IP_FW_CHECK (IP_FW_BASE_CTL+7) /* Takes ip_fwtest */
+#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+8) /* Takes 3 ints */
+#define IP_FW_CREATECHAIN (IP_FW_BASE_CTL+9) /* Takes ip_chainlabel */
+#define IP_FW_DELETECHAIN (IP_FW_BASE_CTL+10) /* Takes ip_chainlabel */
+#define IP_FW_POLICY (IP_FW_BASE_CTL+11) /* Takes ip_fwpolicy */
+/* Masquerade controls */
+#define IP_FW_MASQ_INSERT (IP_FW_BASE_CTL+12)
+#define IP_FW_MASQ_ADD (IP_FW_BASE_CTL+13)
+#define IP_FW_MASQ_DEL (IP_FW_BASE_CTL+14)
+#define IP_FW_MASQ_FLUSH (IP_FW_BASE_CTL+15)
+
+/* Builtin chain labels */
+#define IP_FW_LABEL_FORWARD "forward"
+#define IP_FW_LABEL_INPUT "input"
+#define IP_FW_LABEL_OUTPUT "output"
+
+/* Special targets */
+#define IP_FW_LABEL_MASQUERADE "MASQ"
+#define IP_FW_LABEL_REDIRECT "REDIRECT"
+#define IP_FW_LABEL_ACCEPT "ACCEPT"
+#define IP_FW_LABEL_BLOCK "DENY"
+#define IP_FW_LABEL_REJECT "REJECT"
+#define IP_FW_LABEL_RETURN "RETURN"
+#define IP_FW_LABEL_QUEUE "QUEUE"
+
+/* Files in /proc/net */
+#define IP_FW_PROC_CHAINS "ip_fwchains"
+#define IP_FW_PROC_CHAIN_NAMES "ip_fwnames"
+
struct ip_fwpkt
{
char fwp_vianame[IFNAMSIZ]; /* interface name */
};
+/* The argument to IP_FW_DELETE and IP_FW_APPEND */
+struct ip_fwchange
+{
+ struct ip_fwuser fwc_rule;
+ ip_chainlabel fwc_label;
+};
+
+/* The argument to IP_FW_CHECK. */
+struct ip_fwtest
+{
+ struct ip_fwpkt fwt_packet; /* Packet to be tested */
+ ip_chainlabel fwt_label; /* Block to start test in */
+};
+
+/* The argument to IP_FW_DELETE_NUM */
+struct ip_fwdelnum
+{
+ __u32 fwd_rulenum;
+ ip_chainlabel fwd_label;
+};
+
+/* The argument to IP_FW_REPLACE and IP_FW_INSERT */
+struct ip_fwnew
+{
+ __u32 fwn_rulenum;
+ struct ip_fwuser fwn_rule;
+ ip_chainlabel fwn_label;
+};
+
+/* The argument to IP_FW_POLICY */
+struct ip_fwpolicy
+{
+ ip_chainlabel fwp_policy;
+ ip_chainlabel fwp_label;
+};
+/*
+ * timeouts for ip masquerading
+ */
+
+struct ip_fw_masq;
+
+/* Masquerading stuff */
#define IP_FW_MASQCTL_MAX 256
#define IP_MASQ_MOD_NMAX 32
} u;
};
-/*
- * timeouts for ip masquerading
- */
-struct ip_fw_masq;
/*
* Main firewall chains definitions and global var's definitions.
#ifdef __KERNEL__
-/* Modes used in the ip_fw_chk() routine. */
-#define IP_FW_MODE_FW 0x00 /* kernel firewall check */
-#define IP_FW_MODE_ACCT_IN 0x01 /* accounting (incoming) */
-#define IP_FW_MODE_ACCT_OUT 0x02 /* accounting (outgoing) */
-#define IP_FW_MODE_CHK 0x04 /* check requested by user */
-
#include <linux/config.h>
-#ifdef CONFIG_IP_FIREWALL
-extern struct ip_fw *ip_fw_in_chain;
-extern struct ip_fw *ip_fw_out_chain;
-extern struct ip_fw *ip_fw_fwd_chain;
-extern int ip_fw_in_policy;
-extern int ip_fw_out_policy;
-extern int ip_fw_fwd_policy;
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#include <linux/init.h>
+extern void ip_fw_init(void) __init;
+#else /* 2.0.x */
+extern void ip_fw_init(void);
+#endif /* 2.1.x */
extern int ip_fw_ctl(int, void *, int);
-#endif
-#ifdef CONFIG_IP_ACCT
-extern struct ip_fw *ip_acct_chain;
-extern int ip_acct_ctl(int, void *, int);
-#endif
#ifdef CONFIG_IP_MASQUERADE
extern int ip_masq_ctl(int, void *, int);
#endif
-#ifdef CONFIG_IP_MASQUERADE
-extern int ip_masq_ctl(int, void *, int);
-#endif
-
-extern int ip_fw_chk(struct iphdr *, struct device *, __u16 *, struct ip_fw *, int, int);
-extern void ip_fw_init(void);
#endif /* KERNEL */
-
-
-#endif /* _IP_FW_H */
+#endif /* _IP_FWCHAINS_H */
PROC_NET_DN_L2,
PROC_NET_DN_SKT,
PROC_NET_NETSTAT,
+ PROC_NET_IPFW_CHAINS,
+ PROC_NET_IPFW_CHAIN_NAMES,
PROC_NET_LAST
};
unsigned char *tail; /* Tail pointer */
unsigned char *end; /* End pointer */
void (*destructor)(struct sk_buff *); /* Destruct function */
-
+#ifdef CONFIG_IP_FIREWALL
+ __u32 fwmark; /* Label made by fwchains, used by pktsched */
+#endif
#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
__u32 shapelatency; /* Latency on frame */
__u32 shapeclock; /* Time it should go out */
#define AF_ASH 18 /* Ash */
#define AF_ECONET 19 /* Acorn Econet */
#define AF_ATMSVC 20 /* ATM SVCs */
+#define AF_SNA 22 /* Linux SNA Project (nutters!) */
#define AF_MAX 32 /* For now.. */
/* Protocol families, same as address families. */
#define PF_PACKET AF_PACKET
#define PF_ASH AF_ASH
#define PF_ATMSVC AF_ATMSVC
+#define PF_SNA AF_SNA
#define PF_MAX AF_MAX
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);
-#ifdef CONFIG_IP_ACCT
-extern int ip_acct_output(struct sk_buff *skb);
-#else
-#define ip_acct_output dev_queue_xmit
-#endif
extern void ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*));
extern int ip_do_nat(struct sk_buff *skb);
extern void ip_send_check(struct iphdr *ip);
extern void inet6_rt_notify(int event, struct rt6_info *rt);
-extern void fib6_run_gc(unsigned long dummy);
+extern void fib6_run_gc(unsigned long dummy);
+
+extern void fib6_gc_cleanup(void);
#endif
#endif
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ipv6.h,v 1.10 1998/04/30 16:24:14 freitag Exp $
+ * $Id: ipv6.h,v 1.11 1998/05/07 15:42:46 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
int optname, char *optval,
int *optlen);
+extern void ipv6_packet_init(void);
-extern void ipv6_init(void);
-extern void ipv6_cleanup(void);
-#endif
-#endif
+extern void ipv6_netdev_notif_init(void);
+
+extern void ipv6_packet_cleanup(void);
+
+extern void ipv6_netdev_notif_cleanup(void);
+
+#endif /* __KERNEL__ */
+#endif /* _NET_IPV6_H */
};
-extern void ndisc_init(struct net_proto_family *ops);
+extern int ndisc_init(struct net_proto_family *ops);
+
extern void ndisc_cleanup(void);
extern int ndisc_rcv(struct sk_buff *skb,
/*
* IGMP
*/
-extern void igmp6_init(struct net_proto_family *ops);
+extern int igmp6_init(struct net_proto_family *ops);
+
+extern void igmp6_cleanup(void);
extern int igmp6_event_query(struct sk_buff *skb,
struct icmp6hdr *hdr,
unsigned char node[IPX_NODE_LEN];
#endif
unsigned short type;
-/*
- * To handle asynchronous messages from the NetWare server, we have to
- * know the connection this socket belongs to.
- */
- struct ncp_server *ncp_server;
-
};
#endif
Code Section Bug Report Contact
-------------------+-------------------------------------------
802 [other ] alan@lxorguk.ukuu.org.uk
- [token ring ] pnorton@cts.com
+ [token ring ] p.norton@computer.org
appletalk Jay.Schulist@spacs.k12.wi.us
ax25 g4klx@g4klx.demon.co.uk
core alan@lxorguk.ukuu.org.uk
}
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
+ int rlen;
+
if (link->dumpit == NULL)
link = &(rtnetlink_links[PF_UNSPEC][type]);
atomic_dec(&rtnl_rlockct);
return -1;
}
- skb_pull(skb, NLMSG_ALIGN(nlh->nlmsg_len));
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
+ skb_pull(skb, rlen);
return -1;
}
creds->uid == current->suid) || capable(CAP_SETUID)) &&
((creds->gid == current->gid || creds->gid == current->egid ||
creds->gid == current->sgid) || capable(CAP_SETGID))) {
- return 0;
+ return 0;
}
return -EPERM;
}
skb->ip_summed = 0;
skb->security = 0; /* By default packets are insecure */
skb->dst = NULL;
+#ifdef CONFIG_IP_FIREWALL_CHAINS
+ skb->fwmark = 0;
+#endif
memset(skb->cb, 0, sizeof(skb->cb));
skb->priority = 0;
}
define_bool CONFIG_NETLINK_DEV y
fi
fi
- bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE
bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY
bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
fi
fi
-bool 'IP: accounting' CONFIG_IP_ACCT
if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
bool 'IP: masquerading' CONFIG_IP_MASQUERADE
if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
ip_input.o ip_fragment.o ip_forward.o ip_options.o \
ip_output.o ip_sockglue.o \
tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o\
- raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o ip_fw.o \
+ raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o
IPV4X_OBJS :=
MOD_LIST_NAME := IPV4_MODULES
M_OBJS :=
+ifeq ($(CONFIG_IP_FIREWALL),y)
+IPV4_OBJS += ip_fw.o
+endif
+
ifeq ($(CONFIG_IP_MULTIPLE_TABLES),y)
IPV4_OBJS += fib_rules.o
endif
*
* PF_INET protocol family socket handler.
*
- * Version: $Id: af_inet.c,v 1.72 1998/05/03 14:30:49 alan Exp $
+ * Version: $Id: af_inet.c,v 1.74 1998/05/08 21:06:24 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
/*
* Set the firewalling up
*/
-#if defined(CONFIG_IP_ACCT)||defined(CONFIG_IP_FIREWALL)
+#if defined(CONFIG_IP_FIREWALL)
ip_fw_init();
#endif
+
#ifdef CONFIG_IP_MASQUERADE
ip_masq_init();
#endif
/* linux/net/inet/arp.c
*
- * Version: $Id: arp.c,v 1.65 1998/03/08 20:52:34 davem Exp $
+ * Version: $Id: arp.c,v 1.66 1998/05/08 01:54:55 davem Exp $
*
* Copyright (C) 1994 by Florian La Roche
*
arp_error_report,
neigh_resolve_output,
neigh_connected_output,
- ip_acct_output,
- ip_acct_output
+ dev_queue_xmit,
+ dev_queue_xmit
};
static struct neigh_ops arp_hh_ops =
arp_error_report,
neigh_resolve_output,
neigh_resolve_output,
- ip_acct_output,
- ip_acct_output
+ dev_queue_xmit,
+ dev_queue_xmit
};
static struct neigh_ops arp_direct_ops =
NULL,
NULL,
NULL,
- ip_acct_output,
- ip_acct_output,
- ip_acct_output,
- ip_acct_output
+ dev_queue_xmit,
+ dev_queue_xmit,
+ dev_queue_xmit,
+ dev_queue_xmit
};
#if defined(CONFIG_AX25) || defined(CONFIG_AX25) || \
arp_error_report,
neigh_compat_output,
neigh_compat_output,
- ip_acct_output,
- ip_acct_output,
+ dev_queue_xmit,
+ dev_queue_xmit,
};
#endif
/*
* NET3 IP device support routines.
*
- * Version: $Id: devinet.c,v 1.21 1998/05/03 14:30:52 alan Exp $
+ * Version: $Id: devinet.c,v 1.22 1998/05/08 21:06:26 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
*
* IPv4 Forwarding Information Base: FIB frontend.
*
- * Version: $Id: fib_frontend.c,v 1.9 1998/03/08 20:52:36 davem Exp $
+ * Version: $Id: fib_frontend.c,v 1.10 1998/05/08 21:06:27 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
/*
- * IP firewalling code. This is taken from 4.4BSD. Please note the
- * copyright message below. As per the GPL it must be maintained
- * and the licenses thus do not conflict. While this port is subject
- * to the GPL I also place my modifications under the original
- * license in recognition of the original copyright.
- * -- Alan Cox.
+ * This code is heavily based on the code in ip_fw.c; see that file for
+ * copyrights and attributions. This code is basically GPL.
*
- * $Id: ip_fw.c,v 1.35 1998/04/30 16:29:51 freitag Exp $
- *
- * Ported from BSD to Linux,
- * Alan Cox 22/Nov/1994.
- * Zeroing /proc and other additions
- * Jos Vos 4/Feb/1995.
- * Merged and included the FreeBSD-Current changes at Ugen's request
- * (but hey it's a lot cleaner now). Ugen would prefer in some ways
- * we waited for his final product but since Linux 1.2.0 is about to
- * appear it's not practical - Read: It works, it's not clean but please
- * don't consider it to be his standard of finished work.
- * Alan Cox 12/Feb/1995
- * Porting bidirectional entries from BSD, fixing accounting issues,
- * adding struct ip_fwpkt for checking packets with interface address
- * Jos Vos 5/Mar/1995.
- * Established connections (ACK check), ACK check on bidirectional rules,
- * ICMP type check.
- * Wilfred Mollenvanger 7/7/1995.
- * TCP attack protection.
- * Alan Cox 25/8/95, based on information from bugtraq.
- * ICMP type printk, IP_FW_F_APPEND
- * Bernd Eckenfels 1996-01-31
- * Split blocking chain into input and output chains, add new "insert" and
- * "append" commands to replace semi-intelligent "add" command, let "delete".
- * only delete the first matching entry, use 0xFFFF (0xFF) as ports (ICMP
- * types) when counting packets being 2nd and further fragments.
- * Jos Vos <jos@xos.nl> 8/2/1996.
- * Add support for matching on device names.
- * Jos Vos <jos@xos.nl> 15/2/1996.
- * Transparent proxying support.
- * Willy Konynenberg <willy@xos.nl> 10/5/96.
- * Make separate accounting on incoming and outgoing packets possible.
- * Jos Vos <jos@xos.nl> 18/5/1996.
- * Added trap out of bad frames.
- * Alan Cox <alan@cymru.net> 17/11/1996
- *
- *
- * Masquerading functionality
- *
- * Copyright (c) 1994 Pauline Middelink
- *
- * The pieces which added masquerading functionality are totally
- * my responsibility and have nothing to with the original authors
- * copyright or doing.
- *
- * Parts distributed under GPL.
- *
- * Fixes:
- * Pauline Middelink : Added masquerading.
- * Alan Cox : Fixed an error in the merge.
- * Thomas Quinot : Fixed port spoofing.
- * Alan Cox : Cleaned up retransmits in spoofing.
- * Alan Cox : Cleaned up length setting.
- * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands
- *
- * Juan Jose Ciarlante : Masquerading code moved to ip_masq.c
- * Andi Kleen : Print frag_offsets and the ip flags properly.
- *
- * All the real work was done by .....
- *
- */
-
-
-/*
- * Copyright (c) 1993 Daniel Boulet
- * Copyright (c) 1994 Ugen J.S.Antsilevich
- *
- * Redistribution and use in source forms, with and without modification,
- * are permitted provided that this entire comment appears intact.
- *
- * Redistribution in binary form may occur without any restrictions.
- * Obviously, it would be nice if you gave credit where credit is due
- * but requiring it would be too onerous.
- *
- * This software is provided ``AS IS'' without any warranties of any kind.
+ * 15-Aug-1997: Major changes to allow graphs for firewall rules.
+ * Paul Russell <Paul.Russell@rustcorp.com.au> and
+ * Michael Neuling <Michael.Neuling@rustcorp.com.au>
+ * 24-Aug-1997: Generalised protocol handling (not just TCP/UDP/ICMP).
+ * Added explicit RETURN from chains.
+ * Removed TOS mangling (done in ipchains 1.0.1).
+ * Fixed read & reset bug by reworking proc handling.
+ * Paul Russell <Paul.Russell@rustcorp.com.au>
+ * 28-Sep-1997: Added packet marking for net sched code.
+ * Removed fw_via comparisons: all done on device name now,
+ * similar to changes in ip_fw.c in DaveM's CVS970924 tree.
+ * Paul Russell <Paul.Russell@rustcorp.com.au>
+ * 2-Nov-1997: Moved types across to __u16, etc.
+ * Added inverse flags.
+ * Fixed fragment bug (in args to port_match).
+ * Changed mark to only one flag (MARKABS).
+ * 21-Nov-1997: Added ability to test ICMP code.
+ * 19-Jan-1998: Added wildcard interfaces.
+ * 6-Feb-1998: Merged 2.0 and 2.1 versions.
+ * Initialised ip_masq for 2.0.x version.
+ * Added explicit NETLINK option for 2.1.x version.
+ * Added packet and byte counters for policy matches.
+ * 26-Feb-1998: Fixed race conditions, added SMP support.
+ * 18-Mar-1998: Fix SMP, fix race condition fix.
+ * 1-May-1998: Remove caching of device pointer, added caching
+ * for proc output (no longer order n^2).
*/
#include <linux/config.h>
+
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/config.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <net/sock.h>
#include <net/icmp.h>
#include <linux/netlink.h>
+#include <linux/init.h>
#include <linux/firewall.h>
#include <linux/ip_fw.h>
-#include <linux/init.h>
#ifdef CONFIG_IP_MASQUERADE
#include <net/ip_masq.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+/* Understanding locking in this code: (thanks to Alan Cox for using
+ * little words to explain this to me). -- PR
+ *
+ * In UP, there can be two packets traversing the chains:
+ * 1) A packet from the current userspace context
+ * 2) A packet off the bh handlers (timer or net).
+ *
+ * For SMP (kernel v2.1+), multiply this by # CPUs.
+ *
+ * This means counters and backchains can get corrupted if no precautions
+ * are taken.
+ *
+ * To actually alter a chain on UP, we need only do a cli(), as this will
+ * stop a bh handler firing, as we are in the current userspace context
+ * (coming from a setsockopt()).
+ *
+ * On SMP, we need a write_lock_irqsave(), which is a simple cli() in
+ * UP.
+ *
+ * For backchains and counters, we use an array, indexed by
+ * [smp_processor_id()*2 + !in_interrupt()]; the array is of size
+ * [smp_num_cpus*2]. For v2.0, smp_num_cpus is effectively 1. So,
+ * confident of uniqueness, we modify counters even though we only
+ * have a read lock (to read the counters, you need a write lock,
+ * though). */
+
+/* Why I didn't use straight locking... -- PR
+ *
+ * The backchains can be separated out of the ip_chains structure, and
+ * allocated as needed inside ip_fw_check().
+ *
+ * The counters, however, can't. Trying to lock these means blocking
+ * interrupts every time we want to access them. This would suck HARD
+ * performance-wise. Not locking them leads to possible corruption,
+ * made worse on 32-bit machines (counters are 64-bit). */
+
+/*#define DEBUG_IP_FIREWALL*/
+/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
+/*#define DEBUG_IP_FIREWALL_USER*/
+/*#define DEBUG_IP_FIREWALL_LOCKING*/
+
+#ifdef CONFIG_IP_FIREWALL_NETLINK
+static struct sock *ipfwsk;
+#endif
+
+#define SLOT_NUMBER() (smp_processor_id()*2 + !in_interrupt())
+#define NUM_SLOTS (smp_num_cpus*2)
+
+#define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \
+ + NUM_SLOTS*sizeof(struct ip_reent))
+#define SIZEOF_STRUCT_IP_FW_KERNEL (sizeof(struct ip_fwkernel) \
+ + NUM_SLOTS*sizeof(struct ip_counters))
+
+#ifdef DEBUG_IP_FIREWALL_LOCKING
+static unsigned int fwc_rlocks, fwc_wlocks;
+#define FWC_DEBUG_LOCK(d) \
+do { \
+ FWC_DONT_HAVE_LOCK(d); \
+ d |= (1 << SLOT_NUMBER()); \
+} while (0)
+
+#define FWC_DEBUG_UNLOCK(d) \
+do { \
+ FWC_HAVE_LOCK(d); \
+ d &= ~(1 << SLOT_NUMBER()); \
+} while (0)
+
+#define FWC_DONT_HAVE_LOCK(d) \
+do { \
+ if ((d) & (1 << SLOT_NUMBER())) \
+ printk("%s:%i: Got lock on %i already!\n", \
+ __FILE__, __LINE__, SLOT_NUMBER()); \
+} while(0)
+
+#define FWC_HAVE_LOCK(d) \
+do { \
+ if (!((d) & (1 << SLOT_NUMBER()))) \
+ printk("%s:%i:No lock on %i!\n", \
+ __FILE__, __LINE__, SLOT_NUMBER()); \
+} while (0)
+
+#else
+#define FWC_DEBUG_LOCK(d) do { } while(0)
+#define FWC_DEBUG_UNLOCK(d) do { } while(0)
+#define FWC_DONT_HAVE_LOCK(d) do { } while(0)
+#define FWC_HAVE_LOCK(d) do { } while(0)
+#endif /*DEBUG_IP_FIRWALL_LOCKING*/
+
+#define FWC_READ_LOCK(l) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock(l); } while (0)
+#define FWC_WRITE_LOCK(l) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock(l); } while (0)
+#define FWC_READ_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock_irqsave(l,f); } while (0)
+#define FWC_WRITE_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock_irqsave(l,f); } while (0)
+#define FWC_READ_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock(l); } while (0)
+#define FWC_WRITE_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock(l); } while (0)
+#define FWC_READ_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock_irqrestore(l,f); } while (0)
+#define FWC_WRITE_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock_irqrestore(l,f); } while (0)
+
+struct ip_chain;
+
+struct ip_counters
+{
+ __u64 pcnt, bcnt; /* Packet and byte counters */
+};
+
+struct ip_fwkernel
+{
+ struct ip_fw ipfw;
+ struct ip_fwkernel *next; /* where to go next if current
+ * rule doesn't match */
+ struct ip_chain *branch; /* which branch to jump to if
+ * current rule matches */
+ int simplebranch; /* Use this if branch == NULL */
+ struct ip_counters counters[0]; /* Actually several of these */
+};
+
+struct ip_reent
+{
+ struct ip_chain *prevchain; /* Pointer to referencing chain */
+ struct ip_fwkernel *prevrule; /* Pointer to referencing rule */
+ struct ip_counters counters;
+};
+
+struct ip_chain
+{
+ ip_chainlabel label; /* Defines the label for each block */
+ struct ip_chain *next; /* Pointer to next block */
+ struct ip_fwkernel *chain; /* Pointer to first rule in block */
+ __u32 refcount; /* Number of refernces to block */
+ int policy; /* Default rule for chain. Only *
+ * used in built in chains */
+ struct ip_reent reent[0]; /* Actually several of these */
+};
+
/*
* Implement IP packet firewall
*/
#ifdef DEBUG_IP_FIREWALL
-#define dprintf1(a) printk(a)
-#define dprintf2(a1,a2) printk(a1,a2)
-#define dprintf3(a1,a2,a3) printk(a1,a2,a3)
-#define dprintf4(a1,a2,a3,a4) printk(a1,a2,a3,a4)
+#define dprintf(format, args...) printk(format , ## args)
#else
-#define dprintf1(a)
-#define dprintf2(a1,a2)
-#define dprintf3(a1,a2,a3)
-#define dprintf4(a1,a2,a3,a4)
+#define dprintf(format, args...)
#endif
-#define print_ip(a) printk("%ld.%ld.%ld.%ld",(ntohl(a)>>24)&0xFF,\
- (ntohl(a)>>16)&0xFF,\
- (ntohl(a)>>8)&0xFF,\
- (ntohl(a))&0xFF);
-
-#ifdef DEBUG_IP_FIREWALL
-#define dprint_ip(a) print_ip(a)
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
#else
-#define dprint_ip(a)
+#define duprintf(format, args...)
#endif
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
-
-struct ip_fw *ip_fw_fwd_chain;
-struct ip_fw *ip_fw_in_chain;
-struct ip_fw *ip_fw_out_chain;
-struct ip_fw *ip_acct_chain;
-struct ip_fw *ip_masq_chain;
+/* Lock around ip_fw_chains linked list structure */
+spinlock_t ip_fw_lock = SPIN_LOCK_UNLOCKED;
-static struct ip_fw **chains[] =
- {&ip_fw_fwd_chain, &ip_fw_in_chain, &ip_fw_out_chain, &ip_acct_chain,
- &ip_masq_chain
- };
-#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
-
-#ifdef CONFIG_IP_FIREWALL
-int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
-int ip_fw_in_policy=IP_FW_F_ACCEPT;
-int ip_fw_out_policy=IP_FW_F_ACCEPT;
+/* Head of linked list of fw rules */
+static struct ip_chain *ip_fw_chains;
-static int *policies[] =
- {&ip_fw_fwd_policy, &ip_fw_in_policy, &ip_fw_out_policy};
+#define IP_FW_INPUT_CHAIN ip_fw_chains
+#define IP_FW_FORWARD_CHAIN (ip_fw_chains->next)
+#define IP_FW_OUTPUT_CHAIN (ip_fw_chains->next->next)
-#endif
+/* Returns 1 if the port is matched by the range, 0 otherwise */
+extern inline int port_match(__u16 min, __u16 max, __u16 port,
+ int frag, int invert)
+{
+ if (frag) /* Fragments fail ANY port test. */
+ return (min == 0 && max == 0xFFFF);
+ else return (port >= min && port <= max) ^ invert;
+}
-#ifdef CONFIG_IP_FIREWALL_NETLINK
-struct sock *ipfwsk;
-#endif
+/* Returns whether matches rule or not. */
+static int ip_rule_match(struct ip_fwkernel *f,
+ const char *ifname,
+ struct iphdr *ip,
+ char tcpsyn,
+ __u16 src_port, __u16 dst_port,
+ char isfrag)
+{
+#define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg))
+ /*
+ * This is a bit simpler as we don't have to walk
+ * an interface chain as you do in BSD - same logic
+ * however.
+ */
-/*
- * Returns 1 if the port is matched by the vector, 0 otherwise
- */
+ if (FWINV((ip->saddr&f->ipfw.fw_smsk.s_addr) != f->ipfw.fw_src.s_addr,
+ IP_FW_INV_SRCIP)
+ || FWINV((ip->daddr&f->ipfw.fw_dmsk.s_addr)!=f->ipfw.fw_dst.s_addr,
+ IP_FW_INV_DSTIP)) {
+ dprintf("Source or dest mismatch.\n");
+
+ dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
+ f->ipfw.fw_smsk.s_addr, f->ipfw.fw_src.s_addr,
+ f->ipfw.fw_invflg & IP_FW_INV_SRCIP ? " (INV)" : "");
+ dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
+ f->ipfw.fw_dmsk.s_addr, f->ipfw.fw_dst.s_addr,
+ f->ipfw.fw_invflg & IP_FW_INV_DSTIP ? " (INV)" : "");
+ return 0;
+ }
-extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag)
-{
- if (!nports)
- return 1;
- if ( range_flag )
- {
- if ( portptr[0] <= port && port <= portptr[1] )
- {
- return( 1 );
- }
- nports -= 2;
- portptr += 2;
+ /*
+ * Look for a VIA device match
+ */
+ if (f->ipfw.fw_flg & IP_FW_F_WILDIF) {
+ if (FWINV(strncmp(ifname, f->ipfw.fw_vianame,
+ strlen(f->ipfw.fw_vianame)) != 0,
+ IP_FW_INV_VIA)) {
+ dprintf("Wildcard interface mismatch.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_VIA ? " (INV)" : "");
+ return 0; /* Mismatch */
+ }
}
- while ( nports-- > 0 )
- {
- if ( *portptr++ == port )
- {
- return( 1 );
- }
+ else if (FWINV(strcmp(ifname, f->ipfw.fw_vianame) != 0,
+ IP_FW_INV_VIA)) {
+ dprintf("Interface name does not match.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_VIA
+ ? " (INV)" : "");
+ return 0; /* Mismatch */
+ }
+
+ /*
+ * Ok the chain addresses match.
+ */
+
+ /* If we have a fragment rule but the packet is not a fragment
+ * the we return zero */
+ if (FWINV((f->ipfw.fw_flg&IP_FW_F_FRAG) && !isfrag, IP_FW_INV_FRAG)) {
+ dprintf("Fragment rule but not fragment.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_FRAG ? " (INV)" : "");
+ return 0;
}
- return(0);
-}
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
+ /* Fragment NEVER passes a SYN test, even an inverted one. */
+ if (FWINV((f->ipfw.fw_flg&IP_FW_F_TCPSYN) && !tcpsyn, IP_FW_INV_SYN)
+ || (isfrag && (f->ipfw.fw_flg&IP_FW_F_TCPSYN))) {
+ dprintf("Rule requires SYN and packet has no SYN.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_SYN ? " (INV)" : "");
+ return 0;
+ }
-#ifdef CONFIG_IP_FIREWALL_VERBOSE
+ if (f->ipfw.fw_proto) {
+ /*
+ * Specific firewall - packet's protocol
+ * must match firewall's.
+ */
-/*
- * VERY ugly piece of code which actually makes kernel printf for
- * matching packets.
- */
+ if (FWINV(ip->protocol!=f->ipfw.fw_proto, IP_FW_INV_PROTO)) {
+ dprintf("Packet protocol %hi does not match %hi.%s\n",
+ ip->protocol, f->ipfw.fw_proto,
+ f->ipfw.fw_invflg&IP_FW_INV_PROTO ? " (INV)":"");
+ return 0;
+ }
-static char *chain_name(struct ip_fw *chain, int mode)
-{
- switch (mode) {
- case IP_FW_MODE_ACCT_IN: return "acct in";
- case IP_FW_MODE_ACCT_OUT: return "acct out";
- default:
- if (chain == ip_fw_fwd_chain)
- return "fw-fwd";
- else if (chain == ip_fw_in_chain)
- return "fw-in";
- else
- return "fw-out";
+ /* For non TCP/UDP/ICMP, port range is max anyway. */
+ if (!port_match(f->ipfw.fw_spts[0],
+ f->ipfw.fw_spts[1],
+ src_port, isfrag,
+ !!(f->ipfw.fw_invflg&IP_FW_INV_SRCPT))
+ || !port_match(f->ipfw.fw_dpts[0],
+ f->ipfw.fw_dpts[1],
+ dst_port, isfrag,
+ !!(f->ipfw.fw_invflg
+ &IP_FW_INV_DSTPT))) {
+ dprintf("Port match failed.\n");
+ return 0;
+ }
}
+
+ dprintf("Match succeeded.\n");
+ return 1;
}
-static char *rule_name(struct ip_fw *f, int mode, char *buf)
+static const char *branchname(struct ip_chain *branch,int simplebranch)
{
- if (mode == IP_FW_MODE_ACCT_IN || mode == IP_FW_MODE_ACCT_OUT)
- return "";
-
- if(f->fw_flg&IP_FW_F_ACCEPT) {
- if(f->fw_flg&IP_FW_F_REDIR) {
- sprintf(buf, "acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]);
- return buf;
- } else if(f->fw_flg&IP_FW_F_MASQ)
- return "acc/masq ";
- else
- return "acc ";
- } else if(f->fw_flg&IP_FW_F_ICMPRPL) {
- return "rej ";
- } else {
- return "deny ";
+ if (branch)
+ return branch->label;
+ switch (simplebranch)
+ {
+ case FW_BLOCK: return IP_FW_LABEL_BLOCK;
+ case FW_ACCEPT: return IP_FW_LABEL_ACCEPT;
+ case FW_REJECT: return IP_FW_LABEL_REJECT;
+ case FW_REDIRECT: return IP_FW_LABEL_REDIRECT;
+ case FW_MASQUERADE: return IP_FW_LABEL_MASQUERADE;
+ case FW_SKIP: return "-";
+ case FW_SKIP+1: return IP_FW_LABEL_RETURN;
+ default:
+ return "UNKNOWN";
}
}
-static void print_packet(struct iphdr *ip,
- u16 src_port, u16 dst_port, u16 icmp_type,
- char *chain, char *rule, char *devname)
+/*
+ * VERY ugly piece of code which actually
+ * makes kernel printf for matching packets...
+ */
+static void dump_packet(const struct iphdr *ip,
+ const char *ifname,
+ struct ip_fwkernel *f,
+ const ip_chainlabel chainlabel,
+ __u16 src_port,
+ __u16 dst_port)
{
__u32 *opt = (__u32 *) (ip + 1);
int opti;
- __u16 foff = ntohs(ip->frag_off);
-
- printk(KERN_INFO "IP %s %s%s", chain, rule, devname);
-
- switch(ip->protocol)
+
+ if (f)
{
- case IPPROTO_TCP:
- printk(" TCP ");
- break;
- case IPPROTO_UDP:
- printk(" UDP ");
- break;
- case IPPROTO_ICMP:
- printk(" ICMP/%d ", icmp_type);
- break;
- default:
- printk(" PROTO=%d ", ip->protocol);
- break;
+ printk(KERN_INFO "Packet log: %s ",chainlabel);
+
+ printk("%s ",branchname(f->branch,f->simplebranch));
+ if (f->simplebranch==FW_REDIRECT)
+ printk("%d ",f->ipfw.fw_redirpt);
}
- print_ip(ip->saddr);
- if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
- printk(":%hu", src_port);
- printk(" ");
- print_ip(ip->daddr);
- if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
- printk(":%hu", dst_port);
- printk(" L=%hu S=0x%2.2hX I=%hu FO=0x%4.4hX T=%hu",
+
+ printk("%s PROTO=%d %ld.%ld.%ld.%ld:%hu %ld.%ld.%ld.%ld:%hu"
+ " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
+ ifname, ip->protocol,
+ (ntohl(ip->saddr)>>24)&0xFF,
+ (ntohl(ip->saddr)>>16)&0xFF,
+ (ntohl(ip->saddr)>>8)&0xFF,
+ (ntohl(ip->saddr))&0xFF,
+ src_port,
+ (ntohl(ip->daddr)>>24)&0xFF,
+ (ntohl(ip->daddr)>>16)&0xFF,
+ (ntohl(ip->daddr)>>8)&0xFF,
+ (ntohl(ip->daddr))&0xFF,
+ dst_port,
ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
- foff & IP_OFFSET, ip->ttl);
- if (foff & IP_DF) printk(" DF=1");
- if (foff & IP_MF) printk(" MF=1");
+ ntohs(ip->frag_off), ip->ttl);
+
for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
printk(" O=0x%8.8X", *opt++);
- printk("\n");
+ printk("\n");
+}
+
+/* function for checking chain labels for user space. Makes sure that
+ * there are no special characters in the string */
+static int check_label(ip_chainlabel label)
+{
+ unsigned int i;
+
+ for (i = 0; i < IP_FW_MAX_LABEL_LENGTH + 1 && label[i]; i++)
+ if (label[i] <= ' ')
+ return 0;
+ if (i == IP_FW_MAX_LABEL_LENGTH+1)
+ return 0;
+ return 1;
+}
+
+/* This function returns a pointer to the first chain with a label
+ * that matches the one given. */
+static struct ip_chain *find_label(ip_chainlabel label)
+{
+ struct ip_chain *tmp;
+ FWC_HAVE_LOCK(fwc_rlocks | fwc_wlocks);
+ for (tmp = ip_fw_chains; tmp; tmp = tmp->next)
+ if (strcmp(tmp->label,label) == 0)
+ break;
+ return tmp;
+}
+
+/* This function returns a boolean which when true sets answer to one
+ of the FW_*. */
+static int find_special(ip_chainlabel label, int *answer)
+{
+ if (label[0] == '\0') {
+ *answer = FW_SKIP; /* => pass-through rule */
+ return 1;
+ } else if (strcmp(label,IP_FW_LABEL_ACCEPT) == 0) {
+ *answer = FW_ACCEPT;
+ return 1;
+ } else if (strcmp(label,IP_FW_LABEL_BLOCK) == 0) {
+ *answer = FW_BLOCK;
+ return 1;
+ } else if (strcmp(label,IP_FW_LABEL_REJECT) == 0) {
+ *answer = FW_REJECT;
+ return 1;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ } else if (strcmp(label,IP_FW_LABEL_REDIRECT) == 0) {
+ *answer = FW_REDIRECT;
+ return 1;
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+ } else if (strcmp(label,IP_FW_LABEL_MASQUERADE) == 0) {
+ *answer = FW_MASQUERADE;
+ return 1;
+#endif
+ } else if (strcmp(label, IP_FW_LABEL_RETURN) == 0) {
+ *answer = FW_SKIP+1;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* This function cleans up the prevchain and prevrule. If the verbose
+ * flag is set then he names of the chains will be printed as it
+ * cleans up. */
+static void cleanup(struct ip_chain *chain,
+ const int verbose,
+ unsigned int slot)
+{
+ struct ip_chain *tmpchain = chain->reent[slot].prevchain;
+ if (verbose)
+ printk(KERN_ERR "Chain backtrace: ");
+ while (tmpchain) {
+ if (verbose)
+ printk("%s<-",chain->label);
+ chain->reent[slot].prevchain = NULL;
+ chain = tmpchain;
+ tmpchain = chain->reent[slot].prevchain;
+ }
+ if (verbose)
+ printk("%s\n",chain->label);
}
+
+static inline void
+ip_fw_domatch(struct ip_fwkernel *f,
+ const struct iphdr *ip,
+ const char *rif,
+ const ip_chainlabel label,
+ struct sk_buff *skb,
+ unsigned int slot,
+ __u16 src_port, __u16 dst_port)
+{
+ f->counters[slot].bcnt+=ntohs(ip->tot_len);
+ f->counters[slot].pcnt++;
+ if (f->ipfw.fw_flg & IP_FW_F_PRN) {
+ dump_packet(ip,rif,f,label,src_port,dst_port);
+ }
+/* This functionality is useless in stock 2.0.x series, but we don't
+ * discard the mark thing altogether, to avoid breaking ipchains (and,
+ * more importantly, the ipfwadm wrapper) --PR */
+ if (f->ipfw.fw_flg & IP_FW_F_MARKABS)
+ skb->fwmark = f->ipfw.fw_mark;
+ else
+ skb->fwmark+=f->ipfw.fw_mark;
+#ifdef CONFIG_IP_FIREWALL_NETLINK
+ if (f->ipfw.fw_flg & IP_FW_F_NETLINK) {
+ size_t len = min(f->ipfw.fw_outputsize, ntohs(ip->tot_len))
+ + sizeof(skb->fwmark) + IFNAMSIZ;
+ struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC);
+
+ duprintf("Sending packet out NETLINK (length = %u).\n",
+ (unsigned int)len);
+ if (outskb) {
+ /* Prepend mark & interface */
+ skb_put(outskb, len);
+ *((__u32 *)outskb->data) = skb->fwmark;
+ strcpy(outskb->data+sizeof(__u32), rif);
+ memcpy(outskb->data+sizeof(__u32)+IFNAMSIZ, ip,
+ len-(sizeof(__u32)+IFNAMSIZ));
+ netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL);
+ }
+ else duprintf("netlink post failed - alloc_skb failed!\n");
+ }
#endif
+}
/*
* Returns one of the generic firewall policies, like FW_ACCEPT.
- * Also does accounting so you can feed it the accounting chain.
*
- * The modes is either IP_FW_MODE_FW (normal firewall mode),
- * IP_FW_MODE_ACCT_IN or IP_FW_MODE_ACCT_OUT (accounting mode,
- * steps through the entire chain and handles fragments
- * differently), or IP_FW_MODE_CHK (handles user-level check,
- * counters are not updated).
+ * The testing is either false for normal firewall mode or true for
+ * user checking mode (counters are not updated, TOS & mark not done).
*/
-
-
-int ip_fw_chk(struct iphdr *ip, struct device *rif, __u16 *redirport, struct ip_fw *chain, int policy, int mode)
+static int
+ip_fw_check(struct iphdr *ip,
+ const char *rif,
+ __u16 *redirport,
+ struct ip_chain *chain,
+ struct sk_buff *skb,
+ unsigned int slot,
+ int testing)
{
- struct ip_fw *f;
struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
struct udphdr *udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
struct icmphdr *icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
__u32 src, dst;
- __u16 src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF;
- unsigned short f_prt=0, prt;
- char notcpsyn=0, notcpack=0, match;
- unsigned short offset;
- int answer;
- unsigned char tosand, tosxor;
-
- /*
- * If the chain is empty follow policy. The BSD one
- * accepts anything giving you a time window while
- * flushing and rebuilding the tables.
- */
-
- src = ip->saddr;
- dst = ip->daddr;
-
- /*
- * This way we handle fragmented packets.
- * we ignore all fragments but the first one
- * so the whole packet can't be reassembled.
- * This way we relay on the full info which
- * stored only in first packet.
- *
- * Note that this theoretically allows partial packet
- * spoofing. Not very dangerous but paranoid people may
- * wish to play with this. It also allows the so called
- * "fragment bomb" denial of service attack on some types
- * of system.
- */
+ __u16 src_port = 0xFFFF, dst_port = 0xFFFF;
+ char tcpsyn=0;
+ __u16 offset;
+ unsigned char oldtos;
+ struct ip_fwkernel *f;
+ int ret = FW_SKIP+2;
+
+ /* We handle fragments by dealing with the first fragment as
+ * if it was a normal packet. All other fragments are treated
+ * normally, except that they will NEVER match rules that ask
+ * things we don't know, ie. tcp syn flag or ports). If the
+ * rule is also a fragment-specific rule, non-fragments won't
+ * match it. */
offset = ntohs(ip->frag_off) & IP_OFFSET;
* checks.
*/
- if (offset == 1 && ip->protocol == IPPROTO_TCP)
- return FW_BLOCK;
-
- if (offset!=0 && !(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)) &&
- (ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP ||
- ip->protocol == IPPROTO_ICMP))
- return FW_ACCEPT;
-
- /*
- * Header fragment for TCP is too small to check the bits.
- */
-
- if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len))
+ if (offset == 1 && ip->protocol == IPPROTO_TCP) {
+ if (!testing && net_ratelimit()) {
+ printk("Suspect TCP fragment.\n");
+ dump_packet(ip,rif,NULL,NULL,0,0);
+ }
return FW_BLOCK;
-
- /*
- * Too short.
- *
- * But only too short for a packet with ports...
+ }
+
+ /* Check for too-small packets (not non-first fragments).
+ * For each protocol, we assume that we can get the required
+ * information, eg. port number or ICMP type. If this fails,
+ * reject it.
+ *
+ * Sizes might as well be rounded up to 8 here, since either
+ * there are more fragments to come (which must be on 8-byte
+ * boundaries), or this is a bogus packet anyway.
*/
-
- else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP))
- return FW_BLOCK;
-
+ if (offset == 0) {
+ unsigned int size_req;
+ switch (ip->protocol) {
+ case IPPROTO_TCP:
+ /* Don't care about things past flags word */
+ size_req = 16;
+ break;
+
+ case IPPROTO_UDP:
+ case IPPROTO_ICMP:
+ size_req = 8;
+ break;
+
+ default:
+ size_req = 0;
+ }
+ if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req) {
+ if (!testing && net_ratelimit()) {
+ printk("Packet too short.\n");
+ dump_packet(ip,rif,NULL,NULL,0,0);
+ }
+ return FW_BLOCK;
+ }
+ }
+
src = ip->saddr;
dst = ip->daddr;
-
+ oldtos = ip->tos;
+
/*
* If we got interface from which packet came
* we can use the address directly. This is unlike
* devices instead.
*/
- dprintf1("Packet ");
+ dprintf("Packet ");
switch(ip->protocol)
{
case IPPROTO_TCP:
- dprintf1("TCP ");
- /* ports stay 0xFFFF if it is not the first fragment */
+ dprintf("TCP ");
if (!offset) {
src_port=ntohs(tcp->source);
dst_port=ntohs(tcp->dest);
- if(!tcp->ack && !tcp->rst)
- /* We do NOT have ACK, value TRUE */
- notcpack=1;
- if(!tcp->syn || !notcpack)
- /* We do NOT have SYN, value TRUE */
- notcpsyn=1;
+
+ /* Connection initilisation can only
+ * be made when the syn bit is set and
+ * neither of the ack or reset is
+ * set. */
+ if(tcp->syn && !(tcp->ack || tcp->rst))
+ tcpsyn=1;
}
- prt=IP_FW_F_TCP;
break;
case IPPROTO_UDP:
- dprintf1("UDP ");
- /* ports stay 0xFFFF if it is not the first fragment */
+ dprintf("UDP ");
if (!offset) {
src_port=ntohs(udp->source);
dst_port=ntohs(udp->dest);
}
- prt=IP_FW_F_UDP;
break;
case IPPROTO_ICMP:
- /* icmp_type stays 255 if it is not the first fragment */
- if (!offset)
- icmp_type=(__u16)(icmp->type);
- dprintf2("ICMP:%d ",icmp_type);
- prt=IP_FW_F_ICMP;
+ if (!offset) {
+ src_port=(__u16)icmp->type;
+ dst_port=(__u16)icmp->code;
+ }
+ dprintf("ICMP ");
break;
default:
- dprintf2("p=%d ",ip->protocol);
- prt=IP_FW_F_ALL;
+ dprintf("p=%d ",ip->protocol);
break;
}
#ifdef DEBUG_IP_FIREWALL
- dprint_ip(ip->saddr);
+ print_ip(ip->saddr);
- if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
- /* This will print 65535 when it is not the first fragment! */
- dprintf2(":%d ", src_port);
- dprint_ip(ip->daddr);
- if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
- /* This will print 65535 when it is not the first fragment! */
- dprintf2(":%d ",dst_port);
- dprintf1("\n");
-#endif
-
- for (f=chain;f;f=f->fw_next)
- {
- /*
- * This is a bit simpler as we don't have to walk
- * an interface chain as you do in BSD - same logic
- * however.
- */
-
- /*
- * Match can become 0x01 (a "normal" match was found),
- * 0x02 (a reverse match was found), and 0x03 (the
- * IP addresses match in both directions).
- * Now we know in which direction(s) we should look
- * for a match for the TCP/UDP ports. Both directions
- * might match (e.g., when both addresses are on the
- * same network for which an address/mask is given), but
- * the ports might only match in one direction.
- * This was obviously wrong in the original BSD code.
- */
- match = 0x00;
+ if (offset)
+ dprintf(":fragment (%i) ", ((int)offset)<<2);
+ else if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP
+ || ip->protocol==IPPROTO_ICMP)
+ dprintf(":%hu:%hu", src_port, dst_port);
+ dprintf("\n");
+#endif
- if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
- && (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
- /* normal direction */
- match |= 0x01;
+ if (!testing) FWC_READ_LOCK(&ip_fw_lock);
+ else FWC_HAVE_LOCK(fwc_rlocks);
+
+ f = chain->chain;
+ do {
+ for (; f; f = f->next) {
+ if (ip_rule_match(f,rif,ip,
+ tcpsyn,src_port,dst_port,offset)) {
+ if (!testing)
+ ip_fw_domatch(f, ip, rif, chain->label, skb,
+ slot, src_port,dst_port);
+ break;
+ }
+ }
+ if (f) {
+ if (f->branch) {
+ /* Do sanity check to see if we have
+ * already set prevchain and if so we
+ * must be in a loop */
+ if (f->branch->reent[slot].prevchain) {
+ if (!testing) {
+ printk(KERN_ERR
+ "IP firewall: "
+ "Loop detected "
+ "at `%s'.\n",
+ f->branch->label);
+ cleanup(chain, 1, slot);
+ ret = FW_BLOCK;
+ } else {
+ cleanup(chain, 0, slot);
+ ret = FW_SKIP+1;
+ }
+ }
+ else {
+ f->branch->reent[slot].prevchain
+ = chain;
+ f->branch->reent[slot].prevrule
+ = f->next;
+ chain = f->branch;
+ f = chain->chain;
+ }
+ }
+ else if (f->simplebranch == FW_SKIP)
+ f = f->next;
+ else if (f->simplebranch == FW_SKIP+1) {
+ /* Just like falling off the chain */
+ goto fall_off_chain;
+ }
+ else {
+ cleanup(chain, 0, slot);
+ ret = f->simplebranch;
+ }
+ } /* f == NULL */
+ else {
+ fall_off_chain:
+ if (chain->reent[slot].prevchain) {
+ struct ip_chain *tmp = chain;
+ f = chain->reent[slot].prevrule;
+ chain = chain->reent[slot].prevchain;
+ tmp->reent[slot].prevchain = NULL;
+ }
+ else {
+ ret = chain->policy;
+ if (!testing) {
+ chain->reent[slot].counters.pcnt++;
+ chain->reent[slot].counters.bcnt
+ += ntohs(ip->tot_len);
+ }
+ }
+ }
+ } while (ret == FW_SKIP+2);
- if ((f->fw_flg & IP_FW_F_BIDIR) &&
- (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
- && (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
- /* reverse direction */
- match |= 0x02;
+ if (!testing) FWC_READ_UNLOCK(&ip_fw_lock);
- if (!match)
- continue;
+ /* Recalculate checksum if not going to reject, and TOS changed. */
+ if (ip->tos != oldtos
+ && ret != FW_REJECT && ret != FW_BLOCK
+ && !testing)
+ ip_send_check(ip);
- /*
- * Look for a VIA device match
- */
- if(f->fw_viadev)
- {
- if(rif!=f->fw_viadev)
- continue; /* Mismatch */
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (ret == FW_REDIRECT && redirport) {
+ if ((*redirport = htons(f->ipfw.fw_redirpt)) == 0) {
+ /* Wildcard redirection.
+ * Note that redirport will become
+ * 0xFFFF for non-TCP/UDP packets.
+ */
+ *redirport = htons(dst_port);
}
+ }
+#endif
- /* This looks stupid, because we scan almost static
- list, searching for static key. However, this way seems
- to be only reasonable way of handling fw_via rules
- (btw bsd makes the same thing).
+#ifdef DEBUG_ALLOW_ALL
+ return (testing ? ret : FW_ACCEPT);
+#else
+ return ret;
+#endif
+}
- It will not affect performance if you will follow
- the following simple rules:
+/* Must have write lock & interrupts off for any of these */
- - if inteface is aliased, ALWAYS specify fw_viadev,
- so that previous check will guarantee, that we will
- not waste time when packet arrive on another interface.
+/* This function sets all the byte counters in a chain to zero. The
+ * input is a pointer to the chain required for zeroing */
+static int zero_fw_chain(struct ip_chain *chainptr)
+{
+ struct ip_fwkernel *i;
- - avoid using fw_via.s_addr if fw_via.s_addr is owned
- by an aliased interface.
+ FWC_HAVE_LOCK(fwc_wlocks);
+ for (i = chainptr->chain; i; i = i->next)
+ memset(i->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS);
+ return 0;
+}
- --ANK
- */
- if (f->fw_via.s_addr && rif) {
- struct in_ifaddr *ifa;
+static int clear_fw_chain(struct ip_chain *chainptr)
+{
+ struct ip_fwkernel *i= chainptr->chain;
- if (rif->ip_ptr == NULL)
- continue; /* Mismatch */
+ FWC_HAVE_LOCK(fwc_wlocks);
+ chainptr->chain=NULL;
- for (ifa = ((struct in_device*)(rif->ip_ptr))->ifa_list;
- ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_local == f->fw_via.s_addr)
- goto ifa_ok;
- }
- continue; /* Mismatch */
+ while (i) {
+ struct ip_fwkernel *tmp = i->next;
+ if (i->branch)
+ i->branch->refcount--;
+ kfree(i);
+ i = tmp;
+ }
+ return 0;
+}
- ifa_ok:
- }
+static int replace_in_chain(struct ip_chain *chainptr,
+ struct ip_fwkernel *frwl,
+ __u32 position)
+{
+ struct ip_fwkernel *f = chainptr->chain;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
- /*
- * Ok the chain addresses match.
- */
+ while (--position && f != NULL) f = f->next;
+ if (f == NULL)
+ return EINVAL;
+
+ if (f->branch) f->branch->refcount--;
+ if (frwl->branch) frwl->branch->refcount++;
-#ifdef CONFIG_IP_ACCT
- /*
- * See if we're in accounting mode and only want to
- * count incoming or outgoing packets.
- */
+ frwl->next = f->next;
+ memcpy(f,frwl,sizeof(struct ip_fwkernel));
+ kfree(frwl);
+ return 0;
+}
- if (mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT) &&
- ((mode == IP_FW_MODE_ACCT_IN && f->fw_flg&IP_FW_F_ACCTOUT) ||
- (mode == IP_FW_MODE_ACCT_OUT && f->fw_flg&IP_FW_F_ACCTIN)))
- continue;
+static int append_to_chain(struct ip_chain *chainptr, struct ip_fwkernel *rule)
+{
+ struct ip_fwkernel *i;
-#endif
- /*
- * For all non-TCP packets and/or non-first fragments,
- * notcpsyn and notcpack will always be FALSE,
- * so the IP_FW_F_TCPSYN and IP_FW_F_TCPACK flags
- * are actually ignored for these packets.
- */
-
- if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
- continue;
+ FWC_HAVE_LOCK(fwc_wlocks);
+ /* Special case if no rules already present */
+ if (chainptr->chain == NULL) {
- if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
- continue;
+ /* If pointer writes are atomic then turning off
+ * interupts is not necessary. */
+ chainptr->chain = rule;
+ if (rule->branch) rule->branch->refcount++;
+ return 0;
+ }
- f_prt=f->fw_flg&IP_FW_F_KIND;
- if (f_prt!=IP_FW_F_ALL)
- {
- /*
- * Specific firewall - packet's protocol
- * must match firewall's.
- */
+ /* Find the rule before the end of the chain */
+ for (i = chainptr->chain; i->next; i = i->next);
+ i->next = rule;
+ if (rule->branch) rule->branch->refcount++;
+ return 0;
+}
- if(prt!=f_prt)
- continue;
-
- if((prt==IP_FW_F_ICMP &&
- ! port_match(&f->fw_pts[0], f->fw_nsp,
- icmp_type,f->fw_flg&IP_FW_F_SRNG)) ||
- !(prt==IP_FW_F_ICMP || ((match & 0x01) &&
- port_match(&f->fw_pts[0], f->fw_nsp, src_port,
- f->fw_flg&IP_FW_F_SRNG) &&
- port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
- f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) &&
- port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
- f->fw_flg&IP_FW_F_SRNG) &&
- port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
- f->fw_flg&IP_FW_F_DRNG))))
- {
- continue;
- }
- }
+/* This function inserts a rule at the position of position in the
+ * chain refenced by chainptr. If position is 1 then this rule will
+ * become the new rule one. */
+static int insert_in_chain(struct ip_chain *chainptr,
+ struct ip_fwkernel *frwl,
+ __u32 position)
+{
+ struct ip_fwkernel *f = chainptr->chain;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ /* special case if the position is number 1 */
+ if (position == 1) {
+ frwl->next = chainptr->chain;
+ if (frwl->branch) frwl->branch->refcount++;
+ chainptr->chain = frwl;
+ return 0;
+ }
+ position--;
+ while (--position && f != NULL) f = f->next;
+ if (f == NULL)
+ return EINVAL;
+ if (frwl->branch) frwl->branch->refcount++;
+ frwl->next = f->next;
+
+ f->next = frwl;
+ return 0;
+}
-#ifdef CONFIG_IP_FIREWALL_VERBOSE
- if (f->fw_flg & IP_FW_F_PRN)
- {
- char buf[16];
+/* This function deletes the a rule from a given rulenum and chain.
+ * With rulenum = 1 is the first rule is deleted. */
- print_packet(ip, src_port, dst_port, icmp_type,
- chain_name(chain, mode),
- rule_name(f, mode, buf),
- rif ? rif->name : "-");
- }
-#endif
- if (mode != IP_FW_MODE_CHK) {
- f->fw_bcnt+=ntohs(ip->tot_len);
- f->fw_pcnt++;
- }
- if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)))
- break;
- } /* Loop */
+static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum)
+{
+ struct ip_fwkernel *i=chainptr->chain,*tmp;
- if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT))) {
+ FWC_HAVE_LOCK(fwc_wlocks);
+
+ if (!chainptr->chain)
+ return ENOENT;
+
+ /* Need a special case for the first rule */
+ if (rulenum == 1) {
+ /* store temp to allow for freeing up of memory */
+ tmp = chainptr->chain;
+ if (chainptr->chain->branch) chainptr->chain->branch->refcount--;
+ chainptr->chain = chainptr->chain->next;
+ kfree(tmp); /* free memory that is now unused */
+ } else {
+ rulenum--;
+ while (--rulenum && i->next ) i = i->next;
+ if (!i->next)
+ return ENOENT;
+ tmp = i->next;
+ if (i->next->branch)
+ i->next->branch->refcount--;
+ i->next = i->next->next;
+ kfree(tmp);
+ }
+ return 0;
+}
- /*
- * We rely on policy defined in the rejecting entry or, if no match
- * was found, we rely on the general policy variable for this type
- * of firewall.
- */
- if (f!=NULL) {
- policy=f->fw_flg;
- tosand=f->fw_tosand;
- tosxor=f->fw_tosxor;
- } else {
- tosand=0xFF;
- tosxor=0x00;
- }
+/* This function deletes the a rule from a given rule and chain.
+ * The rule that is deleted is the first occursance of that rule. */
+static int del_rule_from_chain(struct ip_chain *chainptr,
+ struct ip_fwkernel *frwl)
+{
+ struct ip_fwkernel *ltmp,*ftmp = chainptr->chain ;
+ int was_found;
- if (policy&IP_FW_F_ACCEPT) {
- /* Adjust priority and recompute checksum */
- __u8 old_tos = ip->tos;
- ip->tos = (old_tos & tosand) ^ tosxor;
- if (ip->tos != old_tos)
- ip_send_check(ip);
-#ifdef CONFIG_IP_TRANSPARENT_PROXY
- if (policy&IP_FW_F_REDIR) {
- if (redirport)
- if ((*redirport = htons(f->fw_pts[f->fw_nsp+f->fw_ndp])) == 0) {
- /* Wildcard redirection.
- * Note that redirport will become
- * 0xFFFF for non-TCP/UDP packets.
- */
- *redirport = htons(dst_port);
- }
- answer = FW_REDIRECT;
- } else
+ FWC_HAVE_LOCK(fwc_wlocks);
+
+ /* Sure, we should compare marks, but since the `ipfwadm'
+ * script uses it for an unholy hack... well, life is easier
+ * this way. We also mask it out of the flags word. --PR */
+ for (ltmp=NULL, was_found=0;
+ !was_found && ftmp != NULL;
+ ltmp = ftmp,ftmp = ftmp->next) {
+ if (ftmp->ipfw.fw_src.s_addr!=frwl->ipfw.fw_src.s_addr
+ || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr
+ || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr
+ || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr
+#if 0
+ || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg
+#else
+ || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS)
+ != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS))
#endif
-#ifdef CONFIG_IP_MASQUERADE
- if (policy&IP_FW_F_MASQ)
- answer = FW_MASQUERADE;
- else
+ || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg
+ || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto
+#if 0
+ || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark
#endif
- answer = FW_ACCEPT;
-
- } else if(policy&IP_FW_F_ICMPRPL)
- answer = FW_REJECT;
- else
- answer = FW_BLOCK;
+ || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt
+ || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0]
+ || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1]
+ || ftmp->ipfw.fw_dpts[0]!=frwl->ipfw.fw_dpts[0]
+ || ftmp->ipfw.fw_dpts[1]!=frwl->ipfw.fw_dpts[1]
+ || ftmp->ipfw.fw_outputsize!=frwl->ipfw.fw_outputsize) {
+ duprintf("del_rule_from_chain: mismatch:"
+ "src:%u/%u dst:%u/%u smsk:%u/%u dmsk:%u/%u "
+ "flg:%hX/%hX invflg:%hX/%hX proto:%u/%u "
+ "mark:%u/%u "
+ "ports:%hu-%hu/%hu-%hu %hu-%hu/%hu-%hu "
+ "outputsize:%hu-%hu\n",
+ ftmp->ipfw.fw_src.s_addr,
+ frwl->ipfw.fw_src.s_addr,
+ ftmp->ipfw.fw_dst.s_addr,
+ frwl->ipfw.fw_dst.s_addr,
+ ftmp->ipfw.fw_smsk.s_addr,
+ frwl->ipfw.fw_smsk.s_addr,
+ ftmp->ipfw.fw_dmsk.s_addr,
+ frwl->ipfw.fw_dmsk.s_addr,
+ ftmp->ipfw.fw_flg,
+ frwl->ipfw.fw_flg,
+ ftmp->ipfw.fw_invflg,
+ frwl->ipfw.fw_invflg,
+ ftmp->ipfw.fw_proto,
+ frwl->ipfw.fw_proto,
+ ftmp->ipfw.fw_mark,
+ frwl->ipfw.fw_mark,
+ ftmp->ipfw.fw_spts[0],
+ frwl->ipfw.fw_spts[0],
+ ftmp->ipfw.fw_spts[1],
+ frwl->ipfw.fw_spts[1],
+ ftmp->ipfw.fw_dpts[0],
+ frwl->ipfw.fw_dpts[0],
+ ftmp->ipfw.fw_dpts[1],
+ frwl->ipfw.fw_dpts[1],
+ ftmp->ipfw.fw_outputsize,
+ frwl->ipfw.fw_outputsize);
+ continue;
+ }
-#ifdef CONFIG_IP_FIREWALL_NETLINK
- if((policy&IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK))
- {
- struct sk_buff *skb=alloc_skb(128, GFP_ATOMIC);
- if(skb)
- {
- int len=min(128,ntohs(ip->tot_len));
- skb_put(skb,len);
- memcpy(skb->data,ip,len);
- if(netlink_post(NETLINK_FIREWALL, skb))
- kfree_skb(skb);
- }
+ if (strncmp(ftmp->ipfw.fw_vianame,
+ frwl->ipfw.fw_vianame,
+ IFNAMSIZ)) {
+ duprintf("del_rule_from_chain: if mismatch: %s/%s\n",
+ ftmp->ipfw.fw_vianame,
+ frwl->ipfw.fw_vianame);
+ continue;
+ }
+ if (ftmp->branch != frwl->branch) {
+ duprintf("del_rule_from_chain: branch mismatch: "
+ "%s/%s\n",
+ ftmp->branch?ftmp->branch->label:"(null)",
+ frwl->branch?frwl->branch->label:"(null)");
+ continue;
+ }
+ if (ftmp->branch == NULL
+ && ftmp->simplebranch != frwl->simplebranch) {
+ duprintf("del_rule_from_chain: simplebranch mismatch: "
+ "%i/%i\n",
+ ftmp->simplebranch, frwl->simplebranch);
+ continue;
}
-#endif
- return answer;
- } else
- /* we're doing accounting, always ok */
+ was_found = 1;
+ if (ftmp->branch)
+ ftmp->branch->refcount--;
+ if (ltmp)
+ ltmp->next = ftmp->next;
+ else
+ chainptr->chain = ftmp->next;
+ kfree(ftmp);
+ break;
+ }
+
+ if (was_found)
return 0;
-}
-
-
-static void zero_fw_chain(struct ip_fw *chainptr)
-{
- struct ip_fw *ctmp=chainptr;
- while(ctmp)
- {
- ctmp->fw_pcnt=0L;
- ctmp->fw_bcnt=0L;
- ctmp=ctmp->fw_next;
+ else {
+ duprintf("del_rule_from_chain: no matching rule found\n");
+ return EINVAL;
}
}
-static void free_fw_chain(struct ip_fw *volatile* chainptr)
+/* This function takes the label of a chain and deletes the first
+ * chain with that name. No special cases required for the built in
+ * chains as they have their refcount initilised to 1 so that they are
+ * never deleted. */
+static int del_chain(ip_chainlabel label)
{
- unsigned long flags;
- save_flags(flags);
- cli();
- while ( *chainptr != NULL )
- {
- struct ip_fw *ftmp;
- ftmp = *chainptr;
- *chainptr = ftmp->fw_next;
- kfree_s(ftmp,sizeof(*ftmp));
- }
- restore_flags(flags);
-}
+ struct ip_chain *tmp,*tmp2;
-/* Volatiles to keep some of the compiler versions amused */
+ FWC_HAVE_LOCK(fwc_wlocks);
+ /* Corner case: return EBUSY not ENOENT for first elem ("input") */
+ if (strcmp(label, ip_fw_chains->label) == 0)
+ return EBUSY;
-static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
-{
- struct ip_fw *ftmp;
- unsigned long flags;
+ for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next)
+ if(strcmp(tmp->next->label,label) == 0)
+ break;
- save_flags(flags);
+ tmp2 = tmp->next;
+ if (!tmp2)
+ return ENOENT;
- ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
- if ( ftmp == NULL )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: malloc said no\n");
-#endif
- return( ENOMEM );
- }
+ if (tmp2->refcount)
+ return EBUSY;
- memcpy(ftmp, frwl, len);
- /*
- * Allow the more recent "minimise cost" flag to be
- * set. [Rob van Nieuwkerk]
- */
- ftmp->fw_tosand |= 0x01;
- ftmp->fw_tosxor &= 0xFE;
- ftmp->fw_pcnt=0L;
- ftmp->fw_bcnt=0L;
-
- cli();
-
- if ((ftmp->fw_vianame)[0]) {
- if (!(ftmp->fw_viadev = dev_get(ftmp->fw_vianame)))
- ftmp->fw_viadev = (struct device *) -1;
- } else
- ftmp->fw_viadev = NULL;
-
- ftmp->fw_next = *chainptr;
- *chainptr=ftmp;
- restore_flags(flags);
- return(0);
+ if (tmp2->chain)
+ return ENOTEMPTY;
+
+ tmp->next = tmp2->next;
+ kfree(tmp2);
+ return 0;
}
-static int append_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
+/* This is a function to initilise a chain. Built in rules start with
+ * refcount = 1 so that they cannot be deleted. User defined rules
+ * start with refcount = 0 so they can be deleted. */
+static struct ip_chain *ip_init_chain(ip_chainlabel name,
+ __u32 ref,
+ int policy)
{
- struct ip_fw *ftmp;
- struct ip_fw *chtmp=NULL;
- struct ip_fw *volatile chtmp_prev=NULL;
- unsigned long flags;
-
- save_flags(flags);
-
- ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
- if ( ftmp == NULL )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: malloc said no\n");
-#endif
- return( ENOMEM );
+ unsigned int i;
+ struct ip_chain *label
+ = kmalloc(SIZEOF_STRUCT_IP_CHAIN, GFP_KERNEL);
+ if (label == NULL)
+ panic("Can't kmalloc for firewall chains.\n");
+ strcpy(label->label,name);
+ label->next = NULL;
+ label->chain = NULL;
+ label->refcount = ref;
+ label->policy = policy;
+ for (i = 0; i < smp_num_cpus*2; i++) {
+ label->reent[i].counters.pcnt = label->reent[i].counters.bcnt
+ = 0;
+ label->reent[i].prevchain = NULL;
+ label->reent[i].prevrule = NULL;
}
- memcpy(ftmp, frwl, len);
- /*
- * Allow the more recent "minimise cost" flag to be
- * set. [Rob van Nieuwkerk]
- */
- ftmp->fw_tosand |= 0x01;
- ftmp->fw_tosxor &= 0xFE;
- ftmp->fw_pcnt=0L;
- ftmp->fw_bcnt=0L;
-
- ftmp->fw_next = NULL;
-
- cli();
-
- if ((ftmp->fw_vianame)[0]) {
- if (!(ftmp->fw_viadev = dev_get(ftmp->fw_vianame)))
- ftmp->fw_viadev = (struct device *) -1;
- } else
- ftmp->fw_viadev = NULL;
-
- chtmp_prev=NULL;
- for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next)
- chtmp_prev=chtmp;
-
- if (chtmp_prev)
- chtmp_prev->fw_next=ftmp;
- else
- *chainptr=ftmp;
- restore_flags(flags);
- return(0);
+ return label;
}
-static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
+/* This is a function for reating a new chain. The chains is not
+ * created if a chain of the same name already exists */
+static int create_chain(ip_chainlabel label)
{
- struct ip_fw *ftmp,*ltmp;
- unsigned short tport1,tport2,tmpnum;
- char matches,was_found;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- ftmp=*chainptr;
+ struct ip_chain *tmp;
- if ( ftmp == NULL )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: chain is empty\n");
-#endif
- restore_flags(flags);
- return( EINVAL );
- }
-
- ltmp=NULL;
- was_found=0;
-
- while( !was_found && ftmp != NULL )
- {
- matches=1;
- if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr
- || ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr
- || ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr
- || ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr
- || ftmp->fw_via.s_addr!=frwl->fw_via.s_addr
- || ftmp->fw_flg!=frwl->fw_flg)
- matches=0;
-
- tport1=ftmp->fw_nsp+ftmp->fw_ndp;
- tport2=frwl->fw_nsp+frwl->fw_ndp;
- if (tport1!=tport2)
- matches=0;
- else if (tport1!=0)
- {
- for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
- if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum])
- matches=0;
- }
- if (strncmp(ftmp->fw_vianame, frwl->fw_vianame, IFNAMSIZ))
- matches=0;
- if(matches)
- {
- was_found=1;
- if (ltmp)
- {
- ltmp->fw_next=ftmp->fw_next;
- kfree_s(ftmp,sizeof(*ftmp));
- ftmp=ltmp->fw_next;
- }
- else
- {
- *chainptr=ftmp->fw_next;
- kfree_s(ftmp,sizeof(*ftmp));
- ftmp=*chainptr;
- }
- }
- else
- {
- ltmp = ftmp;
- ftmp = ftmp->fw_next;
- }
- }
- restore_flags(flags);
- if (was_found)
- return 0;
- else
- return(EINVAL);
+ FWC_HAVE_LOCK(fwc_wlocks);
+ for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next)
+ if (strcmp(tmp->label,label) == 0)
+ return EEXIST;
+
+ if (strcmp(tmp->label,label) == 0)
+ return EEXIST;
+
+ tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is
+ * zero since this is a
+ * user defined chain *
+ * and therefore can be
+ * deleted */
+ return 0;
}
-#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
+/* This function simply changes the policy on one of the built in
+ * chains. checking must be done before this is call to ensure that
+ * chainptr is pointing to one of the three possible chains */
+static int change_policy(struct ip_chain *chainptr, int policy)
+{
+ FWC_HAVE_LOCK(fwc_wlocks);
+ chainptr->policy = policy;
+ return 0;
+}
-struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
+/* This function takes an ip_fwuser and converts it to a ip_fwkernel. It also
+ * performs some checks in the structure. */
+static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno)
{
+ struct ip_fwkernel *fwkern;
- if ( len != sizeof(struct ip_fw) )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw));
-#endif
- return(NULL);
+ if ( (fwuser->ipfw.fw_flg & ~IP_FW_F_MASK) != 0 ) {
+ duprintf("convert_ipfw: undefined flag bits set (flags=%x)\n",
+ fwuser->ipfw.fw_flg);
+ *errno = EINVAL;
+ return NULL;
}
- if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
- frwl->fw_flg);
-#endif
- return(NULL);
+#if DEBUG_IP_FIREWALL_USER
+ /* These are sanity checks that don't really matter.
+ * We can get rid of these once testing is complete.
+ */
+ if ((fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN)
+ && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO)
+ || fwuser->ipfw.fw_proto != IPPROTO_TCP)) {
+ duprintf("convert_ipfw: TCP SYN flag set but proto != TCP!\n");
+ *errno = EINVAL;
+ return NULL;
}
-#ifndef CONFIG_IP_TRANSPARENT_PROXY
- if (frwl->fw_flg & IP_FW_F_REDIR) {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: unsupported flag IP_FW_F_REDIR\n");
-#endif
- return(NULL);
+ if (strcmp(fwuser->label, IP_FW_LABEL_REDIRECT) != 0
+ && fwuser->ipfw.fw_redirpt != 0) {
+ duprintf("convert_ipfw: Target not REDIR but redirpt != 0!\n");
+ *errno = EINVAL;
+ return NULL;
}
-#endif
-#ifndef CONFIG_IP_MASQUERADE
- if (frwl->fw_flg & IP_FW_F_MASQ) {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: unsupported flag IP_FW_F_MASQ\n");
-#endif
- return(NULL);
+ if ((!(fwuser->ipfw.fw_flg & IP_FW_F_FRAG)
+ && (fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG))
+ || (!(fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN)
+ && (fwuser->ipfw.fw_invflg & IP_FW_INV_SYN))) {
+ duprintf("convert_ipfw: Can't have INV flag if flag unset!\n");
+ *errno = EINVAL;
+ return NULL;
}
-#endif
- if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: src range set but fw_nsp=%d\n",
- frwl->fw_nsp);
-#endif
- return(NULL);
+ if (((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCPT)
+ && fwuser->ipfw.fw_spts[0] == 0
+ && fwuser->ipfw.fw_spts[1] == 0xFFFF)
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTPT)
+ && fwuser->ipfw.fw_dpts[0] == 0
+ && fwuser->ipfw.fw_dpts[1] == 0xFFFF)
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_VIA)
+ && (fwuser->ipfw.fw_vianame)[0] == '\0')
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCIP)
+ && fwuser->ipfw.fw_smsk.s_addr == 0)
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTIP)
+ && fwuser->ipfw.fw_dmsk.s_addr == 0)) {
+ duprintf("convert_ipfw: INV flag makes rule unmatchable!\n");
+ *errno = EINVAL;
+ return NULL;
}
- if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: dst range set but fw_ndp=%d\n",
- frwl->fw_ndp);
-#endif
- return(NULL);
+ if ((fwuser->ipfw.fw_flg & IP_FW_F_FRAG)
+ && !(fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG)
+ && (fwuser->ipfw.fw_spts[0] != 0
+ || fwuser->ipfw.fw_spts[1] != 0xFFFF
+ || fwuser->ipfw.fw_dpts[0] != 0
+ || fwuser->ipfw.fw_dpts[1] != 0xFFFF
+ || (fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN))) {
+ duprintf("convert_ipfw: Can't test ports or SYN with frag!\n");
+ *errno = EINVAL;
+ return NULL;
}
-
- if ( frwl->fw_nsp + frwl->fw_ndp > (frwl->fw_flg & IP_FW_F_REDIR ? IP_FW_MAX_PORTS - 1 : IP_FW_MAX_PORTS) )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: too many ports (%d+%d)\n",
- frwl->fw_nsp,frwl->fw_ndp);
#endif
- return(NULL);
- }
-
- return frwl;
-}
-
-
+ if ((fwuser->ipfw.fw_spts[0] != 0
+ || fwuser->ipfw.fw_spts[1] != 0xFFFF
+ || fwuser->ipfw.fw_dpts[0] != 0
+ || fwuser->ipfw.fw_dpts[1] != 0xFFFF)
+ && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO)
+ || (fwuser->ipfw.fw_proto != IPPROTO_TCP
+ && fwuser->ipfw.fw_proto != IPPROTO_UDP
+ && fwuser->ipfw.fw_proto != IPPROTO_ICMP))) {
+ duprintf("convert_ipfw: Can only test ports for TCP/UDP/ICMP!\n");
+ *errno = EINVAL;
+ return NULL;
+ }
-#ifdef CONFIG_IP_ACCT
-
-int ip_acct_ctl(int stage, void *m, int len)
-{
- if ( stage == IP_ACCT_FLUSH )
- {
- free_fw_chain(&ip_acct_chain);
- return(0);
- }
- if ( stage == IP_ACCT_ZERO )
- {
- zero_fw_chain(ip_acct_chain);
- return(0);
+ fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL);
+ if (!fwkern) {
+ duprintf("convert_ipfw: kmalloc failed!\n");
+ *errno = ENOMEM;
+ return NULL;
}
- if ( stage == IP_ACCT_INSERT || stage == IP_ACCT_APPEND ||
- stage == IP_ACCT_DELETE )
- {
- struct ip_fw *frwl;
+ memcpy(&fwkern->ipfw,&fwuser->ipfw,sizeof(struct ip_fw));
+
+ if (!find_special(fwuser->label, &fwkern->simplebranch)) {
+ fwkern->branch = find_label(fwuser->label);
+ if (!fwkern->branch) {
+ duprintf("convert_ipfw: chain doesn't exist `%s'.\n",
+ fwuser->label);
+ kfree(fwkern);
+ *errno = ENOENT;
+ return NULL;
+ } else if (fwkern->branch == IP_FW_INPUT_CHAIN
+ || fwkern->branch == IP_FW_FORWARD_CHAIN
+ || fwkern->branch == IP_FW_OUTPUT_CHAIN) {
+ duprintf("convert_ipfw: Can't branch to builtin chain `%s'.\n",
+ fwuser->label);
+ kfree(fwkern);
+ *errno = ENOENT;
+ return NULL;
+ }
+ } else
+ fwkern->branch = NULL;
+ memset(fwkern->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS);
- if (!(frwl=check_ipfw_struct(m,len)))
- return (EINVAL);
+ /* Handle empty vianame by making it a wildcard */
+ if ((fwkern->ipfw.fw_vianame)[0] == '\0')
+ fwkern->ipfw.fw_flg |= IP_FW_F_WILDIF;
- switch (stage)
- {
- case IP_ACCT_INSERT:
- return( insert_in_chain(&ip_acct_chain,frwl,len));
- case IP_ACCT_APPEND:
- return( append_to_chain(&ip_acct_chain,frwl,len));
- case IP_ACCT_DELETE:
- return( del_from_chain(&ip_acct_chain,frwl));
- default:
- /*
- * Should be panic but... (Why ??? - AC)
- */
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_acct_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
- }
- }
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_acct_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
+ fwkern->next = NULL;
+ return fwkern;
}
-#endif
-#ifdef CONFIG_IP_FIREWALL
-int ip_fw_ctl(int stage, void *m, int len)
+int ip_fw_ctl(int cmd, void *m, int len)
{
- int cmd, fwtype;
-
- cmd = stage & IP_FW_COMMAND;
- fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
+ int ret;
+ struct ip_chain *chain;
+ unsigned long flags;
- if ( cmd == IP_FW_FLUSH )
- {
- free_fw_chain(chains[fwtype]);
- return(0);
- }
+ FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
- if ( cmd == IP_FW_ZERO )
- {
- zero_fw_chain(*chains[fwtype]);
- return(0);
- }
+ switch (cmd) {
+ case IP_FW_FLUSH:
+ if (len != sizeof(ip_chainlabel) || !check_label(m))
+ ret = EINVAL;
+ else if ((chain = find_label(m)) == NULL)
+ ret = ENOENT;
+ else ret = clear_fw_chain(chain);
+ break;
- if ( cmd == IP_FW_POLICY )
- {
- int *tmp_policy_ptr;
- tmp_policy_ptr=(int *)m;
- *policies[fwtype] = *tmp_policy_ptr;
- return 0;
- }
+ case IP_FW_ZERO:
+ if (len != sizeof(ip_chainlabel) || !check_label(m))
+ ret = EINVAL;
+ else if ((chain = find_label(m)) == NULL)
+ ret = ENOENT;
+ else ret = zero_fw_chain(chain);
+ break;
- if ( cmd == IP_FW_CHECK )
- {
- struct device *viadev;
- struct ip_fwpkt *ipfwp;
+ case IP_FW_CHECK: {
+ struct ip_fwtest *new = m;
struct iphdr *ip;
- if ( len != sizeof(struct ip_fwpkt) )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: length=%d, expected %d\n",
- len, sizeof(struct ip_fwpkt));
-#endif
- return( EINVAL );
- }
-
- ipfwp = (struct ip_fwpkt *)m;
- ip = &(ipfwp->fwp_iph);
-
- if ( !(viadev = dev_get(ipfwp->fwp_vianame)) ) {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: invalid device \"%s\"\n", ipfwp->fwp_vianame);
-#endif
- return(EINVAL);
- } else if ( ip->ihl != sizeof(struct iphdr) / sizeof(int)) {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
- sizeof(struct iphdr)/sizeof(int));
-#endif
- return(EINVAL);
- }
-
- switch (ip_fw_chk(ip, viadev, NULL, *chains[fwtype],
- *policies[fwtype], IP_FW_MODE_CHK))
- {
- case FW_ACCEPT:
- return(0);
- case FW_REDIRECT:
- return(ECONNABORTED);
- case FW_MASQUERADE:
- return(ECONNRESET);
- case FW_REJECT:
- return(ECONNREFUSED);
- default: /* FW_BLOCK */
- return(ETIMEDOUT);
+ /* Don't need write lock. */
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+
+ if (len != sizeof(struct ip_fwtest) || !check_label(m))
+ return EINVAL;
+
+ /* Need readlock to do find_label */
+ FWC_READ_LOCK(&ip_fw_lock);
+
+ if ((chain = find_label(new->fwt_label)) == NULL)
+ ret = ENOENT;
+ else {
+ ip = &(new->fwt_packet.fwp_iph);
+
+ if (ip->ihl != sizeof(struct iphdr) / sizeof(int)) {
+ duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n",
+ ip->ihl,
+ sizeof(struct iphdr) / sizeof(int));
+ ret = EINVAL;
+ }
+ else {
+ ret = ip_fw_check(ip, new->fwt_packet.fwp_vianame,
+ NULL, chain,
+ NULL, SLOT_NUMBER(), 1);
+ switch (ret) {
+ case FW_ACCEPT:
+ ret = 0; break;
+ case FW_REDIRECT:
+ ret = ECONNABORTED; break;
+ case FW_MASQUERADE:
+ ret = ECONNRESET; break;
+ case FW_REJECT:
+ ret = ECONNREFUSED; break;
+ /* Hack to help diag; these only get
+ returned when testing. */
+ case FW_SKIP+1:
+ ret = ELOOP; break;
+ case FW_SKIP:
+ ret = ENFILE; break;
+ default: /* FW_BLOCK */
+ ret = ETIMEDOUT; break;
+ }
+ }
}
+ FWC_READ_UNLOCK(&ip_fw_lock);
+ return ret;
}
- if ( cmd == IP_FW_MASQ_TIMEOUTS )
- {
+ case IP_FW_MASQ_TIMEOUTS: {
#ifdef CONFIG_IP_MASQUERADE
struct ip_fw_masq *masq;
- if ( len != sizeof(struct ip_fw_masq) )
- {
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl (masq): length %d, expected %d\n",
+ if (len != sizeof(struct ip_fw_masq)) {
+ duprintf("ip_fw_ctl (masq): length %d, expected %d\n",
len, sizeof(struct ip_fw_masq));
-
-#endif
- return( EINVAL );
+ ret = EINVAL;
}
-
- masq = (struct ip_fw_masq *) m;
-
- if (masq->tcp_timeout)
- {
- ip_masq_expire->tcp_timeout = masq->tcp_timeout;
+ else {
+ masq = (struct ip_fw_masq *)m;
+ if (masq->tcp_timeout)
+ ip_masq_expire->tcp_timeout
+ = masq->tcp_timeout;
+
+ if (masq->tcp_fin_timeout)
+ ip_masq_expire->tcp_fin_timeout
+ = masq->tcp_fin_timeout;
+
+ if (masq->udp_timeout)
+ ip_masq_expire->udp_timeout
+ = masq->udp_timeout;
+ ret = 0;
}
-
- if (masq->tcp_fin_timeout)
- {
- ip_masq_expire->tcp_fin_timeout = masq->tcp_fin_timeout;
- }
-
- if (masq->udp_timeout)
- {
- ip_masq_expire->udp_timeout = masq->udp_timeout;
- }
-
- return 0;
#else
- return( EINVAL );
+ ret = EINVAL;
#endif
}
+ break;
+
+ case IP_FW_REPLACE: {
+ struct ip_fwkernel *ip_fwkern;
+ struct ip_fwnew *new = m;
+
+ if (len != sizeof(struct ip_fwnew)
+ || !check_label(new->fwn_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwn_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret))
+ != NULL)
+ ret = replace_in_chain(chain, ip_fwkern,
+ new->fwn_rulenum);
+ }
+ break;
+
+ case IP_FW_APPEND: {
+ struct ip_fwchange *new = m;
+ struct ip_fwkernel *ip_fwkern;
+
+ if (len != sizeof(struct ip_fwchange)
+ || !check_label(new->fwc_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwc_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret))
+ != NULL)
+ ret = append_to_chain(chain, ip_fwkern);
+ }
+ break;
+
+ case IP_FW_INSERT: {
+ struct ip_fwkernel *ip_fwkern;
+ struct ip_fwnew *new = m;
+
+ if (len != sizeof(struct ip_fwnew)
+ || !check_label(new->fwn_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwn_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret))
+ != NULL)
+ ret = insert_in_chain(chain, ip_fwkern,
+ new->fwn_rulenum);
+ }
+ break;
+
+ case IP_FW_DELETE: {
+ struct ip_fwchange *new = m;
+ struct ip_fwkernel *ip_fwkern;
+
+ if (len != sizeof(struct ip_fwchange)
+ || !check_label(new->fwc_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwc_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret))
+ != NULL)
+ ret = del_rule_from_chain(chain, ip_fwkern);
+ }
+ break;
-/*
- * Here we really working hard-adding new elements
- * to blocking/forwarding chains or deleting 'em
- */
+ case IP_FW_DELETE_NUM: {
+ struct ip_fwdelnum *new = m;
- if ( cmd == IP_FW_INSERT || cmd == IP_FW_APPEND || cmd == IP_FW_DELETE )
- {
- struct ip_fw *frwl;
- int fwtype;
+ if (len != sizeof(struct ip_fwdelnum)
+ || !check_label(new->fwd_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwd_label)) == NULL)
+ ret = ENOENT;
+ else ret = del_num_from_chain(chain, new->fwd_rulenum);
+ }
+ break;
- frwl=check_ipfw_struct(m,len);
- if (frwl==NULL)
- return (EINVAL);
- fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT;
-
- switch (cmd)
- {
- case IP_FW_INSERT:
- return(insert_in_chain(chains[fwtype],frwl,len));
- case IP_FW_APPEND:
- return(append_to_chain(chains[fwtype],frwl,len));
- case IP_FW_DELETE:
- return(del_from_chain(chains[fwtype],frwl));
+ case IP_FW_CREATECHAIN: {
+ if (len != sizeof(ip_chainlabel)) {
+ duprintf("create_chain: bad size %i\n", len);
+ ret = EINVAL;
+ }
+ else ret = create_chain(m);
+ }
+ break;
+
+ case IP_FW_DELETECHAIN: {
+ if (len != sizeof(ip_chainlabel)) {
+ duprintf("delete_chain: bad size %i\n", len);
+ ret = EINVAL;
+ }
+ else ret = del_chain(m);
+ }
+ break;
+
+ case IP_FW_POLICY: {
+ struct ip_fwpolicy *new = m;
+
+ if (len != sizeof(struct ip_fwpolicy)
+ || !check_label(new->fwp_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwp_label)) == NULL)
+ ret = ENOENT;
+ else if (chain != IP_FW_INPUT_CHAIN
+ && chain != IP_FW_FORWARD_CHAIN
+ && chain != IP_FW_OUTPUT_CHAIN) {
+ duprintf("change_policy: can't change policy on user"
+ " defined chain.\n");
+ ret = EINVAL;
+ }
+ else {
+ int pol = FW_SKIP;
+ find_special(new->fwp_policy, &pol);
+
+ switch(pol) {
+ case FW_MASQUERADE:
+ if (chain != IP_FW_FORWARD_CHAIN) {
+ ret = EINVAL;
+ break;
+ }
+ /* Fall thru... */
+ case FW_BLOCK:
+ case FW_ACCEPT:
+ case FW_REJECT:
+ ret = change_policy(chain, pol);
+ break;
default:
- /*
- * Should be panic but... (Why are BSD people panic obsessed ??)
- */
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
+ duprintf("change_policy: bad policy `%s'\n",
+ new->fwp_policy);
+ ret = EINVAL;
+ }
}
- }
+ break;
+
+ }
+ default:
+ duprintf("ip_fw_ctl: unknown request %d\n",cmd);
+ ret = EINVAL;
+ }
-#ifdef DEBUG_IP_FIREWALL
- printk("ip_fw_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+ return ret;
}
-#endif /* CONFIG_IP_FIREWALL */
-#ifdef CONFIG_PROC_FS
-#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
+/* Returns bytes used - doesn't NUL terminate */
+static int dump_rule(char *buffer,
+ const char *chainlabel,
+ const struct ip_fwkernel *rule)
+{
+ int len;
+ unsigned int i;
+ __u64 packets = 0, bytes = 0;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ for (i = 0; i < NUM_SLOTS; i++) {
+ packets += rule->counters[i].pcnt;
+ bytes += rule->counters[i].bcnt;
+ }
-static int ip_chain_procinfo(int stage, char *buffer, char **start,
+ len=sprintf(buffer,
+ "%9s " /* Chain name */
+ "%08lX/%08lX->%08lX/%08lX " /* Source & Destination IPs */
+ "%.16s " /* Interface */
+ "%hX %hX " /* fw_flg and fw_invflg fields */
+ "%hu " /* Protocol */
+ "%-9u %-9u %-9u %-9u " /* Packet & byte counters */
+ "%hu-%hu %hu-%hu " /* Source & Dest port ranges */
+ "A%02X X%02X " /* TOS and and xor masks */
+ "%08X " /* Redirection port */
+ "%u " /* fw_mark field */
+ "%hu " /* output size */
+ "%9s\n", /* Target */
+ chainlabel,
+ ntohl(rule->ipfw.fw_src.s_addr),
+ ntohl(rule->ipfw.fw_smsk.s_addr),
+ ntohl(rule->ipfw.fw_dst.s_addr),
+ ntohl(rule->ipfw.fw_dmsk.s_addr),
+ (rule->ipfw.fw_vianame)[0] ? rule->ipfw.fw_vianame : "-",
+ rule->ipfw.fw_flg,
+ rule->ipfw.fw_invflg,
+ rule->ipfw.fw_proto,
+ (__u32)(packets >> 32), (__u32)packets,
+ (__u32)(bytes >> 32), (__u32)bytes,
+ rule->ipfw.fw_spts[0], rule->ipfw.fw_spts[1],
+ rule->ipfw.fw_dpts[0], rule->ipfw.fw_dpts[1],
+ rule->ipfw.fw_tosand, rule->ipfw.fw_tosxor,
+ rule->ipfw.fw_redirpt,
+ rule->ipfw.fw_mark,
+ rule->ipfw.fw_outputsize,
+ branchname(rule->branch,rule->simplebranch));
+
+ duprintf("dump_rule: %i bytes done.\n", len);
+ return len;
+}
+
+/* File offset is actually in records, not bytes. */
+static int ip_chain_procinfo(char *buffer, char **start,
off_t offset, int length, int reset)
{
- off_t pos=0, begin=0;
- struct ip_fw *i;
+ struct ip_chain *i;
+ struct ip_fwkernel *j = ip_fw_chains->chain;
unsigned long flags;
- int len, p;
+ int len = 0;
int last_len = 0;
-
+ off_t upto = 0;
+
+ duprintf("Offset starts at %lu\n", offset);
+ duprintf("ip_fw_chains is 0x%0lX\n", (unsigned long int)ip_fw_chains);
+
+ /* Need a write lock to lock out ``readers'' which update counters. */
+ FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
+
+ for (i = ip_fw_chains; i; i = i->next) {
+ for (j = i->chain; j; j = j->next) {
+ if (upto == offset) break;
+ duprintf("Skipping rule in chain `%s'\n",
+ i->label);
+ upto++;
+ }
+ if (upto == offset) break;
+ }
- switch(stage)
- {
-#ifdef CONFIG_IP_FIREWALL
- case IP_FW_IN:
- i = ip_fw_in_chain;
- len=sprintf(buffer, "IP firewall input rules, default %d\n",
- ip_fw_in_policy);
- break;
- case IP_FW_OUT:
- i = ip_fw_out_chain;
- len=sprintf(buffer, "IP firewall output rules, default %d\n",
- ip_fw_out_policy);
- break;
- case IP_FW_FWD:
- i = ip_fw_fwd_chain;
- len=sprintf(buffer, "IP firewall forward rules, default %d\n",
- ip_fw_fwd_policy);
- break;
-#endif
-#ifdef CONFIG_IP_ACCT
- case IP_FW_ACCT:
- i = ip_acct_chain;
- len=sprintf(buffer,"IP accounting rules\n");
- break;
-#endif
- default:
- /* this should never be reached, but safety first... */
- i = NULL;
- len=0;
- break;
+ /* Don't init j first time, or once i = NULL */
+ for (; i; (void)((i = i->next) && (j = i->chain))) {
+ duprintf("Dumping chain `%s'\n", i->label);
+ for (; j; j = j->next, upto++, last_len = len)
+ {
+ len += dump_rule(buffer+len, i->label, j);
+ if (len > length) {
+ duprintf("Dumped to %i (past %i). "
+ "Moving back to %i.\n",
+ len, length, last_len);
+ len = last_len;
+ goto outside;
+ }
+ else if (reset)
+ memset(j->counters, 0,
+ sizeof(struct ip_counters)*NUM_SLOTS);
+ }
}
+outside:
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+ buffer[len] = '\0';
+
+ duprintf("ip_chain_procinfo: Length = %i (of %i). Offset = %li.\n",
+ len, length, upto);
+ /* `start' hack - see fs/proc/generic.c line ~165 */
+ *start=(char *)((unsigned int)upto-offset);
+ return len;
+}
- save_flags(flags);
- cli();
-
- while(i!=NULL)
+static int ip_chain_name_procinfo(char *buffer, char **start,
+ off_t offset, int length, int reset)
+{
+ struct ip_chain *i;
+ int len = 0,last_len = 0;
+ off_t pos = 0,begin = 0;
+ unsigned long flags;
+
+ /* Need a write lock to lock out ``readers'' which update counters. */
+ FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
+
+ for (i = ip_fw_chains; i; i = i->next)
{
- len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %.16s %08lX %X ",
- ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr),
- ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr),
- (i->fw_vianame)[0] ? i->fw_vianame : "-",
- ntohl(i->fw_via.s_addr),i->fw_flg);
- /* 10 is enough for a 32 bit box but the counters are 64bit on
- the Alpha and Ultrapenguin */
- len+=sprintf(buffer+len,"%u %u %-20lu %-20lu",
- i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
- for (p = 0; p < IP_FW_MAX_PORTS; p++)
- len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
- len+=sprintf(buffer+len, " A%02X X%02X", i->fw_tosand, i->fw_tosxor);
- buffer[len++]='\n';
- buffer[len]='\0';
+ unsigned int j;
+ __u32 packetsHi = 0, packetsLo = 0, bytesHi = 0, bytesLo = 0;
+
+ for (j = 0; j < NUM_SLOTS; j++) {
+ packetsLo += i->reent[j].counters.pcnt & 0xFFFFFFFF;
+ packetsHi += ((i->reent[j].counters.pcnt >> 32)
+ & 0xFFFFFFFF);
+ bytesLo += i->reent[j].counters.bcnt & 0xFFFFFFFF;
+ bytesHi += ((i->reent[j].counters.bcnt >> 32)
+ & 0xFFFFFFFF);
+ }
+
+ /* print the label and the policy */
+ len+=sprintf(buffer+len,"%s %s %i %u %u %u %u\n",
+ i->label,branchname(NULL, i->policy),i->refcount,
+ packetsHi, packetsLo, bytesHi, bytesLo);
pos=begin+len;
- if(pos<offset)
- {
+ if(pos<offset) {
len=0;
begin=pos;
}
- else if(pos>offset+length)
- {
+ else if(pos>offset+length) {
len = last_len;
break;
}
- else if(reset)
- {
- /* This needs to be done at this specific place! */
- i->fw_pcnt=0L;
- i->fw_bcnt=0L;
- }
+
last_len = len;
- i=i->fw_next;
}
- restore_flags(flags);
- *start=buffer+(offset-begin);
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+
+ *start = buffer+(offset-begin);
len-=(offset-begin);
if(len>length)
- len=length;
+ len=length;
return len;
}
-#endif
-
-#ifdef CONFIG_IP_ACCT
-
-static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
- int length, int reset)
-{
- return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length,
- reset);
-}
-
-#endif
-
-#ifdef CONFIG_IP_FIREWALL
-static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset,
- int length, int reset)
-{
- return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length,
- reset);
-}
-
-static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset,
- int length, int reset)
-{
- return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length,
- reset);
-}
-
-static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
- int length, int reset)
-{
- return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length,
- reset);
-}
-#endif
-#endif
-
-
-#ifdef CONFIG_IP_FIREWALL
/*
* Interface to the generic firewall chains.
*/
-
-int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb)
+int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev,
+ void *phdr, void *arg, struct sk_buff **pskb)
{
- return ip_fw_chk(phdr, dev, arg, ip_fw_in_chain, ip_fw_in_policy, IP_FW_MODE_FW);
+ return ip_fw_check(phdr, dev->name,
+ arg, IP_FW_INPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
}
-int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb)
+int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev,
+ void *phdr, void *arg, struct sk_buff **pskb)
{
- return ip_fw_chk(phdr, dev, arg, ip_fw_out_chain, ip_fw_out_policy, IP_FW_MODE_FW);
+ return ip_fw_check(phdr, dev->name,
+ arg, IP_FW_OUTPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
}
-int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb)
+int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev,
+ void *phdr, void *arg, struct sk_buff **pskb)
{
- return ip_fw_chk(phdr, dev, arg, ip_fw_fwd_chain, ip_fw_fwd_policy, IP_FW_MODE_FW);
+ return ip_fw_check(phdr, dev->name,
+ arg, IP_FW_FORWARD_CHAIN, *pskb, SLOT_NUMBER(), 0);
}
-
+
struct firewall_ops ipfw_ops=
{
NULL,
0 /* We don't even allow a fall through so we are last */
};
-#endif
-
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
-
-int ipfw_device_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
- struct device *dev=ptr;
- char *devname = dev->name;
- unsigned long flags;
- struct ip_fw *fw;
- int chn;
-
- save_flags(flags);
- cli();
-
- if (event == NETDEV_UP) {
- for (chn = 0; chn < IP_FW_CHAINS; chn++)
- for (fw = *chains[chn]; fw; fw = fw->fw_next)
- if ((fw->fw_vianame)[0] && !strncmp(devname,
- fw->fw_vianame, IFNAMSIZ))
- fw->fw_viadev = dev;
- } else if (event == NETDEV_DOWN) {
- for (chn = 0; chn < IP_FW_CHAINS; chn++)
- for (fw = *chains[chn]; fw; fw = fw->fw_next)
- /* we could compare just the pointers ... */
- if ((fw->fw_vianame)[0] && !strncmp(devname,
- fw->fw_vianame, IFNAMSIZ))
- fw->fw_viadev = (struct device *) -1;
- }
-
- restore_flags(flags);
- return NOTIFY_DONE;
-}
-
-static struct notifier_block ipfw_dev_notifier={
- ipfw_device_event,
- NULL,
- 0
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_ipfwchains_chain = {
+ PROC_NET_IPFW_CHAINS, sizeof(IP_FW_PROC_CHAINS)-1,
+ IP_FW_PROC_CHAINS, S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+ 0, &proc_net_inode_operations, ip_chain_procinfo
};
-#endif
-
-#ifdef CONFIG_PROC_FS
-#ifdef CONFIG_IP_ACCT
-static struct proc_dir_entry proc_net_ipacct = {
- PROC_NET_IPACCT, 7, "ip_acct",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ip_acct_procinfo
+static struct proc_dir_entry proc_net_ipfwchains_chainnames = {
+ PROC_NET_IPFW_CHAIN_NAMES, sizeof(IP_FW_PROC_CHAIN_NAMES)-1,
+ IP_FW_PROC_CHAIN_NAMES, S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+ 0, &proc_net_inode_operations, ip_chain_name_procinfo
};
-#endif
-#endif
-#ifdef CONFIG_IP_FIREWALL
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_ipfwin = {
- PROC_NET_IPFWIN, 8, "ip_input",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ip_fw_in_procinfo
-};
-static struct proc_dir_entry proc_net_ipfwout = {
- PROC_NET_IPFWOUT, 9, "ip_output",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ip_fw_out_procinfo
-};
-static struct proc_dir_entry proc_net_ipfwfwd = {
- PROC_NET_IPFWFWD, 10, "ip_forward",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ip_fw_fwd_procinfo
-};
#endif
-#endif
-
__initfunc(void ip_fw_init(void))
{
-#ifdef CONFIG_PROC_FS
-#ifdef CONFIG_IP_ACCT
- proc_net_register(&proc_net_ipacct);
+#ifdef DEBUG_IP_FIRWALL_LOCKING
+ fwc_wlocks = fwc_rlocks = 0;
#endif
-#endif
-#ifdef CONFIG_IP_FIREWALL
+
+ IP_FW_INPUT_CHAIN = ip_init_chain(IP_FW_LABEL_INPUT, 1, FW_ACCEPT);
+ IP_FW_FORWARD_CHAIN = ip_init_chain(IP_FW_LABEL_FORWARD, 1, FW_ACCEPT);
+ IP_FW_OUTPUT_CHAIN = ip_init_chain(IP_FW_LABEL_OUTPUT, 1, FW_ACCEPT);
if(register_firewall(PF_INET,&ipfw_ops)<0)
panic("Unable to register IP firewall.\n");
+
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_ipfwin);
- proc_net_register(&proc_net_ipfwout);
- proc_net_register(&proc_net_ipfwfwd);
-#endif
+ proc_net_register(&proc_net_ipfwchains_chain);
+ proc_net_register(&proc_net_ipfwchains_chainnames);
#endif
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
- /* Register for device up/down reports */
- register_netdevice_notifier(&ipfw_dev_notifier);
-#endif
#ifdef CONFIG_IP_FIREWALL_NETLINK
ipfwsk = netlink_kernel_create(NETLINK_FIREWALL, NULL);
+ if (ipfwsk == NULL)
+ panic("ip_fw_init: cannot initialize netlink\n");
+#endif
+#if defined(DEBUG_IP_FIREWALL) || defined(DEBUG_IP_FIREWALL_USER)
+ printk("Firewall graphs enabled! Untested kernel coming thru. \n");
#endif
}
*
* The Internet Protocol (IP) module.
*
- * Version: $Id: ip_input.c,v 1.29 1998/04/03 10:52:06 davem Exp $
+ * Version: $Id: ip_input.c,v 1.30 1998/05/08 01:54:54 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
ip_statistics.IpInReceives++;
- /*
- * Account for the packet (even if the packet is
- * not accepted by the firewall!).
- */
-
-#ifdef CONFIG_IP_ACCT
- ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN);
-#endif
-
/*
* RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
*
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.56 1998/04/17 02:36:46 davem Exp $
+ * Version: $Id: ip_output.c,v 1.57 1998/05/08 01:54:56 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
return ip_finish_output(skb);
}
-#ifdef CONFIG_IP_ACCT
-int ip_acct_output(struct sk_buff *skb)
-{
- /*
- * Count mapping we shortcut
- */
-
- ip_fw_chk(skb->nh.iph, skb->dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT);
-
- dev_queue_xmit(skb);
-
- return 0;
-}
-#endif
-
/* Queues a packet to be sent, and starts the transmitter if necessary.
* This routine also needs to put in the total length and compute the
* checksum. We use to do this in two stages, ip_build_header() then
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.32 1998/03/08 05:56:26 davem Exp $
+ * Version: $Id: ip_sockglue.c,v 1.35 1998/05/08 21:06:28 davem Exp $
*
* Authors: see ip.c
*
#include <asm/uaccess.h>
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
#define IP_CMSG_PKTINFO 1
#define IP_CMSG_TTL 2
#define IP_CMSG_TOS 4
int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
{
int val=0,err;
-#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
- struct ip_fw tmp_fw;
+#if defined(CONFIG_IP_FIREWALL)
+ char tmp_fw[MAX(sizeof(struct ip_fwtest),sizeof(struct ip_fwnew))];
#endif
#ifdef CONFIG_IP_MASQUERADE
char masq_ctl[IP_FW_MASQCTL_MAX];
}
if (!mreq.imr_ifindex) {
- if (!mreq.imr_address.s_addr == INADDR_ANY) {
+ if (mreq.imr_address.s_addr == INADDR_ANY) {
sk->ip_mc_index = 0;
sk->ip_mc_addr = 0;
return 0;
return ip_ra_control(sk, val ? 1 : 0, NULL);
#ifdef CONFIG_IP_FIREWALL
- case IP_FW_INSERT_IN:
- case IP_FW_INSERT_OUT:
- case IP_FW_INSERT_FWD:
- case IP_FW_APPEND_IN:
- case IP_FW_APPEND_OUT:
- case IP_FW_APPEND_FWD:
- case IP_FW_DELETE_IN:
- case IP_FW_DELETE_OUT:
- case IP_FW_DELETE_FWD:
- case IP_FW_CHECK_IN:
- case IP_FW_CHECK_OUT:
- case IP_FW_CHECK_FWD:
- case IP_FW_FLUSH_IN:
- case IP_FW_FLUSH_OUT:
- case IP_FW_FLUSH_FWD:
- case IP_FW_ZERO_IN:
- case IP_FW_ZERO_OUT:
- case IP_FW_ZERO_FWD:
- case IP_FW_POLICY_IN:
- case IP_FW_POLICY_OUT:
- case IP_FW_POLICY_FWD:
case IP_FW_MASQ_TIMEOUTS:
+ case IP_FW_APPEND:
+ case IP_FW_REPLACE:
+ case IP_FW_DELETE:
+ case IP_FW_DELETE_NUM:
+ case IP_FW_INSERT:
+ case IP_FW_FLUSH:
+ case IP_FW_ZERO:
+ case IP_FW_CHECK:
+ case IP_FW_CREATECHAIN:
+ case IP_FW_DELETECHAIN:
+ case IP_FW_POLICY:
if(!capable(CAP_NET_ADMIN))
return -EACCES;
if(optlen>sizeof(tmp_fw) || optlen<1)
return -EFAULT;
err=ip_fw_ctl(optname, &tmp_fw,optlen);
return -err; /* -0 is 0 after all */
-
-#endif
+#endif /* CONFIG_IP_FIREWALL */
#ifdef CONFIG_IP_MASQUERADE
case IP_FW_MASQ_ADD:
case IP_FW_MASQ_DEL:
err=ip_masq_ctl(optname, masq_ctl,optlen);
return -err; /* -0 is 0 after all */
-#endif
-#ifdef CONFIG_IP_ACCT
- case IP_ACCT_INSERT:
- case IP_ACCT_APPEND:
- case IP_ACCT_DELETE:
- case IP_ACCT_FLUSH:
- case IP_ACCT_ZERO:
- if(!capable(CAP_NET_ADMIN))
- return -EACCES;
- if(optlen>sizeof(tmp_fw) || optlen<1)
- return -EINVAL;
- if(copy_from_user(&tmp_fw, optval,optlen))
- return -EFAULT;
- err=ip_acct_ctl(optname, &tmp_fw,optlen);
- return -err; /* -0 is 0 after all */
#endif
default:
return(-ENOPROTOOPT);
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: ipmr.c,v 1.34 1998/04/28 06:21:59 davem Exp $
+ * Version: $Id: ipmr.c,v 1.35 1998/05/13 06:23:24 davem Exp $
*
* Fixes:
* Michael Chastain : Incorrect size of copying.
nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
skb_trim(skb, nlh->nlmsg_len);
((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
- netlink_unicast(rtnl, skb, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+ netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
} else
#endif
kfree_skb(skb);
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: $Id: raw.c,v 1.35 1998/03/08 05:56:32 davem Exp $
+ * Version: $Id: raw.c,v 1.36 1998/05/08 21:06:29 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.47 1998/04/28 06:22:01 davem Exp $
+ * Version: $Id: route.c,v 1.50 1998/05/13 06:23:25 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
};
__u8 ip_tos2prio[16] = {
- TC_PRIO_FILLER,
TC_PRIO_BESTEFFORT,
TC_PRIO_FILLER,
+ TC_PRIO_BESTEFFORT,
TC_PRIO_FILLER,
TC_PRIO_BULK,
TC_PRIO_FILLER,
r->u.dst.window,
(int)r->u.dst.rtt, r->key.tos,
r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
- r->u.dst.hh ? (r->u.dst.hh->hh_output == ip_acct_output) : 0,
+ r->u.dst.hh ? (r->u.dst.hh->hh_output == dev_queue_xmit) : 0,
r->rt_spec_dst);
sprintf(buffer+len,"%-127s\n",temp);
len += 128;
rt->u.dst.window= 0;
rt->u.dst.rtt = TCP_TIMEOUT_INIT;
}
-#ifdef CONFIG_NET_CLS_ROUTE
+#if defined(CONFIG_NET_CLS_ROUTE) && defined(CONFIG_IP_MULTIPLE_TABLES)
if (rt->u.dst.tclassid == 0)
rt->u.dst.tclassid = fib_rules_tclass(res);
#endif
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
- NETLINK_CB(skb).pid = NETLINK_CB(in_skb).pid;
+ NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0);
if (err == 0)
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.146 1998/05/03 14:30:59 alan Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.147 1998/05/06 13:25:00 freitag Exp $
*
* IPv4 specific functions
*
/*
- * This routine does path mtu discovery as defined in RFC1197.
+ * This routine does path mtu discovery as defined in RFC1191.
*/
static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip)
{
*
* The User Datagram Protocol (UDP).
*
- * Version: $Id: udp.c,v 1.55 1998/03/21 07:28:01 davem Exp $
+ * Version: $Id: udp.c,v 1.56 1998/05/08 21:06:30 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: addrconf.c,v 1.39 1998/05/03 14:31:04 alan Exp $
+ * $Id: addrconf.c,v 1.41 1998/05/08 21:06:31 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <linux/rtnetlink.h>
#include <asm/uaccess.h>
+#include <asm/delay.h>
/* Set to 3 to get tracing... */
#define ACONF_DEBUG 2
start_bh_atomic();
- /* Discard multicast list */
-
- if (how == 1)
- ipv6_mc_destroy_dev(idev);
- else
- ipv6_mc_down(idev);
-
/* Discard address list */
idev->addr_list = NULL;
}
}
+ /* Discard multicast list */
+
+ if (how == 1)
+ ipv6_mc_destroy_dev(idev);
+ else
+ ipv6_mc_down(idev);
+
/* Delete device from device hash table (if unregistered) */
if (how == 1) {
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.31 1998/05/03 14:31:06 alan Exp $
+ * $Id: af_inet6.c,v 1.33 1998/05/08 21:06:32 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#ifdef MODULE
int ipv6_unload(void)
{
- return 0;
+ /* We keep internally 3 raw sockets */
+ return __this_module.usecount - 3;
}
#endif
#endif
{
struct sk_buff *dummy_skb;
+ int err;
#ifdef MODULE
if (!mod_member_present(&__this_module, can_unload))
#endif
}
- (void) sock_register(&inet6_family_ops);
-
/*
* ipngwg API draft makes clear that the correct semantics
* for TCP and UDP is to consider one TCP and UDP instance
* able to communicate via both network protocols.
*/
- ipv6_init();
-
- icmpv6_init(&inet6_family_ops);
-
- addrconf_init();
-
- sit_init();
-
- /* init v6 transport protocols */
-
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+ ipv6_sysctl_register();
+#endif
+ err = icmpv6_init(&inet6_family_ops);
+ if (err)
+ goto icmp_fail;
+ err = ndisc_init(&inet6_family_ops);
+ if (err)
+ goto ndisc_fail;
+ err = igmp6_init(&inet6_family_ops);
+ if (err)
+ goto igmp_fail;
+ ipv6_netdev_notif_init();
+ ipv6_packet_init();
+ ip6_route_init();
+ addrconf_init();
+ sit_init();
+
+ /* Init v6 transport protocols. */
udpv6_init();
- /* add /proc entries here */
-
tcpv6_init();
/* Create /proc/foo6 entries. */
proc_net_register(&proc_net_sockstat6);
#endif
+ /* Now the userspace is allowed to create INET6 sockets. */
+ (void) sock_register(&inet6_family_ops);
+
#ifdef MODULE
return 0;
+#else
+ return;
+#endif
+
+igmp_fail:
+ ndisc_cleanup();
+ndisc_fail:
+ icmpv6_cleanup();
+icmp_fail:
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+ ipv6_sysctl_unregister();
+#endif
+#ifdef MODULE
+ return err;
+#else
+ return;
#endif
}
#ifdef MODULE
void cleanup_module(void)
{
- sit_cleanup();
- ipv6_cleanup();
- sock_unregister(PF_INET6);
+ /* First of all disallow new sockets creation. */
+ sock_unregister(AF_INET6);
#ifdef CONFIG_PROC_FS
proc_net_unregister(proc_net_raw6.low_ino);
proc_net_unregister(proc_net_tcp6.low_ino);
proc_net_unregister(proc_net_udp6.low_ino);
proc_net_unregister(proc_net_sockstat6.low_ino);
+#endif
+ /* Cleanup code parts. */
+ sit_cleanup();
+ ipv6_netdev_notif_cleanup();
+ addrconf_cleanup();
+ ip6_route_cleanup();
+ ipv6_packet_cleanup();
+ igmp6_cleanup();
+ ndisc_cleanup();
+ icmpv6_cleanup();
+#ifdef CONFIG_SYSCTL
+ ipv6_sysctl_unregister();
#endif
}
#endif /* MODULE */
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.17 1998/05/01 10:31:41 davem Exp $
+ * $Id: icmp.c,v 1.18 1998/05/07 15:42:59 davem Exp $
*
* Based on net/ipv4/icmp.c
*
* ICMP socket for flow control.
*/
-struct inode icmpv6_inode;
-struct socket *icmpv6_socket=&icmpv6_inode.u.socket_i;
+struct socket *icmpv6_socket;
int icmpv6_rcv(struct sk_buff *skb, struct device *dev,
struct in6_addr *saddr, struct in6_addr *daddr,
struct sock *sk;
int err;
- icmpv6_inode.i_mode = S_IFSOCK;
- icmpv6_inode.i_sock = 1;
- icmpv6_inode.i_uid = 0;
- icmpv6_inode.i_gid = 0;
-
- icmpv6_socket->inode = &icmpv6_inode;
- icmpv6_socket->state = SS_UNCONNECTED;
- icmpv6_socket->type=SOCK_RAW;
-
- if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0) {
- printk(KERN_DEBUG
+ icmpv6_socket = sock_alloc();
+ if (icmpv6_socket == NULL) {
+ printk(KERN_ERR
"Failed to create the ICMP6 control socket.\n");
- return 1;
+ return -1;
+ }
+ icmpv6_socket->inode->i_uid = 0;
+ icmpv6_socket->inode->i_gid = 0;
+ icmpv6_socket->type = SOCK_RAW;
+
+ if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) {
+ printk(KERN_ERR
+ "Failed to initialize the ICMP6 control socket (err %d).\n",
+ err);
+ sock_release(icmpv6_socket);
+ icmpv6_socket = NULL; /* for safety */
+ return err;
}
sk = icmpv6_socket->sk;
inet6_add_protocol(&icmpv6_protocol);
- ndisc_init(ops);
- igmp6_init(ops);
- return 0;
+ return 0;
}
void icmpv6_cleanup(void)
{
+ sock_release(icmpv6_socket);
+ icmpv6_socket = NULL; /* For safety. */
inet6_del_protocol(&icmpv6_protocol);
-#if 0
- ndisc_cleanup();
-#endif
- igmp6_cleanup();
}
static struct icmp6_err {
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fib.c,v 1.13 1998/04/28 06:22:03 davem Exp $
+ * $Id: ip6_fib.c,v 1.14 1998/05/07 15:43:03 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
ip6_fib_timer.expires = 0;
}
}
+
+#ifdef MODULE
+void fib6_gc_cleanup(void)
+{
+ del_timer(&ip6_fib_timer);
+}
+#endif
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.20 1998/05/03 14:31:07 alan Exp $
+ * $Id: ipv6_sockglue.c,v 1.21 1998/05/07 15:43:13 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
extern void ipv6_sysctl_unregister(void);
#endif
-__initfunc(void ipv6_init(void))
+__initfunc(void ipv6_packet_init(void))
{
dev_add_pack(&ipv6_packet_type);
+}
-#if defined(MODULE) && defined(CONFIG_SYSCTL)
- ipv6_sysctl_register();
-#endif
-
+__initfunc(void ipv6_netdev_notif_init(void))
+{
register_netdevice_notifier(&ipv6_dev_notf);
-
- ip6_route_init();
}
#ifdef MODULE
-void ipv6_cleanup(void)
+void ipv6_packet_cleanup(void)
{
- unregister_netdevice_notifier(&ipv6_dev_notf);
dev_remove_pack(&ipv6_packet_type);
-#ifdef CONFIG_SYSCTL
- ipv6_sysctl_unregister();
-#endif
- ip6_route_cleanup();
- icmpv6_cleanup();
- addrconf_cleanup();
}
-#endif
-
+void ipv6_netdev_notif_cleanup(void)
+{
+ unregister_netdevice_notifier(&ipv6_dev_notf);
+}
+#endif
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: mcast.c,v 1.15 1998/04/30 16:24:28 freitag Exp $
+ * $Id: mcast.c,v 1.16 1998/05/07 15:43:10 davem Exp $
*
* Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c
*
#define MDBG(x)
#endif
-static struct inode igmp6_inode;
-static struct socket *igmp6_socket=&igmp6_inode.u.socket_i;
+static struct socket *igmp6_socket;
static void igmp6_join_group(struct ifmcaddr6 *ma);
static void igmp6_leave_group(struct ifmcaddr6 *ma);
}
#endif
-__initfunc(void igmp6_init(struct net_proto_family *ops))
+__initfunc(int igmp6_init(struct net_proto_family *ops))
{
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *ent;
struct sock *sk;
int err;
- igmp6_inode.i_mode = S_IFSOCK;
- igmp6_inode.i_sock = 1;
- igmp6_inode.i_uid = 0;
- igmp6_inode.i_gid = 0;
-
- igmp6_socket->inode = &igmp6_inode;
- igmp6_socket->state = SS_UNCONNECTED;
+ igmp6_socket = sock_alloc();
+ if (igmp6_socket == NULL) {
+ printk(KERN_ERR
+ "Failed to create the IGMP6 control socket.\n");
+ return -1;
+ }
+ igmp6_socket->inode->i_uid = 0;
+ igmp6_socket->inode->i_gid = 0;
igmp6_socket->type = SOCK_RAW;
- if((err=ops->create(igmp6_socket, IPPROTO_ICMPV6))<0)
+ if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) {
printk(KERN_DEBUG
- "Failed to create the IGMP6 control socket.\n");
+ "Failed to initialize the IGMP6 control socket (err %d).\n",
+ err);
+ sock_release(igmp6_socket);
+ igmp6_socket = NULL; /* For safety. */
+ return err;
+ }
sk = igmp6_socket->sk;
sk->allocation = GFP_ATOMIC;
ent = create_proc_entry("net/igmp6", 0, 0);
ent->read_proc = igmp6_read_proc;
#endif
+
+ return 0;
}
+#ifdef MODULE
void igmp6_cleanup(void)
{
+ sock_release(igmp6_socket);
+ igmp6_socket = NULL; /* for safety */
#ifdef CONFIG_PROC_FS
- remove_proc_entry("net/igmp6", 0);
+ remove_proc_entry("net/igmp6", 0);
#endif
}
+#endif
#include <net/checksum.h>
#include <linux/proc_fs.h>
-static struct inode ndisc_inode;
-static struct socket *ndisc_socket=&ndisc_inode.u.socket_i;
+static struct socket *ndisc_socket;
static int ndisc_constructor(struct neighbour *neigh);
static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
-__initfunc(void ndisc_init(struct net_proto_family *ops))
+__initfunc(int ndisc_init(struct net_proto_family *ops))
{
struct sock *sk;
int err;
- ndisc_inode.i_mode = S_IFSOCK;
- ndisc_inode.i_sock = 1;
- ndisc_inode.i_uid = 0;
- ndisc_inode.i_gid = 0;
-
- ndisc_socket->inode = &ndisc_inode;
- ndisc_socket->state = SS_UNCONNECTED;
- ndisc_socket->type = SOCK_RAW;
+ ndisc_socket = sock_alloc();
+ if (ndisc_socket == NULL) {
+ printk(KERN_ERR
+ "Failed to create the NDISC control socket.\n");
+ return -1;
+ }
+ ndisc_socket->inode->i_uid = 0;
+ ndisc_socket->inode->i_gid = 0;
+ ndisc_socket->type = SOCK_RAW;
- if((err=ops->create(ndisc_socket, IPPROTO_ICMPV6))<0)
+ if((err = ops->create(ndisc_socket, IPPROTO_ICMPV6)) < 0) {
printk(KERN_DEBUG
- "Failed to create the NDISC control socket.\n");
+ "Failed to initializee the NDISC control socket (err %d).\n",
+ err);
+ sock_release(ndisc_socket);
+ ndisc_socket = NULL; /* For safety. */
+ return err;
+ }
sk = ndisc_socket->sk;
sk->allocation = GFP_ATOMIC;
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
#endif
+
+ return 0;
}
-#ifdef MODULE
void ndisc_cleanup(void)
{
#ifdef CONFIG_PROC_FS
#endif
#endif
neigh_table_clear(&nd_tbl);
+ sock_release(ndisc_socket);
+ ndisc_socket = NULL; /* For safety. */
}
-#endif
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.28 1998/04/28 06:22:04 davem Exp $
+ * $Id: route.c,v 1.30 1998/05/08 21:06:33 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
netlink_detach(NETLINK_ROUTE6);
#endif
rt6_ifdown(NULL);
+ fib6_gc_cleanup();
}
#endif /* MODULE */
if (err == 0)
size = NLMSG_SPACE(sizeof(struct nlmsgerr));
else
- size = NLMSG_SPACE(4 + nlh->nlmsg_len);
+ size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len));
skb = alloc_skb(size, GFP_KERNEL);
if (!skb)
defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \
defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \
defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \
- defined(CONFIG_ES3210)
+ defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \
+ defined(CONFIG_LNE390)
#include "../drivers/net/8390.h"
#endif
defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \
defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \
defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \
- defined(CONFIG_ES3210)
+ defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \
+ defined(CONFIG_LNE390)
/* If 8390 NIC support is built in, we will need these. */
EXPORT_SYMBOL(ei_open);
EXPORT_SYMBOL(ei_close);
EXPORT_SYMBOL(netdev_unregister_fc);
EXPORT_SYMBOL(netdev_fc_xoff);
#endif
-#ifdef CONFIG_IP_ACCT
-EXPORT_SYMBOL(ip_acct_output);
-#endif
EXPORT_SYMBOL(dev_base);
EXPORT_SYMBOL(dev_close);
EXPORT_SYMBOL(dev_mc_add);
#
# Traffic control configuration.
#
+define_bool CONFIG_NETLINK y
+define_bool CONFIG_RTNETLINK y
tristate 'CBQ packet scheduler' CONFIG_NET_SCH_CBQ
tristate 'CSZ packet scheduler' CONFIG_NET_SCH_CSZ
#tristate 'H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ
if [ "$CONFIG_NET_QOS" = "y" ]; then
bool 'Rate estimator' CONFIG_NET_ESTIMATOR
fi
-if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then
- bool 'Packet classifier API' CONFIG_NET_CLS
-fi
+bool 'Packet classifier API' CONFIG_NET_CLS
if [ "$CONFIG_NET_CLS" = "y" ]; then
bool 'Routing tables based classifier' CONFIG_NET_CLS_ROUTE
-# bool 'Firewall based classifier' CONFIG_NET_CLS_FW
+ if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
+ bool 'Firewall based classifier' CONFIG_NET_CLS_FW
+ fi
tristate 'U32 classifier' CONFIG_NET_CLS_U32
if [ "$CONFIG_NET_QOS" = "y" ]; then
tristate 'Special RSVP classifier' CONFIG_NET_CLS_RSVP
u32 protocol = TC_H_MIN(t->tcm_info);
u32 prio = TC_H_MAJ(t->tcm_info);
u32 nprio = prio;
+ u32 parent = t->tcm_parent;
struct device *dev;
struct Qdisc *q;
struct tcf_proto **back, **chain;
return -ENODEV;
/* Find qdisc */
- if (!t->tcm_parent)
+ if (!parent) {
q = dev->qdisc_sleeping;
- else if ((q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent))) == NULL)
+ parent = q->handle;
+ } else if ((q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent))) == NULL)
return -EINVAL;
/* Is it classful? */
return -EINVAL;
/* Do we search for filter, attached to class? */
- if (TC_H_MIN(t->tcm_parent)) {
- cl = cops->get(q, t->tcm_parent);
+ if (TC_H_MIN(parent)) {
+ cl = cops->get(q, parent);
if (cl == 0)
return -ENOENT;
}
tp->prio = nprio ? : tcf_auto_prio(*back, prio);
tp->q = q;
tp->classify = tp_ops->classify;
- tp->classid = t->tcm_parent;
+ tp->classid = parent;
err = tp_ops->init(tp);
if (err) {
kfree(tp);
static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,
struct tcf_result *res)
{
-#if 0 /* XXX skb->fwmark, where is it? -DaveM */
u32 clid = skb->fwmark;
if (clid && (TC_H_MAJ(clid) == 0 ||
res->class = 0;
return 0;
}
-#endif
return -1;
}
return handle ? -EINVAL : 0;
}
-struct tcf_proto_ops fw_cls_ops = {
+struct tcf_proto_ops cls_fw_ops = {
NULL,
"fw",
fw_classify,
* (dst, protocol) are always specified,
so that we are able to hash them.
- * src may be exact, and may be wildcard, so that
- we can keep hash table plus one wildcard entry.
+ * src may be exact, or may be wildcard, so that
+ we can keep a hash table plus one wildcard entry.
* source port (or flow label) is important only if src is given.
IMPLEMENTATION.
- We use two level hash table: top level is keyed by
- destination address and protocol ID, every bucket contains list of
- "rsvp sessions", identified by destination address, protocol
- and DPI(="Destination Port ID"): triple (key, mask, offset).
+ We use a two level hash table: The top level is keyed by
+ destination address and protocol ID, every bucket contains a list
+ of "rsvp sessions", identified by destination address, protocol and
+ DPI(="Destination Port ID"): triple (key, mask, offset).
- Every bucket has smaller hash table keyed by source address
+ Every bucket has a smaller hash table keyed by source address
(cf. RSVP flowspec) and one wildcard entry for wildcard reservations.
- Every bucket is again list of "RSVP flows", selected by
+ Every bucket is again a list of "RSVP flows", selected by
source address and SPI(="Source Port ID" here rather than
"security parameter index"): triple (key, mask, offset).
NOTE 1. All the packets with IPv6 extension headers (but AH and ESP)
- and all fragmented packets go to best-effort traffic class.
+ and all fragmented packets go to the best-effort traffic class.
NOTE 2. Two "port id"'s seems to be redundant, rfc2207 requires
ah, esp (and udp,tcp) both *pi should coincide or one of them
should be wildcard.
- From the first sight, this redundancy is just waste of CPU
- resources. But, DPI and SPI add possibility to assign different
- priorities to GPIs. Look also note 4 about tunnels below.
+ At first sight, this redundancy is just a waste of CPU
+ resources. But DPI and SPI add the possibility to assign different
+ priorities to GPIs. Look also at note 4 about tunnels below.
NOTE 3. One complication is the case of tunneled packets.
- We implement it as the following: if the first lookup
- matches special session with "tunnelhdr" value not zero,
- flowid contains not true flow ID, but tunnel ID (1...255).
+ We implement it as following: if the first lookup
+ matches a special session with "tunnelhdr" value not zero,
+ flowid doesn't contain the true flow ID, but the tunnel ID (1...255).
In this case, we pull tunnelhdr bytes and restart lookup
- with tunnel ID added to list of keys. Simple and stupid 8)8)
+ with tunnel ID added to the list of keys. Simple and stupid 8)8)
It's enough for PIMREG and IPIP.
- NOTE 4. Two GPIs make possible to parse even GRE packets.
+ NOTE 4. Two GPIs make it possible to parse even GRE packets.
F.e. DPI can select ETH_P_IP (and necessary flags to make
tunnelhdr correct) in GRE protocol field and SPI matches
GRE key. Is it not nice? 8)8)
- Well, as result, despite of simplicity, we get pretty
- powerful clsssification engine.
- */
+ Well, as result, despite its simplicity, we get a pretty
+ powerful classification engine. */
#include <linux/config.h>
int err;
if (opt == NULL)
- return -EINVAL;
+ return handle ? -EINVAL : 0;
if (rtattr_parse(tb, TCA_RSVP_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)) < 0)
return -EINVAL;
* with a set of 32bit key/mask pairs at every node.
* Nodes reference next level hash tables etc.
*
- * This scheme is the best universal classifier
- * I managed to invent; it is not super-fast, but it is not slow
- * (provided you programmed it correctly), and enough general.
- * And its relative speed grows, when number of rules becomes larger.
+ * This scheme is the best universal classifier I managed to
+ * invent; it is not super-fast, but it is not slow (provided you
+ * program it correctly), and general enough. And its relative
+ * speed grows as the number of rules becomes larger.
*
- * Seems, it presents the best middle point between speed and
- * managability both by human and by machine.
+ * It seems that it represents the best middle point between
+ * speed and manageability both by human and by machine.
*
- * It is especially useful for link sharing and link sharing, combined
- * with QoS; pure RSVP need not such general approach and can use
+ * It is especially useful for link sharing combined with QoS;
+ * pure RSVP doesn't need such a general approach and can use
* much simpler (and faster) schemes, sort of cls_rsvp.c.
*/
#include <net/pkt_sched.h>
/*
- This text is NOT intended to be used for statistics collection,
- its purpose is to provide base for statistical multiplexing
+ This code is NOT intended to be used for statistics collection,
+ its purpose is to provide a base for statistical multiplexing
for controlled load service.
- If you need only statistics, run user level daemon, which will
- periodically read byte counters.
+ If you need only statistics, run a user level daemon which
+ periodically reads byte counters.
- Unfortunately, rate estimation is not very easy task.
- F.e. I did not find a simple way to estimate current peak rate
+ Unfortunately, rate estimation is not a very easy task.
+ F.e. I did not find a simple way to estimate the current peak rate
and even failed to formulate the problem 8)8)
- So that I preferred not to built estimator in scheduler,
+ So I preferred not to built an estimator into the scheduler,
but run this task separately.
Ideally, it should be kernel thread(s), but for now it runs
- from timers, which puts apparent top bounds on number of rated
- flows, but has minimal overhead on small, but enough
+ from timers, which puts apparent top bounds on the number of rated
+ flows, has minimal overhead on small, but is enough
to handle controlled load service, sets of aggregates.
We measure rate over A=(1<<interval) seconds and evaluate EWMA:
where W is chosen as negative power of 2: W = 2^(-ewma_log)
- Resulting time constant is:
+ The resulting time constant is:
T = A/(-ln(1-W))
NOTES.
- * Stored value for avbps is scaled by 2^5, so that maximal
+ * The stored value for avbps is scaled by 2^5, so that maximal
rate is ~1Gbit, avpps is scaled by 2^10.
- * Minimal interval is HZ/4=250msec (it is the least integer divisor
- both for HZ=100 and HZ=1024 8)), maximal interval
+ * Minimal interval is HZ/4=250msec (it is the greatest common divisor
+ for HZ=100 and HZ=1024 8)), maximal interval
is (HZ/4)*2^EST_MAX_INTERVAL = 8sec. Shorter intervals
are too expensive, longer ones can be implemented
at user level painlessly.
-----------------------------------------------------------------------
- Algorithm skeleton is taken from from NS simulator cbq.cc.
- If someone wants to check this text against LBL version,
- he should take into account that ONLY skeleton is borrowed,
- implementation is different. Particularly:
-
- --- WRR algorithm is different. Our version looks
- more reasonable (I hope) and works when quanta are allowed
- to be less than MTU, which always is the case, when real time
- classes have small rates. Note, that the statement of [3] is incomplete,
- Actually delay may be estimated even if class per-round allotment
- less than MTU. Namely, if per-round allotment is W*r_i,
- and r_1+...+r_k = r < 1
+ Algorithm skeleton was taken from from NS simulator cbq.cc.
+ If someone wants to check this code against the LBL version,
+ he should take into account that ONLY the skeleton was borrowed,
+ the implementation is different. Particularly:
+
+ --- The WRR algorithm is different. Our version looks more
+ reasonable (I hope) and works when quanta are allowed to be
+ less than MTU, which is always the case when real time classes
+ have small rates. Note, that the statement of [3] is
+ incomplete, delay may actually be estimated even if class
+ per-round allotment is less than MTU. Namely, if per-round
+ allotment is W*r_i, and r_1+...+r_k = r < 1
delay_i <= ([MTU/(W*r_i)]*W*r + W*r + k*MTU)/B
and C = MTU*r. The proof (if correct at all) is trivial.
- --- Seems, cbq-2.0 is not very accurate. At least, I cannot
- interpret some places, which look like wrong translation
- from NS. Anyone is advertised to found these differences
- and explain me, why I am wrong 8).
+ --- It seems that cbq-2.0 is not very accurate. At least, I cannot
+ interpret some places, which look like wrong translations
+ from NS. Anyone is advised to find these differences
+ and explain to me, why I am wrong 8).
--- Linux has no EOI event, so that we cannot estimate true class
idle time. Workaround is to consider the next dequeue event
- as sign that previous packet is finished. It is wrong because of
- internal device queueing, but on permanently loaded link it is true.
+ as sign that previous packet is finished. This is wrong because of
+ internal device queueing, but on a permanently loaded link it is true.
Moreover, combined with clock integrator, this scheme looks
- very close to ideal solution.
-*/
+ very close to an ideal solution. */
struct cbq_sched_data;
unsigned pmask;
struct timer_list delay_timer;
- struct timer_list wd_timer; /* Wathchdog timer, that
+ struct timer_list wd_timer; /* Watchdog timer,
started when CBQ has
backlog, but cannot
transmit just now */
transparently.
Namely, you can put link sharing rules (f.e. route based) at root of CBQ,
- so that it resolves to split nodes. Then packeta are classified
- by logical priority, or more specific classifier may be attached
- to split node.
+ so that it resolves to split nodes. Then packets are classified
+ by logical priority, or a more specific classifier may be attached
+ to the split node.
*/
static struct cbq_class *
}
/*
- * Step 3+n. If classifier selected link sharing class,
+ * Step 3+n. If classifier selected a link sharing class,
* apply agency specific classifier.
- * Repeat this procdure until we hit leaf node.
+ * Repeat this procdure until we hit a leaf node.
*/
head = cl;
}
/*
Unlink class from active chain.
- Note, that the same procedure is made directly in cbq_dequeue*
+ Note that this same procedure is done directly in cbq_dequeue*
during round-robin procedure.
*/
/*
That is not all.
- To maintain rate allocated to class,
+ To maintain the rate allocated to the class,
we add to undertime virtual clock,
- necassry to complete transmitted packet.
+ necesary to complete transmitted packet.
(len/phys_bandwidth has been already passed
to the moment of cbq_update)
*/
an arbitrary class is appropriate for ancestor-only
sharing, but not for toplevel algorithm.
- Our version is better, but slower, because requires
- two passes, but it is inavoidable with top-level sharing.
+ Our version is better, but slower, because it requires
+ two passes, but it is unavoidable with top-level sharing.
*/
if (q->toplevel == TC_CBQ_MAXLEVEL &&
q->quanta[prio];
}
if (cl->quantum <= 0 || cl->quantum>32*cl->qdisc->dev->mtu) {
- printk("Damn! %08x cl->quantum==%ld\n", cl->classid, cl->quantum);
- cl->quantum = 1;
+ printk(KERN_WARNING "CBQ: class %08x has bad quantum==%ld, repaired.\n", cl->classid, cl->quantum);
+ cl->quantum = cl->qdisc->dev->mtu/2 + 1;
}
}
}
CBQ presents a flexible universal algorithm for packet scheduling,
but it has pretty poor delay characteristics.
Round-robin scheduling and link-sharing goals
- apparently contradict to minimization of network delay and jitter.
+ apparently contradict minimization of network delay and jitter.
Moreover, correct handling of predictive flows seems to be
impossible in CBQ.
- CSZ presents more precise but less flexible and less efficient
- approach. As I understand, the main idea is to create
+ CSZ presents a more precise but less flexible and less efficient
+ approach. As I understand it, the main idea is to create
WFQ flows for each guaranteed service and to allocate
the rest of bandwith to dummy flow-0. Flow-0 comprises
the predictive services and the best effort traffic;
priority band allocated for predictive services, and the rest ---
to the best effort packets.
- Note, that in CSZ flows are NOT limited to their bandwidth.
- It is supposed, that flow passed admission control at the edge
- of QoS network and it more need no shaping. Any attempt to improve
- the flow or to shape it to a token bucket at intermediate hops
- will introduce undesired delays and raise jitter.
+ Note that in CSZ flows are NOT limited to their bandwidth. It
+ is supposed that the flow passed admission control at the edge
+ of the QoS network and it doesn't need further shaping. Any
+ attempt to improve the flow or to shape it to a token bucket
+ at intermediate hops will introduce undesired delays and raise
+ jitter.
At the moment CSZ is the only scheduler that provides
true guaranteed service. Another schemes (including CBQ)
do not provide guaranteed delay and randomize jitter.
- There exists the statement (Sally Floyd), that delay
- can be estimated by a IntServ compliant formulae.
+ There is a proof (Sally Floyd), that delay
+ can be estimated by a IntServ compliant formula.
This result is true formally, but it is wrong in principle.
It takes into account only round-robin delays,
ignoring delays introduced by link sharing i.e. overlimiting.
- Note, that temporary overlimits are inevitable because
- real links are not ideal, and true algorithm must take it
+ Note that temporary overlimits are inevitable because
+ real links are not ideal, and the real algorithm must take this
into account.
ALGORITHM.
--- Flow model.
- Let $m_a$ is number of backlogged bits in flow $a$.
- The flow is {\em active }, if $m_a > 0$.
- This number is discontinuous function of time;
+ Let $m_a$ is the number of backlogged bits in flow $a$.
+ The flow is {\em active}, if $m_a > 0$.
+ This number is a discontinuous function of time;
when a packet $i$ arrives:
\[
m_a(t_i+0) - m_a(t_i-0) = L^i,
\]
- where $L^i$ is the length of arrived packet.
+ where $L^i$ is the length of the arrived packet.
The flow queue is drained continuously until $m_a == 0$:
\[
{d m_a \over dt} = - { B r_a \over \sum_{b \in A} r_b}.
{d m_a \over dt} = - B r_a .
\]
More complicated hierarchical bandwidth allocation
- policies are possible, but, unfortunately, basic
- flows equation have simple solution only for proportional
+ policies are possible, but unfortunately, the basic
+ flow equations have a simple solution only for proportional
scaling.
--- Departure times.
- We calculate time until the last bit of packet will be sent:
+ We calculate the time until the last bit of packet is sent:
\[
E_a^i(t) = { m_a(t_i) - \delta_a(t) \over r_a },
\]
where $\delta_a(t)$ is number of bits drained since $t_i$.
We have to evaluate $E_a^i$ for all queued packets,
- then find packet with minimal $E_a^i$ and send it.
+ then find the packet with minimal $E_a^i$ and send it.
- It sounds good, but direct implementation of the algorithm
+ This sounds good, but direct implementation of the algorithm
is absolutely infeasible. Luckily, if flow rates
- are scaled proportionally, the equations have simple solution.
+ are scaled proportionally, the equations have a simple solution.
The differential equation for $E_a^i$ is
\[
$B \sum_{a \in A} r_a$ bits per round, that takes
$\sum_{a \in A} r_a$ seconds.
- Hence, $R(t)$ (round number) is monotonically increasing
+ Hence, $R(t)$ (round number) is a monotonically increasing
linear function of time when $A$ is not changed
\[
{ d R(t) \over dt } = { 1 \over \sum_{a \in A} r_a }
$F_a^i = R(t) + E_a^i(t)/B$ does not depend on time at all!
$R(t)$ does not depend on flow, so that $F_a^i$ can be
calculated only once on packet arrival, and we need not
- recalculation of $E$ numbers and resorting queues.
- Number $F_a^i$ is called finish number of the packet.
- It is just value of $R(t)$, when the last bit of packet
- will be sent out.
+ recalculate $E$ numbers and resorting queues.
+ The number $F_a^i$ is called finish number of the packet.
+ It is just the value of $R(t)$ when the last bit of packet
+ is sent out.
Maximal finish number on flow is called finish number of flow
and minimal one is "start number of flow".
Apparently, flow is active if and only if $F_a \leq R$.
- When packet of length $L_i$ bit arrives to flow $a$ at time $t_i$,
- we calculate number $F_a^i$ as:
+ When a packet of length $L_i$ bit arrives to flow $a$ at time $t_i$,
+ we calculate $F_a^i$ as:
If flow was inactive ($F_a < R$):
$F_a^i = R(t) + {L_i \over B r_a}$
These equations complete the algorithm specification.
- It looks pretty hairy, but there exists a simple
+ It looks pretty hairy, but there is a simple
procedure for solving these equations.
See procedure csz_update(), that is a generalization of
- algorithm from S. Keshav's thesis Chapter 3
+ the algorithm from S. Keshav's thesis Chapter 3
"Efficient Implementation of Fair Queeing".
NOTES.
* We implement only the simplest variant of CSZ,
- when flow-0 is explicit 4band priority fifo.
- It is bad, but we need "peek" operation in addition
+ when flow-0 is a explicit 4band priority fifo.
+ This is bad, but we need a "peek" operation in addition
to "dequeue" to implement complete CSZ.
- I do not want to make it, until it is not absolutely
+ I do not want to do that, unless it is absolutely
necessary.
* A primitive support for token bucket filtering
- presents too. It directly contradicts to CSZ, but
- though the Internet is on the globe ... :-)
- yet "the edges of the network" really exist.
+ presents itself too. It directly contradicts CSZ, but
+ even though the Internet is on the globe ... :-)
+ "the edges of the network" really exist.
BUGS.
* Fixed point arithmetic is overcomplicated, suboptimal and even
- wrong. Check it later.
-*/
+ wrong. Check it later. */
/* This number is arbitrary */
struct Qdisc_head qdisc_head = { &qdisc_head };
/* Kick device.
- Note, that this procedure can be called by watchdog timer, so that
+ Note, that this procedure can be called by a watchdog timer, so that
we do not check dev->tbusy flag here.
Returns: 0 - queue is empty.
}
/* Device kicked us out :(
- It is possible in three cases:
+ This is possible in three cases:
1. fastroute is enabled
2. device cannot determine busy state
/* Scan transmission queue and kick devices.
Deficiency: slow devices (ppp) and fast ones (100Mb ethernet)
- share one queue. It means, that if we have a lot of loaded ppp channels,
+ share one queue. This means that if we have a lot of loaded ppp channels,
we will scan a long list on every 100Mb EOI.
I have no idea how to solve it using only "anonymous" Linux mark_bh().
while (!dev->tbusy && (res = qdisc_restart(dev)) < 0)
/* NOTHING */;
- /* The explanation is necessary here.
+ /* An explanation is necessary here.
qdisc_restart called dev->hard_start_xmit,
if device is virtual, it could trigger one more
- dev_queue_xmit and new device could appear
- in active chain. In this case we cannot unlink
- empty queue, because we lost back pointer.
+ dev_queue_xmit and a new device could appear
+ in the active chain. In this case we cannot unlink
+ the empty queue, because we lost the back pointer.
No problem, we will unlink it during the next round.
*/
}
}
-/* Periodic watchdoc timer to recover of hard/soft device bugs. */
+/* Periodic watchdoc timer to recover from hard/soft device bugs. */
static void dev_do_watchdog(unsigned long dummy);
/* "NOOP" scheduler: the best scheduler, recommended for all interfaces
- in all curcumstances. It is difficult to invent anything more
- fast or cheap.
+ under all circumstances. It is difficult to invent anything faster or
+ cheaper.
*/
static int
for Congestion Avoidance", 1993, IEEE/ACM Transactions on Networking.
This file codes a "divisionless" version of RED algorithm
- written down in Fig.17 of the paper.
+ as written down in Fig.17 of the paper.
Short description.
------------------
- When new packet arrives we calculate average queue length:
+ When a new packet arrives we calculate the average queue length:
avg = (1-W)*avg + W*current_queue_len,
- W is filter time constant (choosen as 2^(-Wlog)), controlling
- inertia of algorithm. To allow larger bursts, W should be
+ W is the filter time constant (choosen 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).
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 negative power of two in order arithmetics to contain
+ is a negative power of two in order arithmetics to contain
only shifts.
Hard limit on queue length, should be chosen >qth_max
to allow packet bursts. This parameter does not
- affect algorithm behaviour and can be chosen
+ affect the algorithms behaviour and can be chosen
arbitrarily high (well, less than ram size)
- Really, this limit will never be achieved
+ Really, this limit will never be reached
if RED works correctly.
qth_min - bytes (should be < qth_max/2)
/*
The problem: ideally, average length queue recalcultion should
- be done over constant clock intervals. It is too expensive, so that
- calculation is driven by outgoing packets.
- When queue is idle we have to model this clock by hands.
+ 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 burst after idle time, i.e.
+ dummy packets as a burst after idle time, i.e.
q->qave *= (1-W)^m
- It is apparently overcomplicated solution (f.e. we have to precompute
- a table to make this calculation for reasonable time)
- I believe, that a simpler model may be used here,
+ 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.
*/
q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF];
Queuing using Deficit Round Robin", Proc. SIGCOMM 95.
- It is not the thing that usually called (W)FQ nowadays. It does not
- use any timestamp mechanism, but instead processes queues
- in round-robin order.
+ This is not the thing that is usually called (W)FQ nowadays.
+ It does not use any timestamp mechanism, but instead
+ processes queues in round-robin order.
ADVANTAGE:
DRAWBACKS:
- "Stochastic" -> It is not 100% fair.
- When hash collisions occur, several flows are considred as one.
+ When hash collisions occur, several flows are considered as one.
- "Round-robin" -> It introduces larger delays than virtual clock
- based schemes, and should not be used for isolation interactive
+ based schemes, and should not be used for isolating interactive
traffic from non-interactive. It means, that this scheduler
should be used as leaf of CBQ or P3, which put interactive traffic
to higher priority band.
This implementation limits maximal queue length to 128;
maximal mtu to 2^15-1; number of hash buckets to 1024.
The only goal of this restrictions was that all data
- fitted to one 4K page :-). Struct sfq_sched_data is
- organized in anti-cache manner: all the data for bucket
- scattered over different locations. It is not good,
- but it allowed to put it into 4K.
+ fit into one 4K page :-). Struct sfq_sched_data is
+ organized in anti-cache manner: all the data for a bucket
+ are scattered over different locations. This is not good,
+ but it allowed me to put it into 4K.
- It is easy to increase these values, but not in flight.
-*/
+ It is easy to increase these values, but not in flight. */
#define SFQ_DEPTH 128
#define SFQ_HASH_DIVISOR 1024
Description.
------------
- Data flow obeys TBF with rate R and depth B, if for any
- time interval t_i...t_f number of transmitted bits
+ A data flow obeys TBF with rate R and depth B, if for any
+ time interval t_i...t_f the number of transmitted bits
does not exceed B + R*(t_f-t_i).
Packetized version of this definition:
- sequence of packets of sizes s_i served at moments t_i
+ The sequence of packets of sizes s_i served at moments t_i
obeys TBF, if for any i<=k:
s_i+....+s_k <= B + R*(t_k - t_i)
Algorithm.
----------
- Let N(t_i) be B/R initially and N(t) grows continuously with time as:
+ Let N(t_i) be B/R initially and N(t) grow continuously with time as:
N(t+delta) = min{B/R, N(t) + delta}
- Actually, QoS requires two TBF to be applied to data stream.
+ Actually, QoS requires two TBF to be applied to a data stream.
One of them controls steady state burst size, another
- with rate P (peak rate) and depth M (equal to link MTU)
- limits bursts at smaller time scale.
+ one with rate P (peak rate) and depth M (equal to link MTU)
+ limits bursts at a smaller time scale.
- Apparently, P>R, and B>M. If P is infinity, this double
- TBF is equivalent to single one.
+ It is easy to see that P>R, and B>M. If P is infinity, this double
+ TBF is equivalent to a single one.
When TBF works in reshaping mode, latency is estimated as:
NOTES.
------
- If TBF throttles, it starts watchdog timer, which will wake up it
- when it will be ready to transmit.
- Note, that minimal timer resolution is 1/HZ.
- If no new packets will arrive during this period,
- or device will not be awaken by EOI for previous packet,
- tbf could stop its activity for 1/HZ.
+ If TBF throttles, it starts a watchdog timer, which will wake it up
+ when it is ready to transmit.
+ Note that the minimal timer resolution is 1/HZ.
+ If no new packets arrive during this period,
+ or if the device is not awaken by EOI for some previous packet,
+ TBF can stop its activity for 1/HZ.
- It means, that with depth B, the maximal rate is
+ This means, that with depth B, the maximal rate is
R_crit = B*HZ
- F.e. for 10Mbit ethernet and HZ=100 minimal allowed B is ~10Kbytes.
+ F.e. for 10Mbit ethernet and HZ=100 the minimal allowed B is ~10Kbytes.
- Note, that peak rate TBF is much more tough: with MTU 1500
- P_crit = 150Kbytes/sec. So that, if you need greater peak
+ Note that the peak rate TBF is much more tough: with MTU 1500
+ P_crit = 150Kbytes/sec. So, if you need greater peak
rates, use alpha with HZ=1000 :-)
*/
return 1;
}
- /* Drop action: undo the things that we just made,
+ /* Drop action: undo the things that we just did,
* i.e. make tail drop
*/
add_timer(&q->wd_timer);
}
- /* Maybe, we have in queue a shorter packet,
+ /* Maybe we have a shorter packet in the queue,
which can be sent now. It sounds cool,
- but, however, wrong in principle.
- We MUST NOT reorder packets in these curcumstances.
+ but, however, this is wrong in principle.
+ We MUST NOT reorder packets under these circumstances.
- Really, if we splitted flow to independent
- subflows, it would be very good solution.
- It is main idea of all FQ algorithms
+ Really, if we split the flow into independent
+ subflows, it would be a very good solution.
+ This is the main idea of all FQ algorithms
(cf. CSZ, HPFQ, HFCS)
*/
__skb_queue_head(&sch->q, skb);
How to setup it.
----------------
- After loading this module you will find new device teqlN
- and new qdisc with the same name. To join a slave to equalizer
+ After loading this module you will find a new device teqlN
+ and new qdisc with the same name. To join a slave to the equalizer
you should just set this qdisc on a device f.e.
# tc qdisc add dev eth0 root teql0
Applicability.
--------------
- 1. Slave devices MUST be active devices i.e. must raise tbusy
- signal and generate EOI event. If you want to equalize virtual devices
- sort of tunnels, use normal eql device.
+ 1. Slave devices MUST be active devices, i.e., they must raise the tbusy
+ signal and generate EOI events. If you want to equalize virtual devices
+ like tunnels, use a normal eql device.
2. This device puts no limitations on physical slave characteristics
f.e. it will equalize 9600baud line and 100Mb ethernet perfectly :-)
- Certainly, large difference in link speeds will make resulting eqalized
- link unusable, because of huge packet reordering. I estimated upper
- useful difference as ~10 times.
- 3. If slave requires address resolution, only protocols using
- neighbour cache (IPv4/IPv6) will work over equalized link.
- Another protocols still are allowed to use slave device directly,
+ Certainly, large difference in link speeds will make the resulting
+ eqalized link unusable, because of huge packet reordering.
+ I estimate an upper useful difference as ~10 times.
+ 3. If the slave requires address resolution, only protocols using
+ neighbour cache (IPv4/IPv6) will work over the equalized link.
+ Other protocols are still allowed to use the slave device directly,
which will not break load balancing, though native slave
- traffic will have the highest priority.
- */
+ traffic will have the highest priority. */
struct teql_master
{
NEXT_SLAVE(prev) = NEXT_SLAVE(q);
if (q == master->slaves) {
master->slaves = NEXT_SLAVE(q);
- if (q == master->slaves)
+ if (q == master->slaves) {
master->slaves = NULL;
+ qdisc_reset(master->dev.qdisc);
+ }
}
skb_queue_purge(&dat->q);
teql_neigh_release(xchg(&dat->ncache, NULL));
struct Qdisc *start, *q;
int busy;
int nores;
+ int len = skb->len;
struct sk_buff *skb_res = NULL;
dev->tbusy = 1;
if (slave->hard_start_xmit(skb, slave) == 0) {
master->slaves = NEXT_SLAVE(q);
dev->tbusy = 0;
+ master->stats.tx_packets++;
+ master->stats.tx_bytes += len;
return 0;
}
break;
case 1:
- nores = 1;
- break;
- default:
master->slaves = NEXT_SLAVE(q);
dev->tbusy = 0;
return 0;
+ default:
+ nores = 1;
+ break;
}
__skb_pull(skb, skb->nh.raw - skb->data);
}
dev->tbusy = busy;
if (busy)
return 1;
+ master->stats.tx_errors++;
drop:
+ master->stats.tx_dropped++;
dev_kfree_skb(skb);
return 0;
}
m->dev.mtu = mtu;
m->dev.flags = (m->dev.flags&~FMASK) | flags;
+ m->dev.tbusy = 0;
MOD_INC_USE_COUNT;
return 0;
}