Merge 5.4.248 into android11-5.4-lts
Changes in 5.4.248 test_firmware: fix a memory leak with reqs buffer KEYS: asymmetric: Copy sig and digest in public_key_verify_signature() dasd: refactor dasd_ioctl_information s390/dasd: Use correct lock while counting channel queue length power: supply: ab8500: Fix external_power_changed race power: supply: sc27xx: Fix external_power_changed race power: supply: bq27xxx: Use mod_delayed_work() instead of cancel() + schedule() ARM: dts: vexpress: add missing cache properties power: supply: Ratelimit no data debug output platform/x86: asus-wmi: Ignore WMI events with codes 0x7B, 0xC0 regulator: Fix error checking for debugfs_create_dir irqchip/meson-gpio: Mark OF related data as maybe unused power: supply: Fix logic checking if system is running from battery btrfs: handle memory allocation failure in btrfs_csum_one_bio parisc: Improve cache flushing for PCXL in arch_sync_dma_for_cpu() parisc: Flush gatt writes and adjust gatt mask in parisc_agp_mask_memory() MIPS: Alchemy: fix dbdma2 mips: Move initrd_start check after initrd address sanitisation. xen/blkfront: Only check REQ_FUA for writes drm:amd:amdgpu: Fix missing buffer object unlock in failure path ocfs2: fix use-after-free when unmounting read-only filesystem ocfs2: check new file size on fallocate call nios2: dts: Fix tse_mac "max-frame-size" property nilfs2: fix incomplete buffer cleanup in nilfs_btnode_abort_change_key() nilfs2: fix possible out-of-bounds segment allocation in resize ioctl kexec: support purgatories with .text.hot sections powerpc/purgatory: remove PGO flags nouveau: fix client work fence deletion race RDMA/uverbs: Restrict usage of privileged QKEYs net: usb: qmi_wwan: add support for Compal RXM-G1 ALSA: hda/realtek: Add a quirk for Compaq N14JP6 Remove DECnet support from kernel USB: serial: option: add Quectel EM061KGL series serial: lantiq: add missing interrupt ack usb: dwc3: gadget: Reset num TRBs before giving back the request spi: spi-fsl-dspi: Remove unused chip->void_write_data spi: fsl-dspi: avoid SCK glitches with continuous transfers netfilter: nfnetlink: skip error delivery on batch in case of ENOMEM ping6: Fix send to link-local addresses with VRF. net/sched: cls_u32: Fix reference counter leak leading to overflow RDMA/rxe: Remove the unused variable obj RDMA/rxe: Removed unused name from rxe_task struct RDMA/rxe: Fix the use-before-initialization error of resp_pkts iavf: remove mask from iavf_irq_enable_queues() IB/uverbs: Fix to consider event queue closing also upon non-blocking mode IB/isert: Fix dead lock in ib_isert IB/isert: Fix possible list corruption in CMA handler IB/isert: Fix incorrect release of isert connection ipvlan: fix bound dev checking for IPv6 l3s mode sctp: fix an error code in sctp_sf_eat_auth() igb: fix nvm.ops.read() error handling drm/nouveau/dp: check for NULL nv_connector->native_mode drm/nouveau/kms: Don't change EDID when it hasn't actually changed drm/nouveau: add nv_encoder pointer check for NULL net/sched: cls_api: Fix lockup on flushing explicitly created chain net: lapbether: only support ethernet devices net: tipc: resize nlattr array to correct size selftests/ptp: Fix timestamp printf format for PTP_SYS_OFFSET afs: Fix vlserver probe RTT handling neighbour: Remove unused inline function neigh_key_eq16() net: Remove unused inline function dst_hold_and_use() neighbour: delete neigh_lookup_nodev as not used drm/nouveau/kms: Fix NULL pointer dereference in nouveau_connector_detect_depth mmc: block: ensure error propagation for non-blk Linux 5.4.248 Change-Id: Ie9ec82f0e64b95b2dcce2a754bc6e907c9231db3 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
commit
f4bff64ed2
@ -825,10 +825,6 @@
|
||||
|
||||
debugpat [X86] Enable PAT debugging
|
||||
|
||||
decnet.addr= [HW,NET]
|
||||
Format: <area>[,<node>]
|
||||
See also Documentation/networking/decnet.txt.
|
||||
|
||||
default_hugepagesz=
|
||||
[same as hugepagesz=] The size of the default
|
||||
HugeTLB page size. This is the size represented by
|
||||
|
@ -34,13 +34,14 @@ Table : Subdirectories in /proc/sys/net
|
||||
========= =================== = ========== ==================
|
||||
Directory Content Directory Content
|
||||
========= =================== = ========== ==================
|
||||
core General parameter appletalk Appletalk protocol
|
||||
unix Unix domain sockets netrom NET/ROM
|
||||
802 E802 protocol ax25 AX25
|
||||
ethernet Ethernet protocol rose X.25 PLP layer
|
||||
ipv4 IP version 4 x25 X.25 protocol
|
||||
bridge Bridging decnet DEC net
|
||||
ipv6 IP version 6 tipc TIPC
|
||||
802 E802 protocol mptcp Multipath TCP
|
||||
appletalk Appletalk protocol netfilter Network Filter
|
||||
ax25 AX25 netrom NET/ROM
|
||||
bridge Bridging rose X.25 PLP layer
|
||||
core General parameter tipc TIPC
|
||||
ethernet Ethernet protocol unix Unix domain sockets
|
||||
ipv4 IP version 4 x25 X.25 protocol
|
||||
ipv6 IP version 6
|
||||
========= =================== = ========== ==================
|
||||
|
||||
1. /proc/sys/net/core - Network core options
|
||||
|
@ -302,7 +302,6 @@ Code Seq# Include File Comments
|
||||
0x89 00-06 arch/x86/include/asm/sockios.h
|
||||
0x89 0B-DF linux/sockios.h
|
||||
0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range
|
||||
0x89 E0-EF linux/dn.h PROTOPRIVATE range
|
||||
0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range
|
||||
0x8B all linux/wireless.h
|
||||
0x8C 00-3F WiNRADiO driver
|
||||
|
@ -1,230 +0,0 @@
|
||||
Linux DECnet Networking Layer Information
|
||||
===========================================
|
||||
|
||||
1) Other documentation....
|
||||
|
||||
o Project Home Pages
|
||||
http://www.chygwyn.com/ - Kernel info
|
||||
http://linux-decnet.sourceforge.net/ - Userland tools
|
||||
http://www.sourceforge.net/projects/linux-decnet/ - Status page
|
||||
|
||||
2) Configuring the kernel
|
||||
|
||||
Be sure to turn on the following options:
|
||||
|
||||
CONFIG_DECNET (obviously)
|
||||
CONFIG_PROC_FS (to see what's going on)
|
||||
CONFIG_SYSCTL (for easy configuration)
|
||||
|
||||
if you want to try out router support (not properly debugged yet)
|
||||
you'll need the following options as well...
|
||||
|
||||
CONFIG_DECNET_ROUTER (to be able to add/delete routes)
|
||||
CONFIG_NETFILTER (will be required for the DECnet routing daemon)
|
||||
|
||||
Don't turn on SIOCGIFCONF support for DECnet unless you are really sure
|
||||
that you need it, in general you won't and it can cause ifconfig to
|
||||
malfunction.
|
||||
|
||||
Run time configuration has changed slightly from the 2.4 system. If you
|
||||
want to configure an endnode, then the simplified procedure is as follows:
|
||||
|
||||
o Set the MAC address on your ethernet card before starting _any_ other
|
||||
network protocols.
|
||||
|
||||
As soon as your network card is brought into the UP state, DECnet should
|
||||
start working. If you need something more complicated or are unsure how
|
||||
to set the MAC address, see the next section. Also all configurations which
|
||||
worked with 2.4 will work under 2.5 with no change.
|
||||
|
||||
3) Command line options
|
||||
|
||||
You can set a DECnet address on the kernel command line for compatibility
|
||||
with the 2.4 configuration procedure, but in general it's not needed any more.
|
||||
If you do st a DECnet address on the command line, it has only one purpose
|
||||
which is that its added to the addresses on the loopback device.
|
||||
|
||||
With 2.4 kernels, DECnet would only recognise addresses as local if they
|
||||
were added to the loopback device. In 2.5, any local interface address
|
||||
can be used to loop back to the local machine. Of course this does not
|
||||
prevent you adding further addresses to the loopback device if you
|
||||
want to.
|
||||
|
||||
N.B. Since the address list of an interface determines the addresses for
|
||||
which "hello" messages are sent, if you don't set an address on the loopback
|
||||
interface then you won't see any entries in /proc/net/neigh for the local
|
||||
host until such time as you start a connection. This doesn't affect the
|
||||
operation of the local communications in any other way though.
|
||||
|
||||
The kernel command line takes options looking like the following:
|
||||
|
||||
decnet.addr=1,2
|
||||
|
||||
the two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels
|
||||
and early 2.3.xx kernels, you must use a comma when specifying the
|
||||
DECnet address like this. For more recent 2.3.xx kernels, you may
|
||||
use almost any character except space, although a `.` would be the most
|
||||
obvious choice :-)
|
||||
|
||||
There used to be a third number specifying the node type. This option
|
||||
has gone away in favour of a per interface node type. This is now set
|
||||
using /proc/sys/net/decnet/conf/<dev>/forwarding. This file can be
|
||||
set with a single digit, 0=EndNode, 1=L1 Router and 2=L2 Router.
|
||||
|
||||
There are also equivalent options for modules. The node address can
|
||||
also be set through the /proc/sys/net/decnet/ files, as can other system
|
||||
parameters.
|
||||
|
||||
Currently the only supported devices are ethernet and ip_gre. The
|
||||
ethernet address of your ethernet card has to be set according to the DECnet
|
||||
address of the node in order for it to be autoconfigured (and then appear in
|
||||
/proc/net/decnet_dev). There is a utility available at the above
|
||||
FTP sites called dn2ethaddr which can compute the correct ethernet
|
||||
address to use. The address can be set by ifconfig either before or
|
||||
at the time the device is brought up. If you are using RedHat you can
|
||||
add the line:
|
||||
|
||||
MACADDR=AA:00:04:00:03:04
|
||||
|
||||
or something similar, to /etc/sysconfig/network-scripts/ifcfg-eth0 or
|
||||
wherever your network card's configuration lives. Setting the MAC address
|
||||
of your ethernet card to an address starting with "hi-ord" will cause a
|
||||
DECnet address which matches to be added to the interface (which you can
|
||||
verify with iproute2).
|
||||
|
||||
The default device for routing can be set through the /proc filesystem
|
||||
by setting /proc/sys/net/decnet/default_device to the
|
||||
device you want DECnet to route packets out of when no specific route
|
||||
is available. Usually this will be eth0, for example:
|
||||
|
||||
echo -n "eth0" >/proc/sys/net/decnet/default_device
|
||||
|
||||
If you don't set the default device, then it will default to the first
|
||||
ethernet card which has been autoconfigured as described above. You can
|
||||
confirm that by looking in the default_device file of course.
|
||||
|
||||
There is a list of what the other files under /proc/sys/net/decnet/ do
|
||||
on the kernel patch web site (shown above).
|
||||
|
||||
4) Run time kernel configuration
|
||||
|
||||
This is either done through the sysctl/proc interface (see the kernel web
|
||||
pages for details on what the various options do) or through the iproute2
|
||||
package in the same way as IPv4/6 configuration is performed.
|
||||
|
||||
Documentation for iproute2 is included with the package, although there is
|
||||
as yet no specific section on DECnet, most of the features apply to both
|
||||
IP and DECnet, albeit with DECnet addresses instead of IP addresses and
|
||||
a reduced functionality.
|
||||
|
||||
If you want to configure a DECnet router you'll need the iproute2 package
|
||||
since its the _only_ way to add and delete routes currently. Eventually
|
||||
there will be a routing daemon to send and receive routing messages for
|
||||
each interface and update the kernel routing tables accordingly. The
|
||||
routing daemon will use netfilter to listen to routing packets, and
|
||||
rtnetlink to update the kernels routing tables.
|
||||
|
||||
The DECnet raw socket layer has been removed since it was there purely
|
||||
for use by the routing daemon which will now use netfilter (a much cleaner
|
||||
and more generic solution) instead.
|
||||
|
||||
5) How can I tell if its working ?
|
||||
|
||||
Here is a quick guide of what to look for in order to know if your DECnet
|
||||
kernel subsystem is working.
|
||||
|
||||
- Is the node address set (see /proc/sys/net/decnet/node_address)
|
||||
- Is the node of the correct type
|
||||
(see /proc/sys/net/decnet/conf/<dev>/forwarding)
|
||||
- Is the Ethernet MAC address of each Ethernet card set to match
|
||||
the DECnet address. If in doubt use the dn2ethaddr utility available
|
||||
at the ftp archive.
|
||||
- If the previous two steps are satisfied, and the Ethernet card is up,
|
||||
you should find that it is listed in /proc/net/decnet_dev and also
|
||||
that it appears as a directory in /proc/sys/net/decnet/conf/. The
|
||||
loopback device (lo) should also appear and is required to communicate
|
||||
within a node.
|
||||
- If you have any DECnet routers on your network, they should appear
|
||||
in /proc/net/decnet_neigh, otherwise this file will only contain the
|
||||
entry for the node itself (if it doesn't check to see if lo is up).
|
||||
- If you want to send to any node which is not listed in the
|
||||
/proc/net/decnet_neigh file, you'll need to set the default device
|
||||
to point to an Ethernet card with connection to a router. This is
|
||||
again done with the /proc/sys/net/decnet/default_device file.
|
||||
- Try starting a simple server and client, like the dnping/dnmirror
|
||||
over the loopback interface. With luck they should communicate.
|
||||
For this step and those after, you'll need the DECnet library
|
||||
which can be obtained from the above ftp sites as well as the
|
||||
actual utilities themselves.
|
||||
- If this seems to work, then try talking to a node on your local
|
||||
network, and see if you can obtain the same results.
|
||||
- At this point you are on your own... :-)
|
||||
|
||||
6) How to send a bug report
|
||||
|
||||
If you've found a bug and want to report it, then there are several things
|
||||
you can do to help me work out exactly what it is that is wrong. Useful
|
||||
information (_most_ of which _is_ _essential_) includes:
|
||||
|
||||
- What kernel version are you running ?
|
||||
- What version of the patch are you running ?
|
||||
- How far though the above set of tests can you get ?
|
||||
- What is in the /proc/decnet* files and /proc/sys/net/decnet/* files ?
|
||||
- Which services are you running ?
|
||||
- Which client caused the problem ?
|
||||
- How much data was being transferred ?
|
||||
- Was the network congested ?
|
||||
- How can the problem be reproduced ?
|
||||
- Can you use tcpdump to get a trace ? (N.B. Most (all?) versions of
|
||||
tcpdump don't understand how to dump DECnet properly, so including
|
||||
the hex listing of the packet contents is _essential_, usually the -x flag.
|
||||
You may also need to increase the length grabbed with the -s flag. The
|
||||
-e flag also provides very useful information (ethernet MAC addresses))
|
||||
|
||||
7) MAC FAQ
|
||||
|
||||
A quick FAQ on ethernet MAC addresses to explain how Linux and DECnet
|
||||
interact and how to get the best performance from your hardware.
|
||||
|
||||
Ethernet cards are designed to normally only pass received network frames
|
||||
to a host computer when they are addressed to it, or to the broadcast address.
|
||||
|
||||
Linux has an interface which allows the setting of extra addresses for
|
||||
an ethernet card to listen to. If the ethernet card supports it, the
|
||||
filtering operation will be done in hardware, if not the extra unwanted packets
|
||||
received will be discarded by the host computer. In the latter case,
|
||||
significant processor time and bus bandwidth can be used up on a busy
|
||||
network (see the NAPI documentation for a longer explanation of these
|
||||
effects).
|
||||
|
||||
DECnet makes use of this interface to allow running DECnet on an ethernet
|
||||
card which has already been configured using TCP/IP (presumably using the
|
||||
built in MAC address of the card, as usual) and/or to allow multiple DECnet
|
||||
addresses on each physical interface. If you do this, be aware that if your
|
||||
ethernet card doesn't support perfect hashing in its MAC address filter
|
||||
then your computer will be doing more work than required. Some cards
|
||||
will simply set themselves into promiscuous mode in order to receive
|
||||
packets from the DECnet specified addresses. So if you have one of these
|
||||
cards its better to set the MAC address of the card as described above
|
||||
to gain the best efficiency. Better still is to use a card which supports
|
||||
NAPI as well.
|
||||
|
||||
|
||||
8) Mailing list
|
||||
|
||||
If you are keen to get involved in development, or want to ask questions
|
||||
about configuration, or even just report bugs, then there is a mailing
|
||||
list that you can join, details are at:
|
||||
|
||||
http://sourceforge.net/mail/?group_id=4993
|
||||
|
||||
9) Legal Info
|
||||
|
||||
The Linux DECnet project team have placed their code under the GPL. The
|
||||
software is provided "as is" and without warranty express or implied.
|
||||
DECnet is a trademark of Compaq. This software is not a product of
|
||||
Compaq. We acknowledge the help of people at Compaq in providing extra
|
||||
documentation above and beyond what was previously publicly available.
|
||||
|
||||
Steve Whitehouse <SteveW@ACM.org>
|
||||
|
@ -4617,13 +4617,6 @@ F: include/uapi/linux/dccp.h
|
||||
F: include/linux/tfrc.h
|
||||
F: net/dccp/
|
||||
|
||||
DECnet NETWORK LAYER
|
||||
W: http://linux-decnet.sourceforge.net
|
||||
L: linux-decnet-user@lists.sourceforge.net
|
||||
S: Orphan
|
||||
F: Documentation/networking/decnet.txt
|
||||
F: net/decnet/
|
||||
|
||||
DECSTATION PLATFORM SUPPORT
|
||||
M: "Maciej W. Rozycki" <macro@linux-mips.org>
|
||||
L: linux-mips@vger.kernel.org
|
||||
|
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 247
|
||||
SUBLEVEL = 248
|
||||
EXTRAVERSION =
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
|
@ -132,6 +132,7 @@
|
||||
reg = <0x2c0f0000 0x1000>;
|
||||
interrupts = <0 84 4>;
|
||||
cache-level = <2>;
|
||||
cache-unified;
|
||||
};
|
||||
|
||||
pmu {
|
||||
|
@ -30,6 +30,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/dma-map-ops.h> /* for dma_default_coherent */
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
@ -623,17 +624,18 @@ u32 au1xxx_dbdma_put_source(u32 chanid, dma_addr_t buf, int nbytes, u32 flags)
|
||||
dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
|
||||
|
||||
/*
|
||||
* There is an errata on the Au1200/Au1550 parts that could result
|
||||
* in "stale" data being DMA'ed. It has to do with the snoop logic on
|
||||
* the cache eviction buffer. DMA_NONCOHERENT is on by default for
|
||||
* these parts. If it is fixed in the future, these dma_cache_inv will
|
||||
* just be nothing more than empty macros. See io.h.
|
||||
* There is an erratum on certain Au1200/Au1550 revisions that could
|
||||
* result in "stale" data being DMA'ed. It has to do with the snoop
|
||||
* logic on the cache eviction buffer. dma_default_coherent is set
|
||||
* to false on these parts.
|
||||
*/
|
||||
dma_cache_wback_inv((unsigned long)buf, nbytes);
|
||||
if (!dma_default_coherent)
|
||||
dma_cache_wback_inv(KSEG0ADDR(buf), nbytes);
|
||||
dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
|
||||
wmb(); /* drain writebuffer */
|
||||
dma_cache_wback_inv((unsigned long)dp, sizeof(*dp));
|
||||
ctp->chan_ptr->ddma_dbell = 0;
|
||||
wmb(); /* force doorbell write out to dma engine */
|
||||
|
||||
/* Get next descriptor pointer. */
|
||||
ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
|
||||
@ -685,17 +687,18 @@ u32 au1xxx_dbdma_put_dest(u32 chanid, dma_addr_t buf, int nbytes, u32 flags)
|
||||
dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
|
||||
#endif
|
||||
/*
|
||||
* There is an errata on the Au1200/Au1550 parts that could result in
|
||||
* "stale" data being DMA'ed. It has to do with the snoop logic on the
|
||||
* cache eviction buffer. DMA_NONCOHERENT is on by default for these
|
||||
* parts. If it is fixed in the future, these dma_cache_inv will just
|
||||
* be nothing more than empty macros. See io.h.
|
||||
* There is an erratum on certain Au1200/Au1550 revisions that could
|
||||
* result in "stale" data being DMA'ed. It has to do with the snoop
|
||||
* logic on the cache eviction buffer. dma_default_coherent is set
|
||||
* to false on these parts.
|
||||
*/
|
||||
dma_cache_inv((unsigned long)buf, nbytes);
|
||||
if (!dma_default_coherent)
|
||||
dma_cache_inv(KSEG0ADDR(buf), nbytes);
|
||||
dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
|
||||
wmb(); /* drain writebuffer */
|
||||
dma_cache_wback_inv((unsigned long)dp, sizeof(*dp));
|
||||
ctp->chan_ptr->ddma_dbell = 0;
|
||||
wmb(); /* force doorbell write out to dma engine */
|
||||
|
||||
/* Get next descriptor pointer. */
|
||||
ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
|
||||
|
@ -53,8 +53,6 @@ CONFIG_IPV6_SUBTREES=y
|
||||
CONFIG_NETWORK_SECMARK=y
|
||||
CONFIG_IP_SCTP=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_DECNET_ROUTER=y
|
||||
# CONFIG_WIRELESS is not set
|
||||
# CONFIG_UEVENT_HELPER is not set
|
||||
# CONFIG_FW_LOADER is not set
|
||||
|
@ -49,8 +49,6 @@ CONFIG_IPV6_SUBTREES=y
|
||||
CONFIG_NETWORK_SECMARK=y
|
||||
CONFIG_IP_SCTP=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_DECNET_ROUTER=y
|
||||
# CONFIG_WIRELESS is not set
|
||||
# CONFIG_UEVENT_HELPER is not set
|
||||
# CONFIG_FW_LOADER is not set
|
||||
|
@ -48,8 +48,6 @@ CONFIG_IPV6_SUBTREES=y
|
||||
CONFIG_NETWORK_SECMARK=y
|
||||
CONFIG_IP_SCTP=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_DECNET_ROUTER=y
|
||||
# CONFIG_WIRELESS is not set
|
||||
# CONFIG_UEVENT_HELPER is not set
|
||||
# CONFIG_FW_LOADER is not set
|
||||
|
@ -69,7 +69,6 @@ CONFIG_IP_NF_RAW=m
|
||||
CONFIG_IP_NF_ARPTABLES=m
|
||||
CONFIG_IP_NF_ARPFILTER=m
|
||||
CONFIG_IP_NF_ARP_MANGLE=m
|
||||
CONFIG_DECNET_NF_GRABULATOR=m
|
||||
CONFIG_BRIDGE_NF_EBTABLES=m
|
||||
CONFIG_BRIDGE_EBT_BROUTE=m
|
||||
CONFIG_BRIDGE_EBT_T_FILTER=m
|
||||
@ -99,7 +98,6 @@ CONFIG_ATM_MPOA=m
|
||||
CONFIG_ATM_BR2684=m
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_LLC2=m
|
||||
CONFIG_ATALK=m
|
||||
CONFIG_DEV_APPLETALK=m
|
||||
|
@ -106,7 +106,6 @@ CONFIG_IP6_NF_FILTER=m
|
||||
CONFIG_IP6_NF_TARGET_REJECT=m
|
||||
CONFIG_IP6_NF_MANGLE=m
|
||||
CONFIG_IP6_NF_RAW=m
|
||||
CONFIG_DECNET_NF_GRABULATOR=m
|
||||
CONFIG_BRIDGE_NF_EBTABLES=m
|
||||
CONFIG_BRIDGE_EBT_BROUTE=m
|
||||
CONFIG_BRIDGE_EBT_T_FILTER=m
|
||||
@ -127,7 +126,6 @@ CONFIG_BRIDGE_EBT_REDIRECT=m
|
||||
CONFIG_BRIDGE_EBT_SNAT=m
|
||||
CONFIG_BRIDGE_EBT_LOG=m
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_CBQ=m
|
||||
CONFIG_NET_SCH_HTB=m
|
||||
|
@ -117,7 +117,6 @@ CONFIG_IP6_NF_FILTER=m
|
||||
CONFIG_IP6_NF_TARGET_REJECT=m
|
||||
CONFIG_IP6_NF_MANGLE=m
|
||||
CONFIG_IP6_NF_RAW=m
|
||||
CONFIG_DECNET_NF_GRABULATOR=m
|
||||
CONFIG_BRIDGE_NF_EBTABLES=m
|
||||
CONFIG_BRIDGE_EBT_BROUTE=m
|
||||
CONFIG_BRIDGE_EBT_T_FILTER=m
|
||||
@ -147,7 +146,6 @@ CONFIG_ATM_MPOA=m
|
||||
CONFIG_ATM_BR2684=m
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_LLC2=m
|
||||
CONFIG_ATALK=m
|
||||
CONFIG_DEV_APPLETALK=m
|
||||
|
@ -200,7 +200,6 @@ CONFIG_IP6_NF_TARGET_REJECT=m
|
||||
CONFIG_IP6_NF_MANGLE=m
|
||||
CONFIG_IP6_NF_RAW=m
|
||||
CONFIG_IP6_NF_SECURITY=m
|
||||
CONFIG_DECNET_NF_GRABULATOR=m
|
||||
CONFIG_BRIDGE_NF_EBTABLES=m
|
||||
CONFIG_BRIDGE_EBT_BROUTE=m
|
||||
CONFIG_BRIDGE_EBT_T_FILTER=m
|
||||
@ -234,7 +233,6 @@ CONFIG_ATM_BR2684=m
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_VLAN_8021Q_GVRP=y
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_LLC2=m
|
||||
CONFIG_ATALK=m
|
||||
CONFIG_DEV_APPLETALK=m
|
||||
|
@ -198,7 +198,6 @@ CONFIG_IP6_NF_TARGET_REJECT=m
|
||||
CONFIG_IP6_NF_MANGLE=m
|
||||
CONFIG_IP6_NF_RAW=m
|
||||
CONFIG_IP6_NF_SECURITY=m
|
||||
CONFIG_DECNET_NF_GRABULATOR=m
|
||||
CONFIG_BRIDGE_NF_EBTABLES=m
|
||||
CONFIG_BRIDGE_EBT_BROUTE=m
|
||||
CONFIG_BRIDGE_EBT_T_FILTER=m
|
||||
@ -232,7 +231,6 @@ CONFIG_ATM_BR2684=m
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_VLAN_8021Q_GVRP=y
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_LLC2=m
|
||||
CONFIG_ATALK=m
|
||||
CONFIG_DEV_APPLETALK=m
|
||||
|
@ -116,7 +116,6 @@ CONFIG_IP6_NF_FILTER=m
|
||||
CONFIG_IP6_NF_TARGET_REJECT=m
|
||||
CONFIG_IP6_NF_MANGLE=m
|
||||
CONFIG_IP6_NF_RAW=m
|
||||
CONFIG_DECNET_NF_GRABULATOR=m
|
||||
CONFIG_BRIDGE_NF_EBTABLES=m
|
||||
CONFIG_BRIDGE_EBT_BROUTE=m
|
||||
CONFIG_BRIDGE_EBT_T_FILTER=m
|
||||
@ -137,7 +136,6 @@ CONFIG_BRIDGE_EBT_REDIRECT=m
|
||||
CONFIG_BRIDGE_EBT_SNAT=m
|
||||
CONFIG_BRIDGE_EBT_LOG=m
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_CBQ=m
|
||||
CONFIG_NET_SCH_HTB=m
|
||||
|
@ -190,10 +190,6 @@ static unsigned long __init init_initrd(void)
|
||||
pr_err("initrd start must be page aligned\n");
|
||||
goto disable;
|
||||
}
|
||||
if (initrd_start < PAGE_OFFSET) {
|
||||
pr_err("initrd start < PAGE_OFFSET\n");
|
||||
goto disable;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanitize initrd addresses. For example firmware
|
||||
@ -206,6 +202,11 @@ static unsigned long __init init_initrd(void)
|
||||
initrd_end = (unsigned long)__va(end);
|
||||
initrd_start = (unsigned long)__va(__pa(initrd_start));
|
||||
|
||||
if (initrd_start < PAGE_OFFSET) {
|
||||
pr_err("initrd start < PAGE_OFFSET\n");
|
||||
goto disable;
|
||||
}
|
||||
|
||||
ROOT_DEV = Root_RAM0;
|
||||
return PFN_UP(end);
|
||||
disable:
|
||||
|
@ -97,7 +97,7 @@
|
||||
rx-fifo-depth = <8192>;
|
||||
tx-fifo-depth = <8192>;
|
||||
address-bits = <48>;
|
||||
max-frame-size = <1518>;
|
||||
max-frame-size = <1500>;
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
altr,has-supplementary-unicast;
|
||||
altr,enable-sup-addr = <1>;
|
||||
|
@ -106,7 +106,7 @@
|
||||
interrupt-names = "rx_irq", "tx_irq";
|
||||
rx-fifo-depth = <8192>;
|
||||
tx-fifo-depth = <8192>;
|
||||
max-frame-size = <1518>;
|
||||
max-frame-size = <1500>;
|
||||
local-mac-address = [ 00 00 00 00 00 00 ];
|
||||
phy-mode = "rgmii-id";
|
||||
phy-handle = <&phy0>;
|
||||
|
@ -442,13 +442,29 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr,
|
||||
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
/*
|
||||
* fdc: The data cache line is written back to memory, if and only if
|
||||
* it is dirty, and then invalidated from the data cache.
|
||||
*/
|
||||
flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size);
|
||||
}
|
||||
|
||||
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size);
|
||||
unsigned long addr = (unsigned long) phys_to_virt(paddr);
|
||||
|
||||
switch (dir) {
|
||||
case DMA_TO_DEVICE:
|
||||
case DMA_BIDIRECTIONAL:
|
||||
flush_kernel_dcache_range(addr, size);
|
||||
return;
|
||||
case DMA_FROM_DEVICE:
|
||||
purge_kernel_dcache_range_asm(addr, addr + size);
|
||||
return;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
||||
|
@ -253,8 +253,6 @@ CONFIG_ATM_LANE=m
|
||||
CONFIG_ATM_BR2684=m
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_VLAN_8021Q=m
|
||||
CONFIG_DECNET=m
|
||||
CONFIG_DECNET_ROUTER=y
|
||||
CONFIG_IPX=m
|
||||
CONFIG_ATALK=m
|
||||
CONFIG_DEV_APPLETALK=m
|
||||
|
@ -4,6 +4,11 @@ KASAN_SANITIZE := n
|
||||
|
||||
targets += trampoline.o purgatory.ro kexec-purgatory.c
|
||||
|
||||
# When profile-guided optimization is enabled, llvm emits two different
|
||||
# overlapping text sections, which is not supported by kexec. Remove profile
|
||||
# optimization flags.
|
||||
KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%,$(KBUILD_CFLAGS))
|
||||
|
||||
LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined
|
||||
|
||||
$(obj)/purgatory.ro: $(obj)/trampoline.o FORCE
|
||||
|
@ -255,9 +255,10 @@ int public_key_verify_signature(const struct public_key *pkey,
|
||||
struct crypto_wait cwait;
|
||||
struct crypto_akcipher *tfm;
|
||||
struct akcipher_request *req;
|
||||
struct scatterlist src_sg[2];
|
||||
struct scatterlist src_sg;
|
||||
char alg_name[CRYPTO_MAX_ALG_NAME];
|
||||
char *key, *ptr;
|
||||
char *buf, *ptr;
|
||||
size_t buf_len;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
@ -281,28 +282,31 @@ int public_key_verify_signature(const struct public_key *pkey,
|
||||
if (!req)
|
||||
goto error_free_tfm;
|
||||
|
||||
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
|
||||
GFP_KERNEL);
|
||||
if (!key)
|
||||
buf_len = max_t(size_t, pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
|
||||
sig->s_size + sig->digest_size);
|
||||
|
||||
buf = kmalloc(buf_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
goto error_free_req;
|
||||
|
||||
memcpy(key, pkey->key, pkey->keylen);
|
||||
ptr = key + pkey->keylen;
|
||||
memcpy(buf, pkey->key, pkey->keylen);
|
||||
ptr = buf + pkey->keylen;
|
||||
ptr = pkey_pack_u32(ptr, pkey->algo);
|
||||
ptr = pkey_pack_u32(ptr, pkey->paramlen);
|
||||
memcpy(ptr, pkey->params, pkey->paramlen);
|
||||
|
||||
if (pkey->key_is_private)
|
||||
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
|
||||
ret = crypto_akcipher_set_priv_key(tfm, buf, pkey->keylen);
|
||||
else
|
||||
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
|
||||
ret = crypto_akcipher_set_pub_key(tfm, buf, pkey->keylen);
|
||||
if (ret)
|
||||
goto error_free_key;
|
||||
goto error_free_buf;
|
||||
|
||||
sg_init_table(src_sg, 2);
|
||||
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
|
||||
sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
|
||||
akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
|
||||
memcpy(buf, sig->s, sig->s_size);
|
||||
memcpy(buf + sig->s_size, sig->digest, sig->digest_size);
|
||||
|
||||
sg_init_one(&src_sg, buf, sig->s_size + sig->digest_size);
|
||||
akcipher_request_set_crypt(req, &src_sg, NULL, sig->s_size,
|
||||
sig->digest_size);
|
||||
crypto_init_wait(&cwait);
|
||||
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
|
||||
@ -310,8 +314,8 @@ int public_key_verify_signature(const struct public_key *pkey,
|
||||
crypto_req_done, &cwait);
|
||||
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
|
||||
|
||||
error_free_key:
|
||||
kfree(key);
|
||||
error_free_buf:
|
||||
kfree(buf);
|
||||
error_free_req:
|
||||
akcipher_request_free(req);
|
||||
error_free_tfm:
|
||||
|
@ -779,7 +779,8 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
|
||||
ring_req->u.rw.handle = info->handle;
|
||||
ring_req->operation = rq_data_dir(req) ?
|
||||
BLKIF_OP_WRITE : BLKIF_OP_READ;
|
||||
if (req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA) {
|
||||
if (req_op(req) == REQ_OP_FLUSH ||
|
||||
(req_op(req) == REQ_OP_WRITE && (req->cmd_flags & REQ_FUA))) {
|
||||
/*
|
||||
* Ideally we can do an unordered flush-to-disk.
|
||||
* In case the backend onlysupports barriers, use that.
|
||||
|
@ -90,6 +90,9 @@ parisc_agp_tlbflush(struct agp_memory *mem)
|
||||
{
|
||||
struct _parisc_agp_info *info = &parisc_agp_info;
|
||||
|
||||
/* force fdc ops to be visible to IOMMU */
|
||||
asm_io_sync();
|
||||
|
||||
writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM);
|
||||
readq(info->ioc_regs+IOC_PCOM); /* flush */
|
||||
}
|
||||
@ -158,6 +161,7 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
|
||||
info->gatt[j] =
|
||||
parisc_agp_mask_memory(agp_bridge,
|
||||
paddr, type);
|
||||
asm_io_fdc(&info->gatt[j]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +195,16 @@ static unsigned long
|
||||
parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
|
||||
int type)
|
||||
{
|
||||
return SBA_PDIR_VALID_BIT | addr;
|
||||
unsigned ci; /* coherent index */
|
||||
dma_addr_t pa;
|
||||
|
||||
pa = addr & IOVP_MASK;
|
||||
asm("lci 0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pa)));
|
||||
|
||||
pa |= (ci >> PAGE_SHIFT) & 0xff;/* move CI (8 bits) into lowest byte */
|
||||
pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
|
||||
|
||||
return cpu_to_le64(pa);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3527,8 +3527,10 @@ static int gfx_v10_0_kiq_resume(struct amdgpu_device *adev)
|
||||
return r;
|
||||
|
||||
r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr);
|
||||
if (unlikely(r != 0))
|
||||
if (unlikely(r != 0)) {
|
||||
amdgpu_bo_unreserve(ring->mqd_obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
gfx_v10_0_kiq_init_queue(ring);
|
||||
amdgpu_bo_kunmap(ring->mqd_obj);
|
||||
|
@ -3748,8 +3748,10 @@ static int gfx_v9_0_kiq_resume(struct amdgpu_device *adev)
|
||||
return r;
|
||||
|
||||
r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr);
|
||||
if (unlikely(r != 0))
|
||||
if (unlikely(r != 0)) {
|
||||
amdgpu_bo_unreserve(ring->mqd_obj);
|
||||
return r;
|
||||
}
|
||||
|
||||
gfx_v9_0_kiq_init_queue(ring);
|
||||
amdgpu_bo_kunmap(ring->mqd_obj);
|
||||
|
@ -538,6 +538,19 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_connector_set_edid(struct nouveau_connector *nv_connector,
|
||||
struct edid *edid)
|
||||
{
|
||||
if (nv_connector->edid != edid) {
|
||||
struct edid *old_edid = nv_connector->edid;
|
||||
|
||||
drm_connector_update_edid_property(&nv_connector->base, edid);
|
||||
kfree(old_edid);
|
||||
nv_connector->edid = edid;
|
||||
}
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
@ -551,13 +564,6 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||
int ret;
|
||||
enum drm_connector_status conn_status = connector_status_disconnected;
|
||||
|
||||
/* Cleanup the previous EDID block. */
|
||||
if (nv_connector->edid) {
|
||||
drm_connector_update_edid_property(connector, NULL);
|
||||
kfree(nv_connector->edid);
|
||||
nv_connector->edid = NULL;
|
||||
}
|
||||
|
||||
/* Outputs are only polled while runtime active, so resuming the
|
||||
* device here is unnecessary (and would deadlock upon runtime suspend
|
||||
* because it waits for polling to finish). We do however, want to
|
||||
@ -570,22 +576,23 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||
ret = pm_runtime_get_sync(dev->dev);
|
||||
if (ret < 0 && ret != -EACCES) {
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
nouveau_connector_set_edid(nv_connector, NULL);
|
||||
return conn_status;
|
||||
}
|
||||
}
|
||||
|
||||
nv_encoder = nouveau_connector_ddc_detect(connector);
|
||||
if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
|
||||
struct edid *new_edid;
|
||||
|
||||
if ((vga_switcheroo_handler_flags() &
|
||||
VGA_SWITCHEROO_CAN_SWITCH_DDC) &&
|
||||
nv_connector->type == DCB_CONNECTOR_LVDS)
|
||||
nv_connector->edid = drm_get_edid_switcheroo(connector,
|
||||
i2c);
|
||||
new_edid = drm_get_edid_switcheroo(connector, i2c);
|
||||
else
|
||||
nv_connector->edid = drm_get_edid(connector, i2c);
|
||||
new_edid = drm_get_edid(connector, i2c);
|
||||
|
||||
drm_connector_update_edid_property(connector,
|
||||
nv_connector->edid);
|
||||
nouveau_connector_set_edid(nv_connector, new_edid);
|
||||
if (!nv_connector->edid) {
|
||||
NV_ERROR(drm, "DDC responded, but no EDID for %s\n",
|
||||
connector->name);
|
||||
@ -619,6 +626,8 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||
conn_status = connector_status_connected;
|
||||
drm_dp_cec_set_edid(&nv_connector->aux, nv_connector->edid);
|
||||
goto out;
|
||||
} else {
|
||||
nouveau_connector_set_edid(nv_connector, NULL);
|
||||
}
|
||||
|
||||
nv_encoder = nouveau_connector_of_detect(connector);
|
||||
@ -661,24 +670,20 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||
struct nouveau_encoder *nv_encoder = NULL;
|
||||
struct edid *edid = NULL;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
/* Cleanup the previous EDID block. */
|
||||
if (nv_connector->edid) {
|
||||
drm_connector_update_edid_property(connector, NULL);
|
||||
kfree(nv_connector->edid);
|
||||
nv_connector->edid = NULL;
|
||||
}
|
||||
|
||||
nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS);
|
||||
if (!nv_encoder)
|
||||
return connector_status_disconnected;
|
||||
goto out;
|
||||
|
||||
/* Try retrieving EDID via DDC */
|
||||
if (!drm->vbios.fp_no_ddc) {
|
||||
status = nouveau_connector_detect(connector, force);
|
||||
if (status == connector_status_connected)
|
||||
if (status == connector_status_connected) {
|
||||
edid = nv_connector->edid;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* On some laptops (Sony, i'm looking at you) there appears to
|
||||
@ -691,7 +696,8 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
|
||||
* valid - it's not (rh#613284)
|
||||
*/
|
||||
if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
|
||||
if ((nv_connector->edid = nouveau_acpi_edid(dev, connector))) {
|
||||
edid = nouveau_acpi_edid(dev, connector);
|
||||
if (edid) {
|
||||
status = connector_status_connected;
|
||||
goto out;
|
||||
}
|
||||
@ -711,12 +717,10 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
|
||||
* stored for the panel stored in them.
|
||||
*/
|
||||
if (!drm->vbios.fp_no_ddc) {
|
||||
struct edid *edid =
|
||||
(struct edid *)nouveau_bios_embedded_edid(dev);
|
||||
edid = (struct edid *)nouveau_bios_embedded_edid(dev);
|
||||
if (edid) {
|
||||
nv_connector->edid =
|
||||
kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
|
||||
if (nv_connector->edid)
|
||||
edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
|
||||
if (edid)
|
||||
status = connector_status_connected;
|
||||
}
|
||||
}
|
||||
@ -729,8 +733,9 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
|
||||
status = connector_status_unknown;
|
||||
#endif
|
||||
|
||||
drm_connector_update_edid_property(connector, nv_connector->edid);
|
||||
nouveau_connector_set_encoder(connector, nv_encoder);
|
||||
nouveau_connector_set_edid(nv_connector, edid);
|
||||
if (nv_encoder)
|
||||
nouveau_connector_set_encoder(connector, nv_encoder);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -950,7 +955,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
|
||||
/* Determine display colour depth for everything except LVDS now,
|
||||
* DP requires this before mode_valid() is called.
|
||||
*/
|
||||
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
|
||||
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode)
|
||||
nouveau_connector_detect_depth(connector);
|
||||
|
||||
/* Find the native mode if this is a digital panel, if we didn't
|
||||
@ -971,7 +976,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
|
||||
* "native" mode as some VBIOS tables require us to use the
|
||||
* pixel clock as part of the lookup...
|
||||
*/
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode)
|
||||
nouveau_connector_detect_depth(connector);
|
||||
|
||||
if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
|
||||
|
@ -123,10 +123,16 @@ nouveau_name(struct drm_device *dev)
|
||||
static inline bool
|
||||
nouveau_cli_work_ready(struct dma_fence *fence)
|
||||
{
|
||||
if (!dma_fence_is_signaled(fence))
|
||||
return false;
|
||||
dma_fence_put(fence);
|
||||
return true;
|
||||
bool ret = true;
|
||||
|
||||
spin_lock_irq(fence->lock);
|
||||
if (!dma_fence_is_signaled_locked(fence))
|
||||
ret = false;
|
||||
spin_unlock_irq(fence->lock);
|
||||
|
||||
if (ret == true)
|
||||
dma_fence_put(fence);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1863,8 +1863,13 @@ static int modify_qp(struct uverbs_attr_bundle *attrs,
|
||||
attr->path_mtu = cmd->base.path_mtu;
|
||||
if (cmd->base.attr_mask & IB_QP_PATH_MIG_STATE)
|
||||
attr->path_mig_state = cmd->base.path_mig_state;
|
||||
if (cmd->base.attr_mask & IB_QP_QKEY)
|
||||
if (cmd->base.attr_mask & IB_QP_QKEY) {
|
||||
if (cmd->base.qkey & IB_QP_SET_QKEY && !capable(CAP_NET_RAW)) {
|
||||
ret = -EPERM;
|
||||
goto release_qp;
|
||||
}
|
||||
attr->qkey = cmd->base.qkey;
|
||||
}
|
||||
if (cmd->base.attr_mask & IB_QP_RQ_PSN)
|
||||
attr->rq_psn = cmd->base.rq_psn;
|
||||
if (cmd->base.attr_mask & IB_QP_SQ_PSN)
|
||||
|
@ -230,8 +230,12 @@ static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
|
||||
spin_lock_irq(&ev_queue->lock);
|
||||
|
||||
while (list_empty(&ev_queue->event_list)) {
|
||||
spin_unlock_irq(&ev_queue->lock);
|
||||
if (ev_queue->is_closed) {
|
||||
spin_unlock_irq(&ev_queue->lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&ev_queue->lock);
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
@ -241,12 +245,6 @@ static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
|
||||
return -ERESTARTSYS;
|
||||
|
||||
spin_lock_irq(&ev_queue->lock);
|
||||
|
||||
/* If device was disassociated and no event exists set an error */
|
||||
if (list_empty(&ev_queue->event_list) && ev_queue->is_closed) {
|
||||
spin_unlock_irq(&ev_queue->lock);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
event = list_entry(ev_queue->event_list.next, struct ib_uverbs_event, list);
|
||||
|
@ -219,6 +219,9 @@ static void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp,
|
||||
spin_lock_init(&qp->rq.producer_lock);
|
||||
spin_lock_init(&qp->rq.consumer_lock);
|
||||
|
||||
skb_queue_head_init(&qp->req_pkts);
|
||||
skb_queue_head_init(&qp->resp_pkts);
|
||||
|
||||
atomic_set(&qp->ssn, 0);
|
||||
atomic_set(&qp->skb_out, 0);
|
||||
}
|
||||
@ -276,12 +279,8 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
|
||||
qp->req.opcode = -1;
|
||||
qp->comp.opcode = -1;
|
||||
|
||||
skb_queue_head_init(&qp->req_pkts);
|
||||
|
||||
rxe_init_task(rxe, &qp->req.task, qp,
|
||||
rxe_requester, "req");
|
||||
rxe_init_task(rxe, &qp->comp.task, qp,
|
||||
rxe_completer, "comp");
|
||||
rxe_init_task(&qp->req.task, qp, rxe_requester);
|
||||
rxe_init_task(&qp->comp.task, qp, rxe_completer);
|
||||
|
||||
qp->qp_timeout_jiffies = 0; /* Can't be set for UD/UC in modify_qp */
|
||||
if (init->qp_type == IB_QPT_RC) {
|
||||
@ -325,10 +324,7 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
|
||||
}
|
||||
}
|
||||
|
||||
skb_queue_head_init(&qp->resp_pkts);
|
||||
|
||||
rxe_init_task(rxe, &qp->resp.task, qp,
|
||||
rxe_responder, "resp");
|
||||
rxe_init_task(&qp->resp.task, qp, rxe_responder);
|
||||
|
||||
qp->resp.opcode = OPCODE_NONE;
|
||||
qp->resp.msn = 0;
|
||||
|
@ -114,13 +114,10 @@ void rxe_do_task(unsigned long data)
|
||||
task->ret = ret;
|
||||
}
|
||||
|
||||
int rxe_init_task(void *obj, struct rxe_task *task,
|
||||
void *arg, int (*func)(void *), char *name)
|
||||
int rxe_init_task(struct rxe_task *task, void *arg, int (*func)(void *))
|
||||
{
|
||||
task->obj = obj;
|
||||
task->arg = arg;
|
||||
task->func = func;
|
||||
snprintf(task->name, sizeof(task->name), "%s", name);
|
||||
task->destroyed = false;
|
||||
|
||||
tasklet_init(&task->tasklet, rxe_do_task, (unsigned long)task);
|
||||
|
@ -46,14 +46,12 @@ enum {
|
||||
* called again.
|
||||
*/
|
||||
struct rxe_task {
|
||||
void *obj;
|
||||
struct tasklet_struct tasklet;
|
||||
int state;
|
||||
spinlock_t state_lock; /* spinlock for task state */
|
||||
void *arg;
|
||||
int (*func)(void *arg);
|
||||
int ret;
|
||||
char name[16];
|
||||
bool destroyed;
|
||||
};
|
||||
|
||||
@ -62,8 +60,7 @@ struct rxe_task {
|
||||
* arg => parameter to pass to fcn
|
||||
* fcn => function to call until it returns != 0
|
||||
*/
|
||||
int rxe_init_task(void *obj, struct rxe_task *task,
|
||||
void *arg, int (*func)(void *), char *name);
|
||||
int rxe_init_task(struct rxe_task *task, void *arg, int (*func)(void *));
|
||||
|
||||
/* cleanup task */
|
||||
void rxe_cleanup_task(struct rxe_task *task);
|
||||
|
@ -733,9 +733,13 @@ static int
|
||||
isert_connect_error(struct rdma_cm_id *cma_id)
|
||||
{
|
||||
struct isert_conn *isert_conn = cma_id->qp->qp_context;
|
||||
struct isert_np *isert_np = cma_id->context;
|
||||
|
||||
ib_drain_qp(isert_conn->qp);
|
||||
|
||||
mutex_lock(&isert_np->mutex);
|
||||
list_del_init(&isert_conn->node);
|
||||
mutex_unlock(&isert_np->mutex);
|
||||
isert_conn->cm_id = NULL;
|
||||
isert_put_conn(isert_conn);
|
||||
|
||||
@ -2507,6 +2511,7 @@ isert_free_np(struct iscsi_np *np)
|
||||
{
|
||||
struct isert_np *isert_np = np->np_context;
|
||||
struct isert_conn *isert_conn, *n;
|
||||
LIST_HEAD(drop_conn_list);
|
||||
|
||||
if (isert_np->cm_id)
|
||||
rdma_destroy_id(isert_np->cm_id);
|
||||
@ -2526,7 +2531,7 @@ isert_free_np(struct iscsi_np *np)
|
||||
node) {
|
||||
isert_info("cleaning isert_conn %p state (%d)\n",
|
||||
isert_conn, isert_conn->state);
|
||||
isert_connect_release(isert_conn);
|
||||
list_move_tail(&isert_conn->node, &drop_conn_list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2537,11 +2542,16 @@ isert_free_np(struct iscsi_np *np)
|
||||
node) {
|
||||
isert_info("cleaning isert_conn %p state (%d)\n",
|
||||
isert_conn, isert_conn->state);
|
||||
isert_connect_release(isert_conn);
|
||||
list_move_tail(&isert_conn->node, &drop_conn_list);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&isert_np->mutex);
|
||||
|
||||
list_for_each_entry_safe(isert_conn, n, &drop_conn_list, node) {
|
||||
list_del_init(&isert_conn->node);
|
||||
isert_connect_release(isert_conn);
|
||||
}
|
||||
|
||||
np->np_context = NULL;
|
||||
kfree(isert_np);
|
||||
}
|
||||
@ -2636,8 +2646,6 @@ static void isert_wait_conn(struct iscsi_conn *conn)
|
||||
isert_put_unsol_pending_cmds(conn);
|
||||
isert_wait4cmds(conn);
|
||||
isert_wait4logout(isert_conn);
|
||||
|
||||
queue_work(isert_release_wq, &isert_conn->release_work);
|
||||
}
|
||||
|
||||
static void isert_free_conn(struct iscsi_conn *conn)
|
||||
|
@ -70,7 +70,7 @@ static const struct meson_gpio_irq_params sm1_params = {
|
||||
.support_edge_both = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_irq_gpio_matches[] = {
|
||||
static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
|
||||
{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
|
||||
{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
|
||||
{ .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
|
||||
|
@ -255,6 +255,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
|
||||
goto out_put;
|
||||
}
|
||||
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
|
||||
req_to_mmc_queue_req(req)->drv_op_result = -EIO;
|
||||
blk_execute_rq(mq->queue, NULL, req, 0);
|
||||
ret = req_to_mmc_queue_req(req)->drv_op_result;
|
||||
blk_put_request(req);
|
||||
@ -694,6 +695,7 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
|
||||
idatas[0] = idata;
|
||||
req_to_mmc_queue_req(req)->drv_op =
|
||||
rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
|
||||
req_to_mmc_queue_req(req)->drv_op_result = -EIO;
|
||||
req_to_mmc_queue_req(req)->drv_op_data = idatas;
|
||||
req_to_mmc_queue_req(req)->ioc_count = 1;
|
||||
blk_execute_rq(mq->queue, NULL, req, 0);
|
||||
@ -763,6 +765,7 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
|
||||
}
|
||||
req_to_mmc_queue_req(req)->drv_op =
|
||||
rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
|
||||
req_to_mmc_queue_req(req)->drv_op_result = -EIO;
|
||||
req_to_mmc_queue_req(req)->drv_op_data = idata;
|
||||
req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
|
||||
blk_execute_rq(mq->queue, NULL, req, 0);
|
||||
@ -2798,6 +2801,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS;
|
||||
req_to_mmc_queue_req(req)->drv_op_result = -EIO;
|
||||
blk_execute_rq(mq->queue, NULL, req, 0);
|
||||
ret = req_to_mmc_queue_req(req)->drv_op_result;
|
||||
if (ret >= 0) {
|
||||
@ -2836,6 +2840,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
|
||||
goto out_free;
|
||||
}
|
||||
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD;
|
||||
req_to_mmc_queue_req(req)->drv_op_result = -EIO;
|
||||
req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
|
||||
blk_execute_rq(mq->queue, NULL, req, 0);
|
||||
err = req_to_mmc_queue_req(req)->drv_op_result;
|
||||
|
@ -385,7 +385,7 @@ void iavf_set_ethtool_ops(struct net_device *netdev);
|
||||
void iavf_update_stats(struct iavf_adapter *adapter);
|
||||
void iavf_reset_interrupt_capability(struct iavf_adapter *adapter);
|
||||
int iavf_init_interrupt_scheme(struct iavf_adapter *adapter);
|
||||
void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask);
|
||||
void iavf_irq_enable_queues(struct iavf_adapter *adapter);
|
||||
void iavf_free_all_tx_resources(struct iavf_adapter *adapter);
|
||||
void iavf_free_all_rx_resources(struct iavf_adapter *adapter);
|
||||
|
||||
|
@ -244,21 +244,18 @@ static void iavf_irq_disable(struct iavf_adapter *adapter)
|
||||
}
|
||||
|
||||
/**
|
||||
* iavf_irq_enable_queues - Enable interrupt for specified queues
|
||||
* iavf_irq_enable_queues - Enable interrupt for all queues
|
||||
* @adapter: board private structure
|
||||
* @mask: bitmap of queues to enable
|
||||
**/
|
||||
void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask)
|
||||
void iavf_irq_enable_queues(struct iavf_adapter *adapter)
|
||||
{
|
||||
struct iavf_hw *hw = &adapter->hw;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < adapter->num_msix_vectors; i++) {
|
||||
if (mask & BIT(i - 1)) {
|
||||
wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1),
|
||||
IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
|
||||
IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
|
||||
}
|
||||
wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1),
|
||||
IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
|
||||
IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,7 +269,7 @@ void iavf_irq_enable(struct iavf_adapter *adapter, bool flush)
|
||||
struct iavf_hw *hw = &adapter->hw;
|
||||
|
||||
iavf_misc_irq_enable(adapter);
|
||||
iavf_irq_enable_queues(adapter, ~0);
|
||||
iavf_irq_enable_queues(adapter);
|
||||
|
||||
if (flush)
|
||||
iavf_flush(hw);
|
||||
|
@ -40,7 +40,7 @@
|
||||
#define IAVF_VFINT_DYN_CTL01_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTL01_INTENA_SHIFT)
|
||||
#define IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3
|
||||
#define IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT)
|
||||
#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */
|
||||
#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...63 */ /* Reset: VFR */
|
||||
#define IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT 0
|
||||
#define IAVF_VFINT_DYN_CTLN1_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT)
|
||||
#define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2
|
||||
|
@ -814,6 +814,8 @@ static int igb_set_eeprom(struct net_device *netdev,
|
||||
*/
|
||||
ret_val = hw->nvm.ops.read(hw, last_word, 1,
|
||||
&eeprom_buff[last_word - first_word]);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Device's eeprom is always little-endian, word addressable */
|
||||
@ -833,6 +835,7 @@ static int igb_set_eeprom(struct net_device *netdev,
|
||||
hw->nvm.ops.update(hw);
|
||||
|
||||
igb_set_fw_version(adapter);
|
||||
out:
|
||||
kfree(eeprom_buff);
|
||||
return ret_val;
|
||||
}
|
||||
|
@ -102,6 +102,10 @@ static unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
|
||||
|
||||
skb->dev = addr->master->dev;
|
||||
skb->skb_iif = skb->dev->ifindex;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (addr->atype == IPVL_IPV6)
|
||||
IP6CB(skb)->iif = skb->dev->ifindex;
|
||||
#endif
|
||||
len = skb->len + ETH_HLEN;
|
||||
ipvlan_count_rx(addr->master, len, true, false);
|
||||
out:
|
||||
|
@ -1178,7 +1178,9 @@ static const struct usb_device_id products[] = {
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9080, 8)},
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9083, 3)},
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9084, 4)},
|
||||
{QMI_QUIRK_SET_DTR(0x05c6, 0x9091, 2)}, /* Compal RXM-G1 */
|
||||
{QMI_FIXED_INTF(0x05c6, 0x90b2, 3)}, /* ublox R410M */
|
||||
{QMI_QUIRK_SET_DTR(0x05c6, 0x90db, 2)}, /* Compal RXM-G1 */
|
||||
{QMI_FIXED_INTF(0x05c6, 0x920d, 0)},
|
||||
{QMI_FIXED_INTF(0x05c6, 0x920d, 5)},
|
||||
{QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */
|
||||
|
@ -341,6 +341,9 @@ static int lapbeth_new_device(struct net_device *dev)
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (dev->type != ARPHRD_ETHER)
|
||||
return -EINVAL;
|
||||
|
||||
ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", NET_NAME_UNKNOWN,
|
||||
lapbeth_setup);
|
||||
if (!ndev)
|
||||
|
@ -555,6 +555,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
|
||||
{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
|
||||
{ KE_IGNORE, 0x6E, }, /* Low Battery notification */
|
||||
{ KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */
|
||||
{ KE_IGNORE, 0x7B, }, /* Charger connect/disconnect notification */
|
||||
{ KE_KEY, 0x7c, { KEY_MICMUTE } },
|
||||
{ KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
|
||||
{ KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
|
||||
@ -580,6 +581,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
|
||||
{ KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
|
||||
{ KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
|
||||
{ KE_KEY, 0xB5, { KEY_CALC } },
|
||||
{ KE_IGNORE, 0xC0, }, /* External display connect/disconnect notification */
|
||||
{ KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
|
||||
{ KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
|
||||
{ KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */
|
||||
|
@ -919,10 +919,8 @@ static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data)
|
||||
*/
|
||||
static void ab8500_btemp_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct ab8500_btemp *di = power_supply_get_drvdata(psy);
|
||||
|
||||
class_for_each_device(power_supply_class, NULL,
|
||||
di->btemp_psy, ab8500_btemp_get_ext_psy_data);
|
||||
class_for_each_device(power_supply_class, NULL, psy,
|
||||
ab8500_btemp_get_ext_psy_data);
|
||||
}
|
||||
|
||||
/* ab8500 btemp driver interrupts and their respective isr */
|
||||
|
@ -2380,10 +2380,8 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di)
|
||||
*/
|
||||
static void ab8500_fg_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct ab8500_fg *di = power_supply_get_drvdata(psy);
|
||||
|
||||
class_for_each_device(power_supply_class, NULL,
|
||||
di->fg_psy, ab8500_fg_get_ext_psy_data);
|
||||
class_for_each_device(power_supply_class, NULL, psy,
|
||||
ab8500_fg_get_ext_psy_data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -886,10 +886,8 @@ static int poll_interval_param_set(const char *val, const struct kernel_param *k
|
||||
return ret;
|
||||
|
||||
mutex_lock(&bq27xxx_list_lock);
|
||||
list_for_each_entry(di, &bq27xxx_battery_devices, list) {
|
||||
cancel_delayed_work_sync(&di->work);
|
||||
schedule_delayed_work(&di->work, 0);
|
||||
}
|
||||
list_for_each_entry(di, &bq27xxx_battery_devices, list)
|
||||
mod_delayed_work(system_wq, &di->work, 0);
|
||||
mutex_unlock(&bq27xxx_list_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -347,6 +347,10 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data)
|
||||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
unsigned int *count = data;
|
||||
|
||||
if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_SCOPE, &ret))
|
||||
if (ret.intval == POWER_SUPPLY_SCOPE_DEVICE)
|
||||
return 0;
|
||||
|
||||
(*count)++;
|
||||
if (psy->desc->type != POWER_SUPPLY_TYPE_BATTERY)
|
||||
if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE,
|
||||
@ -365,8 +369,8 @@ int power_supply_is_system_supplied(void)
|
||||
__power_supply_is_system_supplied);
|
||||
|
||||
/*
|
||||
* If no power class device was found at all, most probably we are
|
||||
* running on a desktop system, so assume we are on mains power.
|
||||
* If no system scope power class device was found at all, most probably we
|
||||
* are running on a desktop system, so assume we are on mains power.
|
||||
*/
|
||||
if (count == 0)
|
||||
return 1;
|
||||
|
@ -279,7 +279,8 @@ static ssize_t power_supply_show_property(struct device *dev,
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret == -ENODATA)
|
||||
dev_dbg(dev, "driver has no data for `%s' property\n",
|
||||
dev_dbg_ratelimited(dev,
|
||||
"driver has no data for `%s' property\n",
|
||||
attr->attr.name);
|
||||
else if (ret != -ENODEV && ret != -EAGAIN)
|
||||
dev_err_ratelimited(dev,
|
||||
|
@ -665,13 +665,6 @@ static int sc27xx_fgu_set_property(struct power_supply *psy,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sc27xx_fgu_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy);
|
||||
|
||||
power_supply_changed(data->battery);
|
||||
}
|
||||
|
||||
static int sc27xx_fgu_property_is_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
@ -703,7 +696,7 @@ static const struct power_supply_desc sc27xx_fgu_desc = {
|
||||
.num_properties = ARRAY_SIZE(sc27xx_fgu_props),
|
||||
.get_property = sc27xx_fgu_get_property,
|
||||
.set_property = sc27xx_fgu_set_property,
|
||||
.external_power_changed = sc27xx_fgu_external_power_changed,
|
||||
.external_power_changed = power_supply_changed,
|
||||
.property_is_writeable = sc27xx_fgu_property_is_writeable,
|
||||
};
|
||||
|
||||
|
@ -4910,7 +4910,7 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
|
||||
}
|
||||
|
||||
rdev->debugfs = debugfs_create_dir(rname, debugfs_root);
|
||||
if (!rdev->debugfs) {
|
||||
if (IS_ERR(rdev->debugfs)) {
|
||||
rdev_warn(rdev, "Failed to create debugfs directory\n");
|
||||
return;
|
||||
}
|
||||
@ -5800,7 +5800,7 @@ static int __init regulator_init(void)
|
||||
ret = class_register(®ulator_class);
|
||||
|
||||
debugfs_root = debugfs_create_dir("regulator", NULL);
|
||||
if (!debugfs_root)
|
||||
if (IS_ERR(debugfs_root))
|
||||
pr_warn("regulator: Failed to create debugfs directory\n");
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -457,10 +457,9 @@ static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
|
||||
/*
|
||||
* Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
|
||||
*/
|
||||
static int dasd_ioctl_information(struct dasd_block *block,
|
||||
unsigned int cmd, void __user *argp)
|
||||
static int __dasd_ioctl_information(struct dasd_block *block,
|
||||
struct dasd_information2_t *dasd_info)
|
||||
{
|
||||
struct dasd_information2_t *dasd_info;
|
||||
struct subchannel_id sch_id;
|
||||
struct ccw_dev_id dev_id;
|
||||
struct dasd_device *base;
|
||||
@ -473,15 +472,9 @@ static int dasd_ioctl_information(struct dasd_block *block,
|
||||
if (!base->discipline || !base->discipline->fill_info)
|
||||
return -EINVAL;
|
||||
|
||||
dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
|
||||
if (dasd_info == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = base->discipline->fill_info(base, dasd_info);
|
||||
if (rc) {
|
||||
kfree(dasd_info);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
cdev = base->cdev;
|
||||
ccw_device_get_id(cdev, &dev_id);
|
||||
@ -516,19 +509,28 @@ static int dasd_ioctl_information(struct dasd_block *block,
|
||||
|
||||
memcpy(dasd_info->type, base->discipline->name, 4);
|
||||
|
||||
spin_lock_irqsave(&block->queue_lock, flags);
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
list_for_each(l, &base->ccw_queue)
|
||||
dasd_info->chanq_len++;
|
||||
spin_unlock_irqrestore(&block->queue_lock, flags);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
if (copy_to_user(argp, dasd_info,
|
||||
((cmd == (unsigned int) BIODASDINFO2) ?
|
||||
sizeof(struct dasd_information2_t) :
|
||||
sizeof(struct dasd_information_t))))
|
||||
rc = -EFAULT;
|
||||
static int dasd_ioctl_information(struct dasd_block *block, void __user *argp,
|
||||
size_t copy_size)
|
||||
{
|
||||
struct dasd_information2_t *dasd_info;
|
||||
int error;
|
||||
|
||||
dasd_info = kzalloc(sizeof(*dasd_info), GFP_KERNEL);
|
||||
if (!dasd_info)
|
||||
return -ENOMEM;
|
||||
|
||||
error = __dasd_ioctl_information(block, dasd_info);
|
||||
if (!error && copy_to_user(argp, dasd_info, copy_size))
|
||||
error = -EFAULT;
|
||||
kfree(dasd_info);
|
||||
return rc;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -622,10 +624,12 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
rc = dasd_ioctl_check_format(bdev, argp);
|
||||
break;
|
||||
case BIODASDINFO:
|
||||
rc = dasd_ioctl_information(block, cmd, argp);
|
||||
rc = dasd_ioctl_information(block, argp,
|
||||
sizeof(struct dasd_information_t));
|
||||
break;
|
||||
case BIODASDINFO2:
|
||||
rc = dasd_ioctl_information(block, cmd, argp);
|
||||
rc = dasd_ioctl_information(block, argp,
|
||||
sizeof(struct dasd_information2_t));
|
||||
break;
|
||||
case BIODASDPRRD:
|
||||
rc = dasd_ioctl_read_profile(block, argp);
|
||||
|
@ -121,7 +121,6 @@
|
||||
|
||||
struct chip_data {
|
||||
u32 ctar_val;
|
||||
u16 void_write_data;
|
||||
};
|
||||
|
||||
enum dspi_trans_mode {
|
||||
@ -190,7 +189,6 @@ struct fsl_dspi {
|
||||
const void *tx;
|
||||
void *rx;
|
||||
void *rx_end;
|
||||
u16 void_write_data;
|
||||
u16 tx_cmd;
|
||||
u8 bits_per_word;
|
||||
u8 bytes_per_word;
|
||||
@ -748,8 +746,6 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
||||
dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
|
||||
}
|
||||
|
||||
dspi->void_write_data = dspi->cur_chip->void_write_data;
|
||||
|
||||
dspi->tx = transfer->tx_buf;
|
||||
dspi->rx = transfer->rx_buf;
|
||||
dspi->rx_end = dspi->rx + transfer->len;
|
||||
@ -820,7 +816,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
||||
static int dspi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct fsl_dspi *dspi = spi_controller_get_devdata(spi->controller);
|
||||
u32 period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->max_speed_hz);
|
||||
unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
|
||||
u32 quarter_period_ns = DIV_ROUND_UP(period_ns, 4);
|
||||
u32 cs_sck_delay = 0, sck_cs_delay = 0;
|
||||
struct fsl_dspi_platform_data *pdata;
|
||||
unsigned char pasc = 0, asc = 0;
|
||||
@ -848,7 +846,18 @@ static int dspi_setup(struct spi_device *spi)
|
||||
sck_cs_delay = pdata->sck_cs_delay;
|
||||
}
|
||||
|
||||
chip->void_write_data = 0;
|
||||
/* Since tCSC and tASC apply to continuous transfers too, avoid SCK
|
||||
* glitches of half a cycle by never allowing tCSC + tASC to go below
|
||||
* half a SCK period.
|
||||
*/
|
||||
if (cs_sck_delay < quarter_period_ns)
|
||||
cs_sck_delay = quarter_period_ns;
|
||||
if (sck_cs_delay < quarter_period_ns)
|
||||
sck_cs_delay = quarter_period_ns;
|
||||
|
||||
dev_dbg(&spi->dev,
|
||||
"DSPI controller timing params: CS-to-SCK delay %u ns, SCK-to-CS delay %u ns\n",
|
||||
cs_sck_delay, sck_cs_delay);
|
||||
|
||||
clkrate = clk_get_rate(dspi->clk);
|
||||
hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
|
||||
|
@ -274,6 +274,7 @@ lqasc_err_int(int irq, void *_port)
|
||||
struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
|
||||
|
||||
spin_lock_irqsave(<q_port->lock, flags);
|
||||
__raw_writel(ASC_IRNCR_EIR, port->membase + LTQ_ASC_IRNCR);
|
||||
/* clear any pending interrupts */
|
||||
asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
|
||||
ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
|
||||
|
@ -177,6 +177,7 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
|
||||
list_del(&req->list);
|
||||
req->remaining = 0;
|
||||
req->needs_extra_trb = false;
|
||||
req->num_trbs = 0;
|
||||
|
||||
if (req->request.status == -EINPROGRESS)
|
||||
req->request.status = status;
|
||||
|
@ -248,6 +248,8 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define QUECTEL_VENDOR_ID 0x2c7c
|
||||
/* These Quectel products use Quectel's vendor ID */
|
||||
#define QUECTEL_PRODUCT_EC21 0x0121
|
||||
#define QUECTEL_PRODUCT_EM061K_LTA 0x0123
|
||||
#define QUECTEL_PRODUCT_EM061K_LMS 0x0124
|
||||
#define QUECTEL_PRODUCT_EC25 0x0125
|
||||
#define QUECTEL_PRODUCT_EG91 0x0191
|
||||
#define QUECTEL_PRODUCT_EG95 0x0195
|
||||
@ -266,6 +268,8 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define QUECTEL_PRODUCT_RM520N 0x0801
|
||||
#define QUECTEL_PRODUCT_EC200U 0x0901
|
||||
#define QUECTEL_PRODUCT_EC200S_CN 0x6002
|
||||
#define QUECTEL_PRODUCT_EM061K_LWW 0x6008
|
||||
#define QUECTEL_PRODUCT_EM061K_LCN 0x6009
|
||||
#define QUECTEL_PRODUCT_EC200T 0x6026
|
||||
#define QUECTEL_PRODUCT_RM500K 0x7001
|
||||
|
||||
@ -1189,6 +1193,18 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff),
|
||||
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) },
|
||||
|
@ -92,8 +92,8 @@ void afs_vlserver_probe_result(struct afs_call *call)
|
||||
}
|
||||
}
|
||||
|
||||
if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
|
||||
rtt_us < server->probe.rtt) {
|
||||
rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us);
|
||||
if (rtt_us < server->probe.rtt) {
|
||||
server->probe.rtt = rtt_us;
|
||||
alist->preferred = index;
|
||||
have_result = true;
|
||||
|
@ -499,7 +499,9 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
|
||||
sums = kvzalloc(btrfs_ordered_sum_size(fs_info,
|
||||
bytes_left), GFP_KERNEL);
|
||||
memalloc_nofs_restore(nofs_flag);
|
||||
BUG_ON(!sums); /* -ENOMEM */
|
||||
if (!sums)
|
||||
return BLK_STS_RESOURCE;
|
||||
|
||||
sums->len = bytes_left;
|
||||
ordered = btrfs_lookup_ordered_extent(inode,
|
||||
offset);
|
||||
|
@ -285,6 +285,14 @@ void nilfs_btnode_abort_change_key(struct address_space *btnc,
|
||||
if (nbh == NULL) { /* blocksize == pagesize */
|
||||
xa_erase_irq(&btnc->i_pages, newkey);
|
||||
unlock_page(ctxt->bh->b_page);
|
||||
} else
|
||||
brelse(nbh);
|
||||
} else {
|
||||
/*
|
||||
* When canceling a buffer that a prepare operation has
|
||||
* allocated to copy a node block to another location, use
|
||||
* nilfs_btnode_delete() to initialize and release the buffer
|
||||
* so that the buffer flags will not be in an inconsistent
|
||||
* state when it is reallocated.
|
||||
*/
|
||||
nilfs_btnode_delete(nbh);
|
||||
}
|
||||
}
|
||||
|
@ -782,6 +782,15 @@ int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs)
|
||||
goto out_header;
|
||||
|
||||
sui->ncleansegs -= nsegs - newnsegs;
|
||||
|
||||
/*
|
||||
* If the sufile is successfully truncated, immediately adjust
|
||||
* the segment allocation space while locking the semaphore
|
||||
* "mi_sem" so that nilfs_sufile_alloc() never allocates
|
||||
* segments in the truncated space.
|
||||
*/
|
||||
sui->allocmax = newnsegs - 1;
|
||||
sui->allocmin = 0;
|
||||
}
|
||||
|
||||
kaddr = kmap_atomic(header_bh->b_page);
|
||||
|
@ -2103,14 +2103,20 @@ static long ocfs2_fallocate(struct file *file, int mode, loff_t offset,
|
||||
struct ocfs2_space_resv sr;
|
||||
int change_size = 1;
|
||||
int cmd = OCFS2_IOC_RESVSP64;
|
||||
int ret = 0;
|
||||
|
||||
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
|
||||
return -EOPNOTSUPP;
|
||||
if (!ocfs2_writes_unwritten_extents(osb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (mode & FALLOC_FL_KEEP_SIZE)
|
||||
if (mode & FALLOC_FL_KEEP_SIZE) {
|
||||
change_size = 0;
|
||||
} else {
|
||||
ret = inode_newsize_ok(inode, offset + len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mode & FALLOC_FL_PUNCH_HOLE)
|
||||
cmd = OCFS2_IOC_UNRESVSP64;
|
||||
|
@ -955,8 +955,10 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
|
||||
for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
|
||||
if (!sb_has_quota_loaded(sb, type))
|
||||
continue;
|
||||
oinfo = sb_dqinfo(sb, type)->dqi_priv;
|
||||
cancel_delayed_work_sync(&oinfo->dqi_sync_work);
|
||||
if (!sb_has_quota_suspended(sb, type)) {
|
||||
oinfo = sb_dqinfo(sb, type)->dqi_priv;
|
||||
cancel_delayed_work_sync(&oinfo->dqi_sync_work);
|
||||
}
|
||||
inode = igrab(sb->s_dquot.files[type]);
|
||||
/* Turn off quotas. This will remove all dquot structures from
|
||||
* memory and so they will be automatically synced to global
|
||||
|
@ -1715,7 +1715,6 @@ enum netdev_priv_flags {
|
||||
* @tipc_ptr: TIPC specific data
|
||||
* @atalk_ptr: AppleTalk link
|
||||
* @ip_ptr: IPv4 specific data
|
||||
* @dn_ptr: DECnet specific data
|
||||
* @ip6_ptr: IPv6 specific data
|
||||
* @ax25_ptr: AX.25 specific data
|
||||
* @ieee80211_ptr: IEEE 802.11 specific data, assign before registering
|
||||
@ -1960,9 +1959,6 @@ struct net_device {
|
||||
void *atalk_ptr;
|
||||
#endif
|
||||
struct in_device __rcu *ip_ptr;
|
||||
#if IS_ENABLED(CONFIG_DECNET)
|
||||
struct dn_dev __rcu *dn_ptr;
|
||||
#endif
|
||||
struct inet6_dev __rcu *ip6_ptr;
|
||||
#if IS_ENABLED(CONFIG_AX25)
|
||||
void *ax25_ptr;
|
||||
|
@ -241,11 +241,6 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
|
||||
hook_head = rcu_dereference(net->nf.hooks_bridge[hook]);
|
||||
#endif
|
||||
break;
|
||||
#if IS_ENABLED(CONFIG_DECNET)
|
||||
case NFPROTO_DECNET:
|
||||
hook_head = rcu_dereference(net->nf.hooks_decnet[hook]);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
|
@ -7,14 +7,6 @@
|
||||
/* in/out/forward only */
|
||||
#define NF_ARP_NUMHOOKS 3
|
||||
|
||||
/* max hook is NF_DN_ROUTE (6), also see uapi/linux/netfilter_decnet.h */
|
||||
#define NF_DN_NUMHOOKS 7
|
||||
|
||||
#if IS_ENABLED(CONFIG_DECNET)
|
||||
/* Largest hook number + 1, see uapi/linux/netfilter_decnet.h */
|
||||
#define NF_MAX_HOOKS NF_DN_NUMHOOKS
|
||||
#else
|
||||
#define NF_MAX_HOOKS NF_INET_NUMHOOKS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
231
include/net/dn.h
231
include/net/dn.h
@ -1,231 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _NET_DN_H
|
||||
#define _NET_DN_H
|
||||
|
||||
#include <linux/dn.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/flow.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
struct dn_scp /* Session Control Port */
|
||||
{
|
||||
unsigned char state;
|
||||
#define DN_O 1 /* Open */
|
||||
#define DN_CR 2 /* Connect Receive */
|
||||
#define DN_DR 3 /* Disconnect Reject */
|
||||
#define DN_DRC 4 /* Discon. Rej. Complete*/
|
||||
#define DN_CC 5 /* Connect Confirm */
|
||||
#define DN_CI 6 /* Connect Initiate */
|
||||
#define DN_NR 7 /* No resources */
|
||||
#define DN_NC 8 /* No communication */
|
||||
#define DN_CD 9 /* Connect Delivery */
|
||||
#define DN_RJ 10 /* Rejected */
|
||||
#define DN_RUN 11 /* Running */
|
||||
#define DN_DI 12 /* Disconnect Initiate */
|
||||
#define DN_DIC 13 /* Disconnect Complete */
|
||||
#define DN_DN 14 /* Disconnect Notificat */
|
||||
#define DN_CL 15 /* Closed */
|
||||
#define DN_CN 16 /* Closed Notification */
|
||||
|
||||
__le16 addrloc;
|
||||
__le16 addrrem;
|
||||
__u16 numdat;
|
||||
__u16 numoth;
|
||||
__u16 numoth_rcv;
|
||||
__u16 numdat_rcv;
|
||||
__u16 ackxmt_dat;
|
||||
__u16 ackxmt_oth;
|
||||
__u16 ackrcv_dat;
|
||||
__u16 ackrcv_oth;
|
||||
__u8 flowrem_sw;
|
||||
__u8 flowloc_sw;
|
||||
#define DN_SEND 2
|
||||
#define DN_DONTSEND 1
|
||||
#define DN_NOCHANGE 0
|
||||
__u16 flowrem_dat;
|
||||
__u16 flowrem_oth;
|
||||
__u16 flowloc_dat;
|
||||
__u16 flowloc_oth;
|
||||
__u8 services_rem;
|
||||
__u8 services_loc;
|
||||
__u8 info_rem;
|
||||
__u8 info_loc;
|
||||
|
||||
__u16 segsize_rem;
|
||||
__u16 segsize_loc;
|
||||
|
||||
__u8 nonagle;
|
||||
__u8 multi_ireq;
|
||||
__u8 accept_mode;
|
||||
unsigned long seg_total; /* Running total of current segment */
|
||||
|
||||
struct optdata_dn conndata_in;
|
||||
struct optdata_dn conndata_out;
|
||||
struct optdata_dn discdata_in;
|
||||
struct optdata_dn discdata_out;
|
||||
struct accessdata_dn accessdata;
|
||||
|
||||
struct sockaddr_dn addr; /* Local address */
|
||||
struct sockaddr_dn peer; /* Remote address */
|
||||
|
||||
/*
|
||||
* In this case the RTT estimation is not specified in the
|
||||
* docs, nor is any back off algorithm. Here we follow well
|
||||
* known tcp algorithms with a few small variations.
|
||||
*
|
||||
* snd_window: Max number of packets we send before we wait for
|
||||
* an ack to come back. This will become part of a
|
||||
* more complicated scheme when we support flow
|
||||
* control.
|
||||
*
|
||||
* nsp_srtt: Round-Trip-Time (x8) in jiffies. This is a rolling
|
||||
* average.
|
||||
* nsp_rttvar: Round-Trip-Time-Varience (x4) in jiffies. This is the
|
||||
* varience of the smoothed average (but calculated in
|
||||
* a simpler way than for normal statistical varience
|
||||
* calculations).
|
||||
*
|
||||
* nsp_rxtshift: Backoff counter. Value is zero normally, each time
|
||||
* a packet is lost is increases by one until an ack
|
||||
* is received. Its used to index an array of backoff
|
||||
* multipliers.
|
||||
*/
|
||||
#define NSP_MIN_WINDOW 1
|
||||
#define NSP_MAX_WINDOW (0x07fe)
|
||||
unsigned long max_window;
|
||||
unsigned long snd_window;
|
||||
#define NSP_INITIAL_SRTT (HZ)
|
||||
unsigned long nsp_srtt;
|
||||
#define NSP_INITIAL_RTTVAR (HZ*3)
|
||||
unsigned long nsp_rttvar;
|
||||
#define NSP_MAXRXTSHIFT 12
|
||||
unsigned long nsp_rxtshift;
|
||||
|
||||
/*
|
||||
* Output queues, one for data, one for otherdata/linkservice
|
||||
*/
|
||||
struct sk_buff_head data_xmit_queue;
|
||||
struct sk_buff_head other_xmit_queue;
|
||||
|
||||
/*
|
||||
* Input queue for other data
|
||||
*/
|
||||
struct sk_buff_head other_receive_queue;
|
||||
int other_report;
|
||||
|
||||
/*
|
||||
* Stuff to do with the slow timer
|
||||
*/
|
||||
unsigned long stamp; /* time of last transmit */
|
||||
unsigned long persist;
|
||||
int (*persist_fxn)(struct sock *sk);
|
||||
unsigned long keepalive;
|
||||
void (*keepalive_fxn)(struct sock *sk);
|
||||
|
||||
};
|
||||
|
||||
static inline struct dn_scp *DN_SK(struct sock *sk)
|
||||
{
|
||||
return (struct dn_scp *)(sk + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* src,dst : Source and Destination DECnet addresses
|
||||
* hops : Number of hops through the network
|
||||
* dst_port, src_port : NSP port numbers
|
||||
* services, info : Useful data extracted from conninit messages
|
||||
* rt_flags : Routing flags byte
|
||||
* nsp_flags : NSP layer flags byte
|
||||
* segsize : Size of segment
|
||||
* segnum : Number, for data, otherdata and linkservice
|
||||
* xmit_count : Number of times we've transmitted this skb
|
||||
* stamp : Time stamp of most recent transmission, used in RTT calculations
|
||||
* iif: Input interface number
|
||||
*
|
||||
* As a general policy, this structure keeps all addresses in network
|
||||
* byte order, and all else in host byte order. Thus dst, src, dst_port
|
||||
* and src_port are in network order. All else is in host order.
|
||||
*
|
||||
*/
|
||||
#define DN_SKB_CB(skb) ((struct dn_skb_cb *)(skb)->cb)
|
||||
struct dn_skb_cb {
|
||||
__le16 dst;
|
||||
__le16 src;
|
||||
__u16 hops;
|
||||
__le16 dst_port;
|
||||
__le16 src_port;
|
||||
__u8 services;
|
||||
__u8 info;
|
||||
__u8 rt_flags;
|
||||
__u8 nsp_flags;
|
||||
__u16 segsize;
|
||||
__u16 segnum;
|
||||
__u16 xmit_count;
|
||||
unsigned long stamp;
|
||||
int iif;
|
||||
};
|
||||
|
||||
static inline __le16 dn_eth2dn(unsigned char *ethaddr)
|
||||
{
|
||||
return get_unaligned((__le16 *)(ethaddr + 4));
|
||||
}
|
||||
|
||||
static inline __le16 dn_saddr2dn(struct sockaddr_dn *saddr)
|
||||
{
|
||||
return *(__le16 *)saddr->sdn_nodeaddr;
|
||||
}
|
||||
|
||||
static inline void dn_dn2eth(unsigned char *ethaddr, __le16 addr)
|
||||
{
|
||||
__u16 a = le16_to_cpu(addr);
|
||||
ethaddr[0] = 0xAA;
|
||||
ethaddr[1] = 0x00;
|
||||
ethaddr[2] = 0x04;
|
||||
ethaddr[3] = 0x00;
|
||||
ethaddr[4] = (__u8)(a & 0xff);
|
||||
ethaddr[5] = (__u8)(a >> 8);
|
||||
}
|
||||
|
||||
static inline void dn_sk_ports_copy(struct flowidn *fld, struct dn_scp *scp)
|
||||
{
|
||||
fld->fld_sport = scp->addrloc;
|
||||
fld->fld_dport = scp->addrrem;
|
||||
}
|
||||
|
||||
unsigned int dn_mss_from_pmtu(struct net_device *dev, int mtu);
|
||||
void dn_register_sysctl(void);
|
||||
void dn_unregister_sysctl(void);
|
||||
|
||||
#define DN_MENUVER_ACC 0x01
|
||||
#define DN_MENUVER_USR 0x02
|
||||
#define DN_MENUVER_PRX 0x04
|
||||
#define DN_MENUVER_UIC 0x08
|
||||
|
||||
struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr);
|
||||
struct sock *dn_find_by_skb(struct sk_buff *skb);
|
||||
#define DN_ASCBUF_LEN 9
|
||||
char *dn_addr2asc(__u16, char *);
|
||||
int dn_destroy_timer(struct sock *sk);
|
||||
|
||||
int dn_sockaddr2username(struct sockaddr_dn *addr, unsigned char *buf,
|
||||
unsigned char type);
|
||||
int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *addr,
|
||||
unsigned char *type);
|
||||
|
||||
void dn_start_slow_timer(struct sock *sk);
|
||||
void dn_stop_slow_timer(struct sock *sk);
|
||||
|
||||
extern __le16 decnet_address;
|
||||
extern int decnet_debug_level;
|
||||
extern int decnet_time_wait;
|
||||
extern int decnet_dn_count;
|
||||
extern int decnet_di_count;
|
||||
extern int decnet_dr_count;
|
||||
extern int decnet_no_fc_max_cwnd;
|
||||
|
||||
extern long sysctl_decnet_mem[3];
|
||||
extern int sysctl_decnet_wmem[3];
|
||||
extern int sysctl_decnet_rmem[3];
|
||||
|
||||
#endif /* _NET_DN_H */
|
@ -1,199 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _NET_DN_DEV_H
|
||||
#define _NET_DN_DEV_H
|
||||
|
||||
|
||||
struct dn_dev;
|
||||
|
||||
struct dn_ifaddr {
|
||||
struct dn_ifaddr __rcu *ifa_next;
|
||||
struct dn_dev *ifa_dev;
|
||||
__le16 ifa_local;
|
||||
__le16 ifa_address;
|
||||
__u32 ifa_flags;
|
||||
__u8 ifa_scope;
|
||||
char ifa_label[IFNAMSIZ];
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
#define DN_DEV_S_RU 0 /* Run - working normally */
|
||||
#define DN_DEV_S_CR 1 /* Circuit Rejected */
|
||||
#define DN_DEV_S_DS 2 /* Data Link Start */
|
||||
#define DN_DEV_S_RI 3 /* Routing Layer Initialize */
|
||||
#define DN_DEV_S_RV 4 /* Routing Layer Verify */
|
||||
#define DN_DEV_S_RC 5 /* Routing Layer Complete */
|
||||
#define DN_DEV_S_OF 6 /* Off */
|
||||
#define DN_DEV_S_HA 7 /* Halt */
|
||||
|
||||
|
||||
/*
|
||||
* The dn_dev_parms structure contains the set of parameters
|
||||
* for each device (hence inclusion in the dn_dev structure)
|
||||
* and an array is used to store the default types of supported
|
||||
* device (in dn_dev.c).
|
||||
*
|
||||
* The type field matches the ARPHRD_ constants and is used in
|
||||
* searching the list for supported devices when new devices
|
||||
* come up.
|
||||
*
|
||||
* The mode field is used to find out if a device is broadcast,
|
||||
* multipoint, or pointopoint. Please note that DECnet thinks
|
||||
* different ways about devices to the rest of the kernel
|
||||
* so the normal IFF_xxx flags are invalid here. For devices
|
||||
* which can be any combination of the previously mentioned
|
||||
* attributes, you can set this on a per device basis by
|
||||
* installing an up() routine.
|
||||
*
|
||||
* The device state field, defines the initial state in which the
|
||||
* device will come up. In the dn_dev structure, it is the actual
|
||||
* state.
|
||||
*
|
||||
* Things have changed here. I've killed timer1 since it's a user space
|
||||
* issue for a user space routing deamon to sort out. The kernel does
|
||||
* not need to be bothered with it.
|
||||
*
|
||||
* Timers:
|
||||
* t2 - Rate limit timer, min time between routing and hello messages
|
||||
* t3 - Hello timer, send hello messages when it expires
|
||||
*
|
||||
* Callbacks:
|
||||
* up() - Called to initialize device, return value can veto use of
|
||||
* device with DECnet.
|
||||
* down() - Called to turn device off when it goes down
|
||||
* timer3() - Called once for each ifaddr when timer 3 goes off
|
||||
*
|
||||
* sysctl - Hook for sysctl things
|
||||
*
|
||||
*/
|
||||
struct dn_dev_parms {
|
||||
int type; /* ARPHRD_xxx */
|
||||
int mode; /* Broadcast, Unicast, Mulitpoint */
|
||||
#define DN_DEV_BCAST 1
|
||||
#define DN_DEV_UCAST 2
|
||||
#define DN_DEV_MPOINT 4
|
||||
int state; /* Initial state */
|
||||
int forwarding; /* 0=EndNode, 1=L1Router, 2=L2Router */
|
||||
unsigned long t2; /* Default value of t2 */
|
||||
unsigned long t3; /* Default value of t3 */
|
||||
int priority; /* Priority to be a router */
|
||||
char *name; /* Name for sysctl */
|
||||
int (*up)(struct net_device *);
|
||||
void (*down)(struct net_device *);
|
||||
void (*timer3)(struct net_device *, struct dn_ifaddr *ifa);
|
||||
void *sysctl;
|
||||
};
|
||||
|
||||
|
||||
struct dn_dev {
|
||||
struct dn_ifaddr __rcu *ifa_list;
|
||||
struct net_device *dev;
|
||||
struct dn_dev_parms parms;
|
||||
char use_long;
|
||||
struct timer_list timer;
|
||||
unsigned long t3;
|
||||
struct neigh_parms *neigh_parms;
|
||||
__u8 addr[ETH_ALEN];
|
||||
struct neighbour *router; /* Default router on circuit */
|
||||
struct neighbour *peer; /* Peer on pointopoint links */
|
||||
unsigned long uptime; /* Time device went up in jiffies */
|
||||
};
|
||||
|
||||
struct dn_short_packet {
|
||||
__u8 msgflg;
|
||||
__le16 dstnode;
|
||||
__le16 srcnode;
|
||||
__u8 forward;
|
||||
} __packed;
|
||||
|
||||
struct dn_long_packet {
|
||||
__u8 msgflg;
|
||||
__u8 d_area;
|
||||
__u8 d_subarea;
|
||||
__u8 d_id[6];
|
||||
__u8 s_area;
|
||||
__u8 s_subarea;
|
||||
__u8 s_id[6];
|
||||
__u8 nl2;
|
||||
__u8 visit_ct;
|
||||
__u8 s_class;
|
||||
__u8 pt;
|
||||
} __packed;
|
||||
|
||||
/*------------------------- DRP - Routing messages ---------------------*/
|
||||
|
||||
struct endnode_hello_message {
|
||||
__u8 msgflg;
|
||||
__u8 tiver[3];
|
||||
__u8 id[6];
|
||||
__u8 iinfo;
|
||||
__le16 blksize;
|
||||
__u8 area;
|
||||
__u8 seed[8];
|
||||
__u8 neighbor[6];
|
||||
__le16 timer;
|
||||
__u8 mpd;
|
||||
__u8 datalen;
|
||||
__u8 data[2];
|
||||
} __packed;
|
||||
|
||||
struct rtnode_hello_message {
|
||||
__u8 msgflg;
|
||||
__u8 tiver[3];
|
||||
__u8 id[6];
|
||||
__u8 iinfo;
|
||||
__le16 blksize;
|
||||
__u8 priority;
|
||||
__u8 area;
|
||||
__le16 timer;
|
||||
__u8 mpd;
|
||||
} __packed;
|
||||
|
||||
|
||||
void dn_dev_init(void);
|
||||
void dn_dev_cleanup(void);
|
||||
|
||||
int dn_dev_ioctl(unsigned int cmd, void __user *arg);
|
||||
|
||||
void dn_dev_devices_off(void);
|
||||
void dn_dev_devices_on(void);
|
||||
|
||||
void dn_dev_init_pkt(struct sk_buff *skb);
|
||||
void dn_dev_veri_pkt(struct sk_buff *skb);
|
||||
void dn_dev_hello(struct sk_buff *skb);
|
||||
|
||||
void dn_dev_up(struct net_device *);
|
||||
void dn_dev_down(struct net_device *);
|
||||
|
||||
int dn_dev_set_default(struct net_device *dev, int force);
|
||||
struct net_device *dn_dev_get_default(void);
|
||||
int dn_dev_bind_default(__le16 *addr);
|
||||
|
||||
int register_dnaddr_notifier(struct notifier_block *nb);
|
||||
int unregister_dnaddr_notifier(struct notifier_block *nb);
|
||||
|
||||
static inline int dn_dev_islocal(struct net_device *dev, __le16 addr)
|
||||
{
|
||||
struct dn_dev *dn_db;
|
||||
struct dn_ifaddr *ifa;
|
||||
int res = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
dn_db = rcu_dereference(dev->dn_ptr);
|
||||
if (dn_db == NULL) {
|
||||
printk(KERN_DEBUG "dn_dev_islocal: Called for non DECnet device\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (ifa = rcu_dereference(dn_db->ifa_list);
|
||||
ifa != NULL;
|
||||
ifa = rcu_dereference(ifa->ifa_next))
|
||||
if ((addr ^ ifa->ifa_local) == 0) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* _NET_DN_DEV_H */
|
@ -1,167 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _NET_DN_FIB_H
|
||||
#define _NET_DN_FIB_H
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
extern const struct nla_policy rtm_dn_policy[];
|
||||
|
||||
struct dn_fib_res {
|
||||
struct fib_rule *r;
|
||||
struct dn_fib_info *fi;
|
||||
unsigned char prefixlen;
|
||||
unsigned char nh_sel;
|
||||
unsigned char type;
|
||||
unsigned char scope;
|
||||
};
|
||||
|
||||
struct dn_fib_nh {
|
||||
struct net_device *nh_dev;
|
||||
unsigned int nh_flags;
|
||||
unsigned char nh_scope;
|
||||
int nh_weight;
|
||||
int nh_power;
|
||||
int nh_oif;
|
||||
__le16 nh_gw;
|
||||
};
|
||||
|
||||
struct dn_fib_info {
|
||||
struct dn_fib_info *fib_next;
|
||||
struct dn_fib_info *fib_prev;
|
||||
int fib_treeref;
|
||||
refcount_t fib_clntref;
|
||||
int fib_dead;
|
||||
unsigned int fib_flags;
|
||||
int fib_protocol;
|
||||
__le16 fib_prefsrc;
|
||||
__u32 fib_priority;
|
||||
__u32 fib_metrics[RTAX_MAX];
|
||||
int fib_nhs;
|
||||
int fib_power;
|
||||
struct dn_fib_nh fib_nh[0];
|
||||
#define dn_fib_dev fib_nh[0].nh_dev
|
||||
};
|
||||
|
||||
|
||||
#define DN_FIB_RES_RESET(res) ((res).nh_sel = 0)
|
||||
#define DN_FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel])
|
||||
|
||||
#define DN_FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __dn_fib_res_prefsrc(&res))
|
||||
#define DN_FIB_RES_GW(res) (DN_FIB_RES_NH(res).nh_gw)
|
||||
#define DN_FIB_RES_DEV(res) (DN_FIB_RES_NH(res).nh_dev)
|
||||
#define DN_FIB_RES_OIF(res) (DN_FIB_RES_NH(res).nh_oif)
|
||||
|
||||
typedef struct {
|
||||
__le16 datum;
|
||||
} dn_fib_key_t;
|
||||
|
||||
typedef struct {
|
||||
__le16 datum;
|
||||
} dn_fib_hash_t;
|
||||
|
||||
typedef struct {
|
||||
__u16 datum;
|
||||
} dn_fib_idx_t;
|
||||
|
||||
struct dn_fib_node {
|
||||
struct dn_fib_node *fn_next;
|
||||
struct dn_fib_info *fn_info;
|
||||
#define DN_FIB_INFO(f) ((f)->fn_info)
|
||||
dn_fib_key_t fn_key;
|
||||
u8 fn_type;
|
||||
u8 fn_scope;
|
||||
u8 fn_state;
|
||||
};
|
||||
|
||||
|
||||
struct dn_fib_table {
|
||||
struct hlist_node hlist;
|
||||
u32 n;
|
||||
|
||||
int (*insert)(struct dn_fib_table *t, struct rtmsg *r,
|
||||
struct nlattr *attrs[], struct nlmsghdr *n,
|
||||
struct netlink_skb_parms *req);
|
||||
int (*delete)(struct dn_fib_table *t, struct rtmsg *r,
|
||||
struct nlattr *attrs[], struct nlmsghdr *n,
|
||||
struct netlink_skb_parms *req);
|
||||
int (*lookup)(struct dn_fib_table *t, const struct flowidn *fld,
|
||||
struct dn_fib_res *res);
|
||||
int (*flush)(struct dn_fib_table *t);
|
||||
int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
|
||||
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DECNET_ROUTER
|
||||
/*
|
||||
* dn_fib.c
|
||||
*/
|
||||
void dn_fib_init(void);
|
||||
void dn_fib_cleanup(void);
|
||||
|
||||
int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
|
||||
struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r,
|
||||
struct nlattr *attrs[],
|
||||
const struct nlmsghdr *nlh, int *errp);
|
||||
int dn_fib_semantic_match(int type, struct dn_fib_info *fi,
|
||||
const struct flowidn *fld, struct dn_fib_res *res);
|
||||
void dn_fib_release_info(struct dn_fib_info *fi);
|
||||
void dn_fib_flush(void);
|
||||
void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res);
|
||||
|
||||
/*
|
||||
* dn_tables.c
|
||||
*/
|
||||
struct dn_fib_table *dn_fib_get_table(u32 n, int creat);
|
||||
struct dn_fib_table *dn_fib_empty_table(void);
|
||||
void dn_fib_table_init(void);
|
||||
void dn_fib_table_cleanup(void);
|
||||
|
||||
/*
|
||||
* dn_rules.c
|
||||
*/
|
||||
void dn_fib_rules_init(void);
|
||||
void dn_fib_rules_cleanup(void);
|
||||
unsigned int dnet_addr_type(__le16 addr);
|
||||
int dn_fib_lookup(struct flowidn *fld, struct dn_fib_res *res);
|
||||
|
||||
int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
|
||||
void dn_fib_free_info(struct dn_fib_info *fi);
|
||||
|
||||
static inline void dn_fib_info_put(struct dn_fib_info *fi)
|
||||
{
|
||||
if (refcount_dec_and_test(&fi->fib_clntref))
|
||||
dn_fib_free_info(fi);
|
||||
}
|
||||
|
||||
static inline void dn_fib_res_put(struct dn_fib_res *res)
|
||||
{
|
||||
if (res->fi)
|
||||
dn_fib_info_put(res->fi);
|
||||
if (res->r)
|
||||
fib_rule_put(res->r);
|
||||
}
|
||||
|
||||
#else /* Endnode */
|
||||
|
||||
#define dn_fib_init() do { } while(0)
|
||||
#define dn_fib_cleanup() do { } while(0)
|
||||
|
||||
#define dn_fib_lookup(fl, res) (-ESRCH)
|
||||
#define dn_fib_info_put(fi) do { } while(0)
|
||||
#define dn_fib_select_multipath(fl, res) do { } while(0)
|
||||
#define dn_fib_rules_policy(saddr,res,flags) (0)
|
||||
#define dn_fib_res_put(res) do { } while(0)
|
||||
|
||||
#endif /* CONFIG_DECNET_ROUTER */
|
||||
|
||||
static inline __le16 dnet_make_mask(int n)
|
||||
{
|
||||
if (n)
|
||||
return cpu_to_le16(~((1 << (16 - n)) - 1));
|
||||
return cpu_to_le16(0);
|
||||
}
|
||||
|
||||
#endif /* _NET_DN_FIB_H */
|
@ -1,30 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _NET_DN_NEIGH_H
|
||||
#define _NET_DN_NEIGH_H
|
||||
|
||||
/*
|
||||
* The position of the first two fields of
|
||||
* this structure are critical - SJW
|
||||
*/
|
||||
struct dn_neigh {
|
||||
struct neighbour n;
|
||||
__le16 addr;
|
||||
unsigned long flags;
|
||||
#define DN_NDFLAG_R1 0x0001 /* Router L1 */
|
||||
#define DN_NDFLAG_R2 0x0002 /* Router L2 */
|
||||
#define DN_NDFLAG_P3 0x0004 /* Phase III Node */
|
||||
unsigned long blksize;
|
||||
__u8 priority;
|
||||
};
|
||||
|
||||
void dn_neigh_init(void);
|
||||
void dn_neigh_cleanup(void);
|
||||
int dn_neigh_router_hello(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||
int dn_neigh_endnode_hello(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||
void dn_neigh_pointopoint_hello(struct sk_buff *skb);
|
||||
int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n);
|
||||
int dn_to_neigh_output(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
extern struct neigh_table dn_neigh_table;
|
||||
|
||||
#endif /* _NET_DN_NEIGH_H */
|
@ -1,195 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef _NET_DN_NSP_H
|
||||
#define _NET_DN_NSP_H
|
||||
/******************************************************************************
|
||||
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
|
||||
|
||||
*******************************************************************************/
|
||||
/* dn_nsp.c functions prototyping */
|
||||
|
||||
void dn_nsp_send_data_ack(struct sock *sk);
|
||||
void dn_nsp_send_oth_ack(struct sock *sk);
|
||||
void dn_send_conn_ack(struct sock *sk);
|
||||
void dn_send_conn_conf(struct sock *sk, gfp_t gfp);
|
||||
void dn_nsp_send_disc(struct sock *sk, unsigned char type,
|
||||
unsigned short reason, gfp_t gfp);
|
||||
void dn_nsp_return_disc(struct sk_buff *skb, unsigned char type,
|
||||
unsigned short reason);
|
||||
void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval);
|
||||
void dn_nsp_send_conninit(struct sock *sk, unsigned char flags);
|
||||
|
||||
void dn_nsp_output(struct sock *sk);
|
||||
int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb,
|
||||
struct sk_buff_head *q, unsigned short acknum);
|
||||
void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb, gfp_t gfp,
|
||||
int oob);
|
||||
unsigned long dn_nsp_persist(struct sock *sk);
|
||||
int dn_nsp_xmit_timeout(struct sock *sk);
|
||||
|
||||
int dn_nsp_rx(struct sk_buff *);
|
||||
int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri);
|
||||
struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock,
|
||||
long timeo, int *err);
|
||||
|
||||
#define NSP_REASON_OK 0 /* No error */
|
||||
#define NSP_REASON_NR 1 /* No resources */
|
||||
#define NSP_REASON_UN 2 /* Unrecognised node name */
|
||||
#define NSP_REASON_SD 3 /* Node shutting down */
|
||||
#define NSP_REASON_ID 4 /* Invalid destination end user */
|
||||
#define NSP_REASON_ER 5 /* End user lacks resources */
|
||||
#define NSP_REASON_OB 6 /* Object too busy */
|
||||
#define NSP_REASON_US 7 /* Unspecified error */
|
||||
#define NSP_REASON_TP 8 /* Third-Party abort */
|
||||
#define NSP_REASON_EA 9 /* End user has aborted the link */
|
||||
#define NSP_REASON_IF 10 /* Invalid node name format */
|
||||
#define NSP_REASON_LS 11 /* Local node shutdown */
|
||||
#define NSP_REASON_LL 32 /* Node lacks logical-link resources */
|
||||
#define NSP_REASON_LE 33 /* End user lacks logical-link resources */
|
||||
#define NSP_REASON_UR 34 /* Unacceptable RQSTRID or PASSWORD field */
|
||||
#define NSP_REASON_UA 36 /* Unacceptable ACCOUNT field */
|
||||
#define NSP_REASON_TM 38 /* End user timed out logical link */
|
||||
#define NSP_REASON_NU 39 /* Node unreachable */
|
||||
#define NSP_REASON_NL 41 /* No-link message */
|
||||
#define NSP_REASON_DC 42 /* Disconnect confirm */
|
||||
#define NSP_REASON_IO 43 /* Image data field overflow */
|
||||
|
||||
#define NSP_DISCINIT 0x38
|
||||
#define NSP_DISCCONF 0x48
|
||||
|
||||
/*------------------------- NSP - messages ------------------------------*/
|
||||
/* Data Messages */
|
||||
/*---------------*/
|
||||
|
||||
/* Data Messages (data segment/interrupt/link service) */
|
||||
|
||||
struct nsp_data_seg_msg {
|
||||
__u8 msgflg;
|
||||
__le16 dstaddr;
|
||||
__le16 srcaddr;
|
||||
} __packed;
|
||||
|
||||
struct nsp_data_opt_msg {
|
||||
__le16 acknum;
|
||||
__le16 segnum;
|
||||
__le16 lsflgs;
|
||||
} __packed;
|
||||
|
||||
struct nsp_data_opt_msg1 {
|
||||
__le16 acknum;
|
||||
__le16 segnum;
|
||||
} __packed;
|
||||
|
||||
|
||||
/* Acknowledgment Message (data/other data) */
|
||||
struct nsp_data_ack_msg {
|
||||
__u8 msgflg;
|
||||
__le16 dstaddr;
|
||||
__le16 srcaddr;
|
||||
__le16 acknum;
|
||||
} __packed;
|
||||
|
||||
/* Connect Acknowledgment Message */
|
||||
struct nsp_conn_ack_msg {
|
||||
__u8 msgflg;
|
||||
__le16 dstaddr;
|
||||
} __packed;
|
||||
|
||||
|
||||
/* Connect Initiate/Retransmit Initiate/Connect Confirm */
|
||||
struct nsp_conn_init_msg {
|
||||
__u8 msgflg;
|
||||
#define NSP_CI 0x18 /* Connect Initiate */
|
||||
#define NSP_RCI 0x68 /* Retrans. Conn Init */
|
||||
__le16 dstaddr;
|
||||
__le16 srcaddr;
|
||||
__u8 services;
|
||||
#define NSP_FC_NONE 0x00 /* Flow Control None */
|
||||
#define NSP_FC_SRC 0x04 /* Seg Req. Count */
|
||||
#define NSP_FC_SCMC 0x08 /* Sess. Control Mess */
|
||||
#define NSP_FC_MASK 0x0c /* FC type mask */
|
||||
__u8 info;
|
||||
__le16 segsize;
|
||||
} __packed;
|
||||
|
||||
/* Disconnect Initiate/Disconnect Confirm */
|
||||
struct nsp_disconn_init_msg {
|
||||
__u8 msgflg;
|
||||
__le16 dstaddr;
|
||||
__le16 srcaddr;
|
||||
__le16 reason;
|
||||
} __packed;
|
||||
|
||||
|
||||
|
||||
struct srcobj_fmt {
|
||||
__u8 format;
|
||||
__u8 task;
|
||||
__le16 grpcode;
|
||||
__le16 usrcode;
|
||||
__u8 dlen;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* A collection of functions for manipulating the sequence
|
||||
* numbers used in NSP. Similar in operation to the functions
|
||||
* of the same name in TCP.
|
||||
*/
|
||||
static __inline__ int dn_before(__u16 seq1, __u16 seq2)
|
||||
{
|
||||
seq1 &= 0x0fff;
|
||||
seq2 &= 0x0fff;
|
||||
|
||||
return (int)((seq1 - seq2) & 0x0fff) > 2048;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ int dn_after(__u16 seq1, __u16 seq2)
|
||||
{
|
||||
seq1 &= 0x0fff;
|
||||
seq2 &= 0x0fff;
|
||||
|
||||
return (int)((seq2 - seq1) & 0x0fff) > 2048;
|
||||
}
|
||||
|
||||
static __inline__ int dn_equal(__u16 seq1, __u16 seq2)
|
||||
{
|
||||
return ((seq1 ^ seq2) & 0x0fff) == 0;
|
||||
}
|
||||
|
||||
static __inline__ int dn_before_or_equal(__u16 seq1, __u16 seq2)
|
||||
{
|
||||
return (dn_before(seq1, seq2) || dn_equal(seq1, seq2));
|
||||
}
|
||||
|
||||
static __inline__ void seq_add(__u16 *seq, __u16 off)
|
||||
{
|
||||
(*seq) += off;
|
||||
(*seq) &= 0x0fff;
|
||||
}
|
||||
|
||||
static __inline__ int seq_next(__u16 seq1, __u16 seq2)
|
||||
{
|
||||
return dn_equal(seq1 + 1, seq2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Can we delay the ack ?
|
||||
*/
|
||||
static __inline__ int sendack(__u16 seq)
|
||||
{
|
||||
return (int)((seq & 0x1000) ? 0 : 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is socket congested ?
|
||||
*/
|
||||
static __inline__ int dn_congested(struct sock *sk)
|
||||
{
|
||||
return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1);
|
||||
}
|
||||
|
||||
#define DN_MAX_NSP_DATA_HEADER (11)
|
||||
|
||||
#endif /* _NET_DN_NSP_H */
|
@ -1,115 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef _NET_DN_ROUTE_H
|
||||
#define _NET_DN_ROUTE_H
|
||||
|
||||
/******************************************************************************
|
||||
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri);
|
||||
int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *,
|
||||
struct sock *sk, int flags);
|
||||
int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
void dn_rt_cache_flush(int delay);
|
||||
int dn_route_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev);
|
||||
|
||||
/* Masks for flags field */
|
||||
#define DN_RT_F_PID 0x07 /* Mask for packet type */
|
||||
#define DN_RT_F_PF 0x80 /* Padding Follows */
|
||||
#define DN_RT_F_VER 0x40 /* Version =0 discard packet if ==1 */
|
||||
#define DN_RT_F_IE 0x20 /* Intra Ethernet, Reserved in short pkt */
|
||||
#define DN_RT_F_RTS 0x10 /* Packet is being returned to sender */
|
||||
#define DN_RT_F_RQR 0x08 /* Return packet to sender upon non-delivery */
|
||||
|
||||
/* Mask for types of routing packets */
|
||||
#define DN_RT_PKT_MSK 0x06
|
||||
/* Types of routing packets */
|
||||
#define DN_RT_PKT_SHORT 0x02 /* Short routing packet */
|
||||
#define DN_RT_PKT_LONG 0x06 /* Long routing packet */
|
||||
|
||||
/* Mask for control/routing selection */
|
||||
#define DN_RT_PKT_CNTL 0x01 /* Set to 1 if a control packet */
|
||||
/* Types of control packets */
|
||||
#define DN_RT_CNTL_MSK 0x0f /* Mask for control packets */
|
||||
#define DN_RT_PKT_INIT 0x01 /* Initialisation packet */
|
||||
#define DN_RT_PKT_VERI 0x03 /* Verification Message */
|
||||
#define DN_RT_PKT_HELO 0x05 /* Hello and Test Message */
|
||||
#define DN_RT_PKT_L1RT 0x07 /* Level 1 Routing Message */
|
||||
#define DN_RT_PKT_L2RT 0x09 /* Level 2 Routing Message */
|
||||
#define DN_RT_PKT_ERTH 0x0b /* Ethernet Router Hello */
|
||||
#define DN_RT_PKT_EEDH 0x0d /* Ethernet EndNode Hello */
|
||||
|
||||
/* Values for info field in hello message */
|
||||
#define DN_RT_INFO_TYPE 0x03 /* Type mask */
|
||||
#define DN_RT_INFO_L1RT 0x02 /* L1 Router */
|
||||
#define DN_RT_INFO_L2RT 0x01 /* L2 Router */
|
||||
#define DN_RT_INFO_ENDN 0x03 /* EndNode */
|
||||
#define DN_RT_INFO_VERI 0x04 /* Verification Reqd. */
|
||||
#define DN_RT_INFO_RJCT 0x08 /* Reject Flag, Reserved */
|
||||
#define DN_RT_INFO_VFLD 0x10 /* Verification Failed, Reserved */
|
||||
#define DN_RT_INFO_NOML 0x20 /* No Multicast traffic accepted */
|
||||
#define DN_RT_INFO_BLKR 0x40 /* Blocking Requested */
|
||||
|
||||
/*
|
||||
* The fl structure is what we used to look up the route.
|
||||
* The rt_saddr & rt_daddr entries are the same as key.saddr & key.daddr
|
||||
* except for local input routes, where the rt_saddr = fl.fld_dst and
|
||||
* rt_daddr = fl.fld_src to allow the route to be used for returning
|
||||
* packets to the originating host.
|
||||
*/
|
||||
struct dn_route {
|
||||
struct dst_entry dst;
|
||||
struct dn_route __rcu *dn_next;
|
||||
|
||||
struct neighbour *n;
|
||||
|
||||
struct flowidn fld;
|
||||
|
||||
__le16 rt_saddr;
|
||||
__le16 rt_daddr;
|
||||
__le16 rt_gateway;
|
||||
__le16 rt_local_src; /* Source used for forwarding packets */
|
||||
__le16 rt_src_map;
|
||||
__le16 rt_dst_map;
|
||||
|
||||
unsigned int rt_flags;
|
||||
unsigned int rt_type;
|
||||
};
|
||||
|
||||
static inline bool dn_is_input_route(struct dn_route *rt)
|
||||
{
|
||||
return rt->fld.flowidn_iif != 0;
|
||||
}
|
||||
|
||||
static inline bool dn_is_output_route(struct dn_route *rt)
|
||||
{
|
||||
return rt->fld.flowidn_iif == 0;
|
||||
}
|
||||
|
||||
void dn_route_init(void);
|
||||
void dn_route_cleanup(void);
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
||||
static inline void dn_rt_send(struct sk_buff *skb)
|
||||
{
|
||||
dev_queue_xmit(skb);
|
||||
}
|
||||
|
||||
static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst, char *src)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
|
||||
if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
|
||||
dst = NULL;
|
||||
|
||||
if (dev_hard_header(skb, dev, ETH_P_DNA_RT, dst, src, skb->len) >= 0)
|
||||
dn_rt_send(skb);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
#endif /* _NET_DN_ROUTE_H */
|
@ -236,12 +236,6 @@ static inline void dst_use_noref(struct dst_entry *dst, unsigned long time)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dst_hold_and_use(struct dst_entry *dst, unsigned long time)
|
||||
{
|
||||
dst_hold(dst);
|
||||
dst_use_noref(dst, time);
|
||||
}
|
||||
|
||||
static inline struct dst_entry *dst_clone(struct dst_entry *dst)
|
||||
{
|
||||
if (dst)
|
||||
|
@ -259,11 +259,6 @@ static inline void *neighbour_priv(const struct neighbour *n)
|
||||
|
||||
extern const struct nla_policy nda_policy[];
|
||||
|
||||
static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey)
|
||||
{
|
||||
return *(const u16 *)n->primary_key == *(const u16 *)pkey;
|
||||
}
|
||||
|
||||
static inline bool neigh_key_eq32(const struct neighbour *n, const void *pkey)
|
||||
{
|
||||
return *(const u32 *)n->primary_key == *(const u32 *)pkey;
|
||||
@ -313,8 +308,6 @@ void neigh_table_init(int index, struct neigh_table *tbl);
|
||||
int neigh_table_clear(int index, struct neigh_table *tbl);
|
||||
struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
|
||||
struct net_device *dev);
|
||||
struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
|
||||
const void *pkey);
|
||||
struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
|
||||
struct net_device *dev, bool want_ref);
|
||||
static inline struct neighbour *neigh_create(struct neigh_table *tbl,
|
||||
|
@ -25,9 +25,6 @@ struct netns_nf {
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
struct nf_hook_entries __rcu *hooks_bridge[NF_INET_NUMHOOKS];
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_DECNET)
|
||||
struct nf_hook_entries __rcu *hooks_decnet[NF_DN_NUMHOOKS];
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
|
||||
bool defrag_ipv4;
|
||||
#endif
|
||||
|
@ -1,149 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _LINUX_DN_H
|
||||
#define _LINUX_DN_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
/*
|
||||
|
||||
DECnet Data Structures and Constants
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* DNPROTO_NSP can't be the same as SOL_SOCKET,
|
||||
* so increment each by one (compared to ULTRIX)
|
||||
*/
|
||||
#define DNPROTO_NSP 2 /* NSP protocol number */
|
||||
#define DNPROTO_ROU 3 /* Routing protocol number */
|
||||
#define DNPROTO_NML 4 /* Net mgt protocol number */
|
||||
#define DNPROTO_EVL 5 /* Evl protocol number (usr) */
|
||||
#define DNPROTO_EVR 6 /* Evl protocol number (evl) */
|
||||
#define DNPROTO_NSPT 7 /* NSP trace protocol number */
|
||||
|
||||
|
||||
#define DN_ADDL 2
|
||||
#define DN_MAXADDL 2 /* ULTRIX headers have 20 here, but pathworks has 2 */
|
||||
#define DN_MAXOPTL 16
|
||||
#define DN_MAXOBJL 16
|
||||
#define DN_MAXACCL 40
|
||||
#define DN_MAXALIASL 128
|
||||
#define DN_MAXNODEL 256
|
||||
#define DNBUFSIZE 65023
|
||||
|
||||
/*
|
||||
* SET/GET Socket options - must match the DSO_ numbers below
|
||||
*/
|
||||
#define SO_CONDATA 1
|
||||
#define SO_CONACCESS 2
|
||||
#define SO_PROXYUSR 3
|
||||
#define SO_LINKINFO 7
|
||||
|
||||
#define DSO_CONDATA 1 /* Set/Get connect data */
|
||||
#define DSO_DISDATA 10 /* Set/Get disconnect data */
|
||||
#define DSO_CONACCESS 2 /* Set/Get connect access data */
|
||||
#define DSO_ACCEPTMODE 4 /* Set/Get accept mode */
|
||||
#define DSO_CONACCEPT 5 /* Accept deferred connection */
|
||||
#define DSO_CONREJECT 6 /* Reject deferred connection */
|
||||
#define DSO_LINKINFO 7 /* Set/Get link information */
|
||||
#define DSO_STREAM 8 /* Set socket type to stream */
|
||||
#define DSO_SEQPACKET 9 /* Set socket type to sequenced packet */
|
||||
#define DSO_MAXWINDOW 11 /* Maximum window size allowed */
|
||||
#define DSO_NODELAY 12 /* Turn off nagle */
|
||||
#define DSO_CORK 13 /* Wait for more data! */
|
||||
#define DSO_SERVICES 14 /* NSP Services field */
|
||||
#define DSO_INFO 15 /* NSP Info field */
|
||||
#define DSO_MAX 15 /* Maximum option number */
|
||||
|
||||
|
||||
/* LINK States */
|
||||
#define LL_INACTIVE 0
|
||||
#define LL_CONNECTING 1
|
||||
#define LL_RUNNING 2
|
||||
#define LL_DISCONNECTING 3
|
||||
|
||||
#define ACC_IMMED 0
|
||||
#define ACC_DEFER 1
|
||||
|
||||
#define SDF_WILD 1 /* Wild card object */
|
||||
#define SDF_PROXY 2 /* Addr eligible for proxy */
|
||||
#define SDF_UICPROXY 4 /* Use uic-based proxy */
|
||||
|
||||
/* Structures */
|
||||
|
||||
|
||||
struct dn_naddr {
|
||||
__le16 a_len;
|
||||
__u8 a_addr[DN_MAXADDL]; /* Two bytes little endian */
|
||||
};
|
||||
|
||||
struct sockaddr_dn {
|
||||
__u16 sdn_family;
|
||||
__u8 sdn_flags;
|
||||
__u8 sdn_objnum;
|
||||
__le16 sdn_objnamel;
|
||||
__u8 sdn_objname[DN_MAXOBJL];
|
||||
struct dn_naddr sdn_add;
|
||||
};
|
||||
#define sdn_nodeaddrl sdn_add.a_len /* Node address length */
|
||||
#define sdn_nodeaddr sdn_add.a_addr /* Node address */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* DECnet set/get DSO_CONDATA, DSO_DISDATA (optional data) structure
|
||||
*/
|
||||
struct optdata_dn {
|
||||
__le16 opt_status; /* Extended status return */
|
||||
#define opt_sts opt_status
|
||||
__le16 opt_optl; /* Length of user data */
|
||||
__u8 opt_data[16]; /* User data */
|
||||
};
|
||||
|
||||
struct accessdata_dn {
|
||||
__u8 acc_accl;
|
||||
__u8 acc_acc[DN_MAXACCL];
|
||||
__u8 acc_passl;
|
||||
__u8 acc_pass[DN_MAXACCL];
|
||||
__u8 acc_userl;
|
||||
__u8 acc_user[DN_MAXACCL];
|
||||
};
|
||||
|
||||
/*
|
||||
* DECnet logical link information structure
|
||||
*/
|
||||
struct linkinfo_dn {
|
||||
__u16 idn_segsize; /* Segment size for link */
|
||||
__u8 idn_linkstate; /* Logical link state */
|
||||
};
|
||||
|
||||
/*
|
||||
* Ethernet address format (for DECnet)
|
||||
*/
|
||||
union etheraddress {
|
||||
__u8 dne_addr[ETH_ALEN]; /* Full ethernet address */
|
||||
struct {
|
||||
__u8 dne_hiord[4]; /* DECnet HIORD prefix */
|
||||
__u8 dne_nodeaddr[2]; /* DECnet node address */
|
||||
} dne_remote;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* DECnet physical socket address format
|
||||
*/
|
||||
struct dn_addr {
|
||||
__le16 dna_family; /* AF_DECnet */
|
||||
union etheraddress dna_netaddr; /* DECnet ethernet address */
|
||||
};
|
||||
|
||||
#define DECNET_IOCTL_BASE 0x89 /* PROTOPRIVATE range */
|
||||
|
||||
#define SIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, struct dn_naddr)
|
||||
#define SIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, struct dn_naddr)
|
||||
#define OSIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, int)
|
||||
#define OSIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, int)
|
||||
|
||||
#endif /* _LINUX_DN_H */
|
@ -1,72 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef __LINUX_DECNET_NETFILTER_H
|
||||
#define __LINUX_DECNET_NETFILTER_H
|
||||
|
||||
/* DECnet-specific defines for netfilter.
|
||||
* This file (C) Steve Whitehouse 1999 derived from the
|
||||
* ipv4 netfilter header file which is
|
||||
* (C)1998 Rusty Russell -- This code is GPL.
|
||||
*/
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
/* only for userspace compatibility */
|
||||
#ifndef __KERNEL__
|
||||
|
||||
#include <limits.h> /* for INT_MIN, INT_MAX */
|
||||
|
||||
/* kernel define is in netfilter_defs.h */
|
||||
#define NF_DN_NUMHOOKS 7
|
||||
#endif /* ! __KERNEL__ */
|
||||
|
||||
/* DECnet Hooks */
|
||||
/* After promisc drops, checksum checks. */
|
||||
#define NF_DN_PRE_ROUTING 0
|
||||
/* If the packet is destined for this box. */
|
||||
#define NF_DN_LOCAL_IN 1
|
||||
/* If the packet is destined for another interface. */
|
||||
#define NF_DN_FORWARD 2
|
||||
/* Packets coming from a local process. */
|
||||
#define NF_DN_LOCAL_OUT 3
|
||||
/* Packets about to hit the wire. */
|
||||
#define NF_DN_POST_ROUTING 4
|
||||
/* Input Hello Packets */
|
||||
#define NF_DN_HELLO 5
|
||||
/* Input Routing Packets */
|
||||
#define NF_DN_ROUTE 6
|
||||
|
||||
enum nf_dn_hook_priorities {
|
||||
NF_DN_PRI_FIRST = INT_MIN,
|
||||
NF_DN_PRI_CONNTRACK = -200,
|
||||
NF_DN_PRI_MANGLE = -150,
|
||||
NF_DN_PRI_NAT_DST = -100,
|
||||
NF_DN_PRI_FILTER = 0,
|
||||
NF_DN_PRI_NAT_SRC = 100,
|
||||
NF_DN_PRI_DNRTMSG = 200,
|
||||
NF_DN_PRI_LAST = INT_MAX,
|
||||
};
|
||||
|
||||
struct nf_dn_rtmsg {
|
||||
int nfdn_ifindex;
|
||||
};
|
||||
|
||||
#define NFDN_RTMSG(r) ((unsigned char *)(r) + NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg)))
|
||||
|
||||
#ifndef __KERNEL__
|
||||
/* backwards compatibility for userspace */
|
||||
#define DNRMG_L1_GROUP 0x01
|
||||
#define DNRMG_L2_GROUP 0x02
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DNRNG_NLGRP_NONE,
|
||||
#define DNRNG_NLGRP_NONE DNRNG_NLGRP_NONE
|
||||
DNRNG_NLGRP_L1,
|
||||
#define DNRNG_NLGRP_L1 DNRNG_NLGRP_L1
|
||||
DNRNG_NLGRP_L2,
|
||||
#define DNRNG_NLGRP_L2 DNRNG_NLGRP_L2
|
||||
__DNRNG_NLGRP_MAX
|
||||
};
|
||||
#define DNRNG_NLGRP_MAX (__DNRNG_NLGRP_MAX - 1)
|
||||
|
||||
#endif /*__LINUX_DECNET_NETFILTER_H*/
|
@ -20,7 +20,7 @@
|
||||
#define NETLINK_CONNECTOR 11
|
||||
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
|
||||
#define NETLINK_IP6_FW 13
|
||||
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
|
||||
#define NETLINK_DNRTMSG 14 /* DECnet routing messages (obsolete) */
|
||||
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
|
||||
#define NETLINK_GENERIC 16
|
||||
/* leave room for NETLINK_DM (DM Events) */
|
||||
|
@ -901,10 +901,22 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
|
||||
}
|
||||
|
||||
offset = ALIGN(offset, align);
|
||||
|
||||
/*
|
||||
* Check if the segment contains the entry point, if so,
|
||||
* calculate the value of image->start based on it.
|
||||
* If the compiler has produced more than one .text section
|
||||
* (Eg: .text.hot), they are generally after the main .text
|
||||
* section, and they shall not be used to calculate
|
||||
* image->start. So do not re-calculate image->start if it
|
||||
* is not set to the initial value, and warn the user so they
|
||||
* have a chance to fix their purgatory's linker script.
|
||||
*/
|
||||
if (sechdrs[i].sh_flags & SHF_EXECINSTR &&
|
||||
pi->ehdr->e_entry >= sechdrs[i].sh_addr &&
|
||||
pi->ehdr->e_entry < (sechdrs[i].sh_addr
|
||||
+ sechdrs[i].sh_size)) {
|
||||
+ sechdrs[i].sh_size) &&
|
||||
!WARN_ON(kbuf->image->start != pi->ehdr->e_entry)) {
|
||||
kbuf->image->start -= sechdrs[i].sh_addr;
|
||||
kbuf->image->start += kbuf->mem + offset;
|
||||
}
|
||||
|
@ -679,6 +679,11 @@ static ssize_t trigger_batched_requests_store(struct device *dev,
|
||||
|
||||
mutex_lock(&test_fw_mutex);
|
||||
|
||||
if (test_fw_config->reqs) {
|
||||
rc = -EBUSY;
|
||||
goto out_bail;
|
||||
}
|
||||
|
||||
test_fw_config->reqs =
|
||||
vzalloc(array3_size(sizeof(struct test_batched_req),
|
||||
test_fw_config->num_requests, 2));
|
||||
@ -778,6 +783,11 @@ ssize_t trigger_batched_requests_async_store(struct device *dev,
|
||||
|
||||
mutex_lock(&test_fw_mutex);
|
||||
|
||||
if (test_fw_config->reqs) {
|
||||
rc = -EBUSY;
|
||||
goto out_bail;
|
||||
}
|
||||
|
||||
test_fw_config->reqs =
|
||||
vzalloc(array3_size(sizeof(struct test_batched_req),
|
||||
test_fw_config->num_requests, 2));
|
||||
|
@ -202,7 +202,6 @@ config BRIDGE_NETFILTER
|
||||
source "net/netfilter/Kconfig"
|
||||
source "net/ipv4/netfilter/Kconfig"
|
||||
source "net/ipv6/netfilter/Kconfig"
|
||||
source "net/decnet/netfilter/Kconfig"
|
||||
source "net/bridge/netfilter/Kconfig"
|
||||
|
||||
endif
|
||||
@ -219,7 +218,6 @@ source "net/802/Kconfig"
|
||||
source "net/bridge/Kconfig"
|
||||
source "net/dsa/Kconfig"
|
||||
source "net/8021q/Kconfig"
|
||||
source "net/decnet/Kconfig"
|
||||
source "net/llc/Kconfig"
|
||||
source "drivers/net/appletalk/Kconfig"
|
||||
source "net/x25/Kconfig"
|
||||
|
@ -39,7 +39,6 @@ obj-$(CONFIG_AF_KCM) += kcm/
|
||||
obj-$(CONFIG_STREAM_PARSER) += strparser/
|
||||
obj-$(CONFIG_ATM) += atm/
|
||||
obj-$(CONFIG_L2TP) += l2tp/
|
||||
obj-$(CONFIG_DECNET) += decnet/
|
||||
obj-$(CONFIG_PHONET) += phonet/
|
||||
ifneq ($(CONFIG_VLAN_8021Q),)
|
||||
obj-y += 8021q/
|
||||
|
@ -9445,9 +9445,7 @@ void netdev_run_todo(void)
|
||||
BUG_ON(!list_empty(&dev->ptype_specific));
|
||||
WARN_ON(rcu_access_pointer(dev->ip_ptr));
|
||||
WARN_ON(rcu_access_pointer(dev->ip6_ptr));
|
||||
#if IS_ENABLED(CONFIG_DECNET)
|
||||
WARN_ON(dev->dn_ptr);
|
||||
#endif
|
||||
|
||||
if (dev->priv_destructor)
|
||||
dev->priv_destructor(dev);
|
||||
if (dev->needs_free_netdev)
|
||||
|
@ -569,37 +569,6 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_lookup);
|
||||
|
||||
struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
|
||||
const void *pkey)
|
||||
{
|
||||
struct neighbour *n;
|
||||
unsigned int key_len = tbl->key_len;
|
||||
u32 hash_val;
|
||||
struct neigh_hash_table *nht;
|
||||
|
||||
NEIGH_CACHE_STAT_INC(tbl, lookups);
|
||||
|
||||
rcu_read_lock_bh();
|
||||
nht = rcu_dereference_bh(tbl->nht);
|
||||
hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
|
||||
|
||||
for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
|
||||
n != NULL;
|
||||
n = rcu_dereference_bh(n->next)) {
|
||||
if (!memcmp(n->primary_key, pkey, key_len) &&
|
||||
net_eq(dev_net(n->dev), net)) {
|
||||
if (!refcount_inc_not_zero(&n->refcnt))
|
||||
n = NULL;
|
||||
NEIGH_CACHE_STAT_INC(tbl, hits);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock_bh();
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_lookup_nodev);
|
||||
|
||||
static struct neighbour *
|
||||
___neigh_create(struct neigh_table *tbl, const void *pkey,
|
||||
struct net_device *dev, u8 flags,
|
||||
@ -1798,9 +1767,6 @@ static struct neigh_table *neigh_find_table(int family)
|
||||
case AF_INET6:
|
||||
tbl = neigh_tables[NEIGH_ND_TABLE];
|
||||
break;
|
||||
case AF_DECnet:
|
||||
tbl = neigh_tables[NEIGH_DN_TABLE];
|
||||
break;
|
||||
}
|
||||
|
||||
return tbl;
|
||||
|
@ -1,43 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# DECnet configuration
|
||||
#
|
||||
config DECNET
|
||||
tristate "DECnet Support"
|
||||
---help---
|
||||
The DECnet networking protocol was used in many products made by
|
||||
Digital (now Compaq). It provides reliable stream and sequenced
|
||||
packet communications over which run a variety of services similar
|
||||
to those which run over TCP/IP.
|
||||
|
||||
To find some tools to use with the kernel layer support, please
|
||||
look at Patrick Caulfield's web site:
|
||||
<http://linux-decnet.sourceforge.net/>.
|
||||
|
||||
More detailed documentation is available in
|
||||
<file:Documentation/networking/decnet.txt>.
|
||||
|
||||
Be sure to say Y to "/proc file system support" and "Sysctl support"
|
||||
below when using DECnet, since you will need sysctl support to aid
|
||||
in configuration at run time.
|
||||
|
||||
The DECnet code 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 decnet.
|
||||
|
||||
config DECNET_ROUTER
|
||||
bool "DECnet: router support"
|
||||
depends on DECNET
|
||||
select FIB_RULES
|
||||
---help---
|
||||
Add support for turning your DECnet Endnode into a level 1 or 2
|
||||
router. This is an experimental, but functional option. If you
|
||||
do say Y here, then make sure that you also say Y to "Kernel/User
|
||||
network link driver", "Routing messages" and "Network packet
|
||||
filtering". The first two are required to allow configuration via
|
||||
rtnetlink (you will need Alexey Kuznetsov's iproute2 package
|
||||
from <ftp://ftp.tux.org/pub/net/ip-routing/>). The "Network packet
|
||||
filtering" option will be required for the forthcoming routing daemon
|
||||
to work.
|
||||
|
||||
See <file:Documentation/networking/decnet.txt> for more information.
|
@ -1,10 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_DECNET) += decnet.o
|
||||
|
||||
decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o \
|
||||
dn_route.o dn_dev.o dn_neigh.o dn_timer.o
|
||||
decnet-$(CONFIG_DECNET_ROUTER) += dn_fib.o dn_rules.o dn_table.o
|
||||
decnet-y += sysctl_net_decnet.o
|
||||
|
||||
obj-$(CONFIG_NETFILTER) += netfilter/
|
@ -1,8 +0,0 @@
|
||||
Linux DECnet Project
|
||||
======================
|
||||
|
||||
The documentation for this kernel subsystem is available in the
|
||||
Documentation/networking subdirectory of this distribution and also
|
||||
on line at http://www.chygwyn.com/DECnet/
|
||||
|
||||
Steve Whitehouse <SteveW@ACM.org>
|
File diff suppressed because it is too large
Load Diff
1438
net/decnet/dn_dev.c
1438
net/decnet/dn_dev.c
File diff suppressed because it is too large
Load Diff
@ -1,799 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DECnet An implementation of the DECnet protocol suite for the LINUX
|
||||
* operating system. DECnet is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DECnet Routing Forwarding Information Base (Glue/Info List)
|
||||
*
|
||||
* Author: Steve Whitehouse <SteveW@ACM.org>
|
||||
*
|
||||
*
|
||||
* Changes:
|
||||
* Alexey Kuznetsov : SMP locking changes
|
||||
* Steve Whitehouse : Rewrote it... Well to be more correct, I
|
||||
* copied most of it from the ipv4 fib code.
|
||||
* Steve Whitehouse : Updated it in style and fixed a few bugs
|
||||
* which were fixed in the ipv4 code since
|
||||
* this code was copied from it.
|
||||
*
|
||||
*/
|
||||
#include <linux/string.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/fib_rules.h>
|
||||
#include <net/dn.h>
|
||||
#include <net/dn_route.h>
|
||||
#include <net/dn_fib.h>
|
||||
#include <net/dn_neigh.h>
|
||||
#include <net/dn_dev.h>
|
||||
#include <net/rtnh.h>
|
||||
|
||||
#define RT_MIN_TABLE 1
|
||||
|
||||
#define for_fib_info() { struct dn_fib_info *fi;\
|
||||
for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
|
||||
#define endfor_fib_info() }
|
||||
|
||||
#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
|
||||
for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
|
||||
|
||||
#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\
|
||||
for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
|
||||
|
||||
#define endfor_nexthops(fi) }
|
||||
|
||||
static DEFINE_SPINLOCK(dn_fib_multipath_lock);
|
||||
static struct dn_fib_info *dn_fib_info_list;
|
||||
static DEFINE_SPINLOCK(dn_fib_info_lock);
|
||||
|
||||
static struct
|
||||
{
|
||||
int error;
|
||||
u8 scope;
|
||||
} dn_fib_props[RTN_MAX+1] = {
|
||||
[RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
|
||||
[RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE },
|
||||
[RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST },
|
||||
[RTN_BROADCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
|
||||
[RTN_ANYCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
|
||||
[RTN_MULTICAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
|
||||
[RTN_BLACKHOLE] = { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
|
||||
[RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
|
||||
[RTN_PROHIBIT] = { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
|
||||
[RTN_THROW] = { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
|
||||
[RTN_NAT] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
|
||||
[RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
|
||||
};
|
||||
|
||||
static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
|
||||
static int dn_fib_sync_up(struct net_device *dev);
|
||||
|
||||
void dn_fib_free_info(struct dn_fib_info *fi)
|
||||
{
|
||||
if (fi->fib_dead == 0) {
|
||||
printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
change_nexthops(fi) {
|
||||
if (nh->nh_dev)
|
||||
dev_put(nh->nh_dev);
|
||||
nh->nh_dev = NULL;
|
||||
} endfor_nexthops(fi);
|
||||
kfree(fi);
|
||||
}
|
||||
|
||||
void dn_fib_release_info(struct dn_fib_info *fi)
|
||||
{
|
||||
spin_lock(&dn_fib_info_lock);
|
||||
if (fi && --fi->fib_treeref == 0) {
|
||||
if (fi->fib_next)
|
||||
fi->fib_next->fib_prev = fi->fib_prev;
|
||||
if (fi->fib_prev)
|
||||
fi->fib_prev->fib_next = fi->fib_next;
|
||||
if (fi == dn_fib_info_list)
|
||||
dn_fib_info_list = fi->fib_next;
|
||||
fi->fib_dead = 1;
|
||||
dn_fib_info_put(fi);
|
||||
}
|
||||
spin_unlock(&dn_fib_info_lock);
|
||||
}
|
||||
|
||||
static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
|
||||
{
|
||||
const struct dn_fib_nh *onh = ofi->fib_nh;
|
||||
|
||||
for_nexthops(fi) {
|
||||
if (nh->nh_oif != onh->nh_oif ||
|
||||
nh->nh_gw != onh->nh_gw ||
|
||||
nh->nh_scope != onh->nh_scope ||
|
||||
nh->nh_weight != onh->nh_weight ||
|
||||
((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
|
||||
return -1;
|
||||
onh++;
|
||||
} endfor_nexthops(fi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
|
||||
{
|
||||
for_fib_info() {
|
||||
if (fi->fib_nhs != nfi->fib_nhs)
|
||||
continue;
|
||||
if (nfi->fib_protocol == fi->fib_protocol &&
|
||||
nfi->fib_prefsrc == fi->fib_prefsrc &&
|
||||
nfi->fib_priority == fi->fib_priority &&
|
||||
memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
|
||||
((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
|
||||
(nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
|
||||
return fi;
|
||||
} endfor_fib_info();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dn_fib_count_nhs(const struct nlattr *attr)
|
||||
{
|
||||
struct rtnexthop *nhp = nla_data(attr);
|
||||
int nhs = 0, nhlen = nla_len(attr);
|
||||
|
||||
while (rtnh_ok(nhp, nhlen)) {
|
||||
nhs++;
|
||||
nhp = rtnh_next(nhp, &nhlen);
|
||||
}
|
||||
|
||||
/* leftover implies invalid nexthop configuration, discard it */
|
||||
return nhlen > 0 ? 0 : nhs;
|
||||
}
|
||||
|
||||
static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
|
||||
const struct rtmsg *r)
|
||||
{
|
||||
struct rtnexthop *nhp = nla_data(attr);
|
||||
int nhlen = nla_len(attr);
|
||||
|
||||
change_nexthops(fi) {
|
||||
int attrlen;
|
||||
|
||||
if (!rtnh_ok(nhp, nhlen))
|
||||
return -EINVAL;
|
||||
|
||||
nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
|
||||
nh->nh_oif = nhp->rtnh_ifindex;
|
||||
nh->nh_weight = nhp->rtnh_hops + 1;
|
||||
|
||||
attrlen = rtnh_attrlen(nhp);
|
||||
if (attrlen > 0) {
|
||||
struct nlattr *gw_attr;
|
||||
|
||||
gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
|
||||
nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
|
||||
}
|
||||
|
||||
nhp = rtnh_next(nhp, &nhlen);
|
||||
} endfor_nexthops(fi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (nh->nh_gw) {
|
||||
struct flowidn fld;
|
||||
struct dn_fib_res res;
|
||||
|
||||
if (nh->nh_flags&RTNH_F_ONLINK) {
|
||||
struct net_device *dev;
|
||||
|
||||
if (r->rtm_scope >= RT_SCOPE_LINK)
|
||||
return -EINVAL;
|
||||
if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
|
||||
return -EINVAL;
|
||||
if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL)
|
||||
return -ENODEV;
|
||||
if (!(dev->flags&IFF_UP))
|
||||
return -ENETDOWN;
|
||||
nh->nh_dev = dev;
|
||||
dev_hold(dev);
|
||||
nh->nh_scope = RT_SCOPE_LINK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&fld, 0, sizeof(fld));
|
||||
fld.daddr = nh->nh_gw;
|
||||
fld.flowidn_oif = nh->nh_oif;
|
||||
fld.flowidn_scope = r->rtm_scope + 1;
|
||||
|
||||
if (fld.flowidn_scope < RT_SCOPE_LINK)
|
||||
fld.flowidn_scope = RT_SCOPE_LINK;
|
||||
|
||||
if ((err = dn_fib_lookup(&fld, &res)) != 0)
|
||||
return err;
|
||||
|
||||
err = -EINVAL;
|
||||
if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
|
||||
goto out;
|
||||
nh->nh_scope = res.scope;
|
||||
nh->nh_oif = DN_FIB_RES_OIF(res);
|
||||
nh->nh_dev = DN_FIB_RES_DEV(res);
|
||||
if (nh->nh_dev == NULL)
|
||||
goto out;
|
||||
dev_hold(nh->nh_dev);
|
||||
err = -ENETDOWN;
|
||||
if (!(nh->nh_dev->flags & IFF_UP))
|
||||
goto out;
|
||||
err = 0;
|
||||
out:
|
||||
dn_fib_res_put(&res);
|
||||
return err;
|
||||
} else {
|
||||
struct net_device *dev;
|
||||
|
||||
if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
|
||||
return -EINVAL;
|
||||
|
||||
dev = __dev_get_by_index(&init_net, nh->nh_oif);
|
||||
if (dev == NULL || dev->dn_ptr == NULL)
|
||||
return -ENODEV;
|
||||
if (!(dev->flags&IFF_UP))
|
||||
return -ENETDOWN;
|
||||
nh->nh_dev = dev;
|
||||
dev_hold(nh->nh_dev);
|
||||
nh->nh_scope = RT_SCOPE_HOST;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
|
||||
const struct nlmsghdr *nlh, int *errp)
|
||||
{
|
||||
int err;
|
||||
struct dn_fib_info *fi = NULL;
|
||||
struct dn_fib_info *ofi;
|
||||
int nhs = 1;
|
||||
|
||||
if (r->rtm_type > RTN_MAX)
|
||||
goto err_inval;
|
||||
|
||||
if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
|
||||
goto err_inval;
|
||||
|
||||
if (attrs[RTA_MULTIPATH] &&
|
||||
(nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
|
||||
goto err_inval;
|
||||
|
||||
fi = kzalloc(struct_size(fi, fib_nh, nhs), GFP_KERNEL);
|
||||
err = -ENOBUFS;
|
||||
if (fi == NULL)
|
||||
goto failure;
|
||||
|
||||
fi->fib_protocol = r->rtm_protocol;
|
||||
fi->fib_nhs = nhs;
|
||||
fi->fib_flags = r->rtm_flags;
|
||||
|
||||
if (attrs[RTA_PRIORITY])
|
||||
fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
|
||||
|
||||
if (attrs[RTA_METRICS]) {
|
||||
struct nlattr *attr;
|
||||
int rem;
|
||||
|
||||
nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
|
||||
int type = nla_type(attr);
|
||||
|
||||
if (type) {
|
||||
if (type > RTAX_MAX || type == RTAX_CC_ALGO ||
|
||||
nla_len(attr) < 4)
|
||||
goto err_inval;
|
||||
|
||||
fi->fib_metrics[type-1] = nla_get_u32(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs[RTA_PREFSRC])
|
||||
fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
|
||||
|
||||
if (attrs[RTA_MULTIPATH]) {
|
||||
if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
|
||||
goto failure;
|
||||
|
||||
if (attrs[RTA_OIF] &&
|
||||
fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
|
||||
goto err_inval;
|
||||
|
||||
if (attrs[RTA_GATEWAY] &&
|
||||
fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
|
||||
goto err_inval;
|
||||
} else {
|
||||
struct dn_fib_nh *nh = fi->fib_nh;
|
||||
|
||||
if (attrs[RTA_OIF])
|
||||
nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
|
||||
|
||||
if (attrs[RTA_GATEWAY])
|
||||
nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
|
||||
|
||||
nh->nh_flags = r->rtm_flags;
|
||||
nh->nh_weight = 1;
|
||||
}
|
||||
|
||||
if (r->rtm_type == RTN_NAT) {
|
||||
if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
|
||||
goto err_inval;
|
||||
|
||||
fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
|
||||
goto link_it;
|
||||
}
|
||||
|
||||
if (dn_fib_props[r->rtm_type].error) {
|
||||
if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
|
||||
goto err_inval;
|
||||
|
||||
goto link_it;
|
||||
}
|
||||
|
||||
if (r->rtm_scope > RT_SCOPE_HOST)
|
||||
goto err_inval;
|
||||
|
||||
if (r->rtm_scope == RT_SCOPE_HOST) {
|
||||
struct dn_fib_nh *nh = fi->fib_nh;
|
||||
|
||||
/* Local address is added */
|
||||
if (nhs != 1 || nh->nh_gw)
|
||||
goto err_inval;
|
||||
nh->nh_scope = RT_SCOPE_NOWHERE;
|
||||
nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif);
|
||||
err = -ENODEV;
|
||||
if (nh->nh_dev == NULL)
|
||||
goto failure;
|
||||
} else {
|
||||
change_nexthops(fi) {
|
||||
if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
|
||||
goto failure;
|
||||
} endfor_nexthops(fi)
|
||||
}
|
||||
|
||||
if (fi->fib_prefsrc) {
|
||||
if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
|
||||
fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
|
||||
if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
|
||||
goto err_inval;
|
||||
}
|
||||
|
||||
link_it:
|
||||
if ((ofi = dn_fib_find_info(fi)) != NULL) {
|
||||
fi->fib_dead = 1;
|
||||
dn_fib_free_info(fi);
|
||||
ofi->fib_treeref++;
|
||||
return ofi;
|
||||
}
|
||||
|
||||
fi->fib_treeref++;
|
||||
refcount_set(&fi->fib_clntref, 1);
|
||||
spin_lock(&dn_fib_info_lock);
|
||||
fi->fib_next = dn_fib_info_list;
|
||||
fi->fib_prev = NULL;
|
||||
if (dn_fib_info_list)
|
||||
dn_fib_info_list->fib_prev = fi;
|
||||
dn_fib_info_list = fi;
|
||||
spin_unlock(&dn_fib_info_lock);
|
||||
return fi;
|
||||
|
||||
err_inval:
|
||||
err = -EINVAL;
|
||||
|
||||
failure:
|
||||
*errp = err;
|
||||
if (fi) {
|
||||
fi->fib_dead = 1;
|
||||
dn_fib_free_info(fi);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn *fld, struct dn_fib_res *res)
|
||||
{
|
||||
int err = dn_fib_props[type].error;
|
||||
|
||||
if (err == 0) {
|
||||
if (fi->fib_flags & RTNH_F_DEAD)
|
||||
return 1;
|
||||
|
||||
res->fi = fi;
|
||||
|
||||
switch (type) {
|
||||
case RTN_NAT:
|
||||
DN_FIB_RES_RESET(*res);
|
||||
refcount_inc(&fi->fib_clntref);
|
||||
return 0;
|
||||
case RTN_UNICAST:
|
||||
case RTN_LOCAL:
|
||||
for_nexthops(fi) {
|
||||
if (nh->nh_flags & RTNH_F_DEAD)
|
||||
continue;
|
||||
if (!fld->flowidn_oif ||
|
||||
fld->flowidn_oif == nh->nh_oif)
|
||||
break;
|
||||
}
|
||||
if (nhsel < fi->fib_nhs) {
|
||||
res->nh_sel = nhsel;
|
||||
refcount_inc(&fi->fib_clntref);
|
||||
return 0;
|
||||
}
|
||||
endfor_nexthops(fi);
|
||||
res->fi = NULL;
|
||||
return 1;
|
||||
default:
|
||||
net_err_ratelimited("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n",
|
||||
type);
|
||||
res->fi = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
|
||||
{
|
||||
struct dn_fib_info *fi = res->fi;
|
||||
int w;
|
||||
|
||||
spin_lock_bh(&dn_fib_multipath_lock);
|
||||
if (fi->fib_power <= 0) {
|
||||
int power = 0;
|
||||
change_nexthops(fi) {
|
||||
if (!(nh->nh_flags&RTNH_F_DEAD)) {
|
||||
power += nh->nh_weight;
|
||||
nh->nh_power = nh->nh_weight;
|
||||
}
|
||||
} endfor_nexthops(fi);
|
||||
fi->fib_power = power;
|
||||
if (power < 0) {
|
||||
spin_unlock_bh(&dn_fib_multipath_lock);
|
||||
res->nh_sel = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
w = jiffies % fi->fib_power;
|
||||
|
||||
change_nexthops(fi) {
|
||||
if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
|
||||
if ((w -= nh->nh_power) <= 0) {
|
||||
nh->nh_power--;
|
||||
fi->fib_power--;
|
||||
res->nh_sel = nhsel;
|
||||
spin_unlock_bh(&dn_fib_multipath_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} endfor_nexthops(fi);
|
||||
res->nh_sel = 0;
|
||||
spin_unlock_bh(&dn_fib_multipath_lock);
|
||||
}
|
||||
|
||||
static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
|
||||
{
|
||||
if (attrs[RTA_TABLE])
|
||||
table = nla_get_u32(attrs[RTA_TABLE]);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct dn_fib_table *tb;
|
||||
struct rtmsg *r = nlmsg_data(nlh);
|
||||
struct nlattr *attrs[RTA_MAX+1];
|
||||
int err;
|
||||
|
||||
if (!netlink_capable(skb, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (!net_eq(net, &init_net))
|
||||
return -EINVAL;
|
||||
|
||||
err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
|
||||
rtm_dn_policy, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
|
||||
if (!tb)
|
||||
return -ESRCH;
|
||||
|
||||
return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
|
||||
}
|
||||
|
||||
static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct dn_fib_table *tb;
|
||||
struct rtmsg *r = nlmsg_data(nlh);
|
||||
struct nlattr *attrs[RTA_MAX+1];
|
||||
int err;
|
||||
|
||||
if (!netlink_capable(skb, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (!net_eq(net, &init_net))
|
||||
return -EINVAL;
|
||||
|
||||
err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
|
||||
rtm_dn_policy, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
|
||||
if (!tb)
|
||||
return -ENOBUFS;
|
||||
|
||||
return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
|
||||
}
|
||||
|
||||
static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
|
||||
{
|
||||
struct dn_fib_table *tb;
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtmsg rtm;
|
||||
} req;
|
||||
struct {
|
||||
struct nlattr hdr;
|
||||
__le16 dst;
|
||||
} dst_attr = {
|
||||
.dst = dst,
|
||||
};
|
||||
struct {
|
||||
struct nlattr hdr;
|
||||
__le16 prefsrc;
|
||||
} prefsrc_attr = {
|
||||
.prefsrc = ifa->ifa_local,
|
||||
};
|
||||
struct {
|
||||
struct nlattr hdr;
|
||||
u32 oif;
|
||||
} oif_attr = {
|
||||
.oif = ifa->ifa_dev->dev->ifindex,
|
||||
};
|
||||
struct nlattr *attrs[RTA_MAX+1] = {
|
||||
[RTA_DST] = (struct nlattr *) &dst_attr,
|
||||
[RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
|
||||
[RTA_OIF] = (struct nlattr *) &oif_attr,
|
||||
};
|
||||
|
||||
memset(&req.rtm, 0, sizeof(req.rtm));
|
||||
|
||||
if (type == RTN_UNICAST)
|
||||
tb = dn_fib_get_table(RT_MIN_TABLE, 1);
|
||||
else
|
||||
tb = dn_fib_get_table(RT_TABLE_LOCAL, 1);
|
||||
|
||||
if (tb == NULL)
|
||||
return;
|
||||
|
||||
req.nlh.nlmsg_len = sizeof(req);
|
||||
req.nlh.nlmsg_type = cmd;
|
||||
req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
|
||||
req.nlh.nlmsg_pid = 0;
|
||||
req.nlh.nlmsg_seq = 0;
|
||||
|
||||
req.rtm.rtm_dst_len = dst_len;
|
||||
req.rtm.rtm_table = tb->n;
|
||||
req.rtm.rtm_protocol = RTPROT_KERNEL;
|
||||
req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
|
||||
req.rtm.rtm_type = type;
|
||||
|
||||
if (cmd == RTM_NEWROUTE)
|
||||
tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
|
||||
else
|
||||
tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
|
||||
}
|
||||
|
||||
static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
|
||||
{
|
||||
|
||||
fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
|
||||
|
||||
#if 0
|
||||
if (!(dev->flags&IFF_UP))
|
||||
return;
|
||||
/* In the future, we will want to add default routes here */
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
|
||||
{
|
||||
int found_it = 0;
|
||||
struct net_device *dev;
|
||||
struct dn_dev *dn_db;
|
||||
struct dn_ifaddr *ifa2;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
/* Scan device list */
|
||||
rcu_read_lock();
|
||||
for_each_netdev_rcu(&init_net, dev) {
|
||||
dn_db = rcu_dereference(dev->dn_ptr);
|
||||
if (dn_db == NULL)
|
||||
continue;
|
||||
for (ifa2 = rcu_dereference(dn_db->ifa_list);
|
||||
ifa2 != NULL;
|
||||
ifa2 = rcu_dereference(ifa2->ifa_next)) {
|
||||
if (ifa2->ifa_local == ifa->ifa_local) {
|
||||
found_it = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (found_it == 0) {
|
||||
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
|
||||
|
||||
if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
|
||||
if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))
|
||||
dn_fib_flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dn_fib_disable_addr(struct net_device *dev, int force)
|
||||
{
|
||||
if (dn_fib_sync_down(0, dev, force))
|
||||
dn_fib_flush();
|
||||
dn_rt_cache_flush(0);
|
||||
neigh_ifdown(&dn_neigh_table, dev);
|
||||
}
|
||||
|
||||
static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
{
|
||||
struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UP:
|
||||
dn_fib_add_ifaddr(ifa);
|
||||
dn_fib_sync_up(ifa->ifa_dev->dev);
|
||||
dn_rt_cache_flush(-1);
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
dn_fib_del_ifaddr(ifa);
|
||||
if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
|
||||
dn_fib_disable_addr(ifa->ifa_dev->dev, 1);
|
||||
} else {
|
||||
dn_rt_cache_flush(-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
|
||||
{
|
||||
int ret = 0;
|
||||
int scope = RT_SCOPE_NOWHERE;
|
||||
|
||||
if (force)
|
||||
scope = -1;
|
||||
|
||||
for_fib_info() {
|
||||
/*
|
||||
* This makes no sense for DECnet.... we will almost
|
||||
* certainly have more than one local address the same
|
||||
* over all our interfaces. It needs thinking about
|
||||
* some more.
|
||||
*/
|
||||
if (local && fi->fib_prefsrc == local) {
|
||||
fi->fib_flags |= RTNH_F_DEAD;
|
||||
ret++;
|
||||
} else if (dev && fi->fib_nhs) {
|
||||
int dead = 0;
|
||||
|
||||
change_nexthops(fi) {
|
||||
if (nh->nh_flags&RTNH_F_DEAD)
|
||||
dead++;
|
||||
else if (nh->nh_dev == dev &&
|
||||
nh->nh_scope != scope) {
|
||||
spin_lock_bh(&dn_fib_multipath_lock);
|
||||
nh->nh_flags |= RTNH_F_DEAD;
|
||||
fi->fib_power -= nh->nh_power;
|
||||
nh->nh_power = 0;
|
||||
spin_unlock_bh(&dn_fib_multipath_lock);
|
||||
dead++;
|
||||
}
|
||||
} endfor_nexthops(fi)
|
||||
if (dead == fi->fib_nhs) {
|
||||
fi->fib_flags |= RTNH_F_DEAD;
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
} endfor_fib_info();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int dn_fib_sync_up(struct net_device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!(dev->flags&IFF_UP))
|
||||
return 0;
|
||||
|
||||
for_fib_info() {
|
||||
int alive = 0;
|
||||
|
||||
change_nexthops(fi) {
|
||||
if (!(nh->nh_flags&RTNH_F_DEAD)) {
|
||||
alive++;
|
||||
continue;
|
||||
}
|
||||
if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
|
||||
continue;
|
||||
if (nh->nh_dev != dev || dev->dn_ptr == NULL)
|
||||
continue;
|
||||
alive++;
|
||||
spin_lock_bh(&dn_fib_multipath_lock);
|
||||
nh->nh_power = 0;
|
||||
nh->nh_flags &= ~RTNH_F_DEAD;
|
||||
spin_unlock_bh(&dn_fib_multipath_lock);
|
||||
} endfor_nexthops(fi);
|
||||
|
||||
if (alive > 0) {
|
||||
fi->fib_flags &= ~RTNH_F_DEAD;
|
||||
ret++;
|
||||
}
|
||||
} endfor_fib_info();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct notifier_block dn_fib_dnaddr_notifier = {
|
||||
.notifier_call = dn_fib_dnaddr_event,
|
||||
};
|
||||
|
||||
void __exit dn_fib_cleanup(void)
|
||||
{
|
||||
dn_fib_table_cleanup();
|
||||
dn_fib_rules_cleanup();
|
||||
|
||||
unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);
|
||||
}
|
||||
|
||||
|
||||
void __init dn_fib_init(void)
|
||||
{
|
||||
dn_fib_table_init();
|
||||
dn_fib_rules_init();
|
||||
|
||||
register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
|
||||
|
||||
rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_NEWROUTE,
|
||||
dn_fib_rtm_newroute, NULL, 0);
|
||||
rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_DELROUTE,
|
||||
dn_fib_rtm_delroute, NULL, 0);
|
||||
}
|
@ -1,605 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DECnet An implementation of the DECnet protocol suite for the LINUX
|
||||
* operating system. DECnet is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DECnet Neighbour Functions (Adjacency Database and
|
||||
* On-Ethernet Cache)
|
||||
*
|
||||
* Author: Steve Whitehouse <SteveW@ACM.org>
|
||||
*
|
||||
*
|
||||
* Changes:
|
||||
* Steve Whitehouse : Fixed router listing routine
|
||||
* Steve Whitehouse : Added error_report functions
|
||||
* Steve Whitehouse : Added default router detection
|
||||
* Steve Whitehouse : Hop counts in outgoing messages
|
||||
* Steve Whitehouse : Fixed src/dst in outgoing messages so
|
||||
* forwarding now stands a good chance of
|
||||
* working.
|
||||
* Steve Whitehouse : Fixed neighbour states (for now anyway).
|
||||
* Steve Whitehouse : Made error_report functions dummies. This
|
||||
* is not the right place to return skbs.
|
||||
* Steve Whitehouse : Convert to seq_file
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/net.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/netfilter_decnet.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/dn.h>
|
||||
#include <net/dn_dev.h>
|
||||
#include <net/dn_neigh.h>
|
||||
#include <net/dn_route.h>
|
||||
|
||||
static int dn_neigh_construct(struct neighbour *);
|
||||
static void dn_neigh_error_report(struct neighbour *, struct sk_buff *);
|
||||
static int dn_neigh_output(struct neighbour *neigh, struct sk_buff *skb);
|
||||
|
||||
/*
|
||||
* Operations for adding the link layer header.
|
||||
*/
|
||||
static const struct neigh_ops dn_neigh_ops = {
|
||||
.family = AF_DECnet,
|
||||
.error_report = dn_neigh_error_report,
|
||||
.output = dn_neigh_output,
|
||||
.connected_output = dn_neigh_output,
|
||||
};
|
||||
|
||||
static u32 dn_neigh_hash(const void *pkey,
|
||||
const struct net_device *dev,
|
||||
__u32 *hash_rnd)
|
||||
{
|
||||
return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]);
|
||||
}
|
||||
|
||||
static bool dn_key_eq(const struct neighbour *neigh, const void *pkey)
|
||||
{
|
||||
return neigh_key_eq16(neigh, pkey);
|
||||
}
|
||||
|
||||
struct neigh_table dn_neigh_table = {
|
||||
.family = PF_DECnet,
|
||||
.entry_size = NEIGH_ENTRY_SIZE(sizeof(struct dn_neigh)),
|
||||
.key_len = sizeof(__le16),
|
||||
.protocol = cpu_to_be16(ETH_P_DNA_RT),
|
||||
.hash = dn_neigh_hash,
|
||||
.key_eq = dn_key_eq,
|
||||
.constructor = dn_neigh_construct,
|
||||
.id = "dn_neigh_cache",
|
||||
.parms ={
|
||||
.tbl = &dn_neigh_table,
|
||||
.reachable_time = 30 * HZ,
|
||||
.data = {
|
||||
[NEIGH_VAR_MCAST_PROBES] = 0,
|
||||
[NEIGH_VAR_UCAST_PROBES] = 0,
|
||||
[NEIGH_VAR_APP_PROBES] = 0,
|
||||
[NEIGH_VAR_RETRANS_TIME] = 1 * HZ,
|
||||
[NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ,
|
||||
[NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
|
||||
[NEIGH_VAR_GC_STALETIME] = 60 * HZ,
|
||||
[NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX,
|
||||
[NEIGH_VAR_PROXY_QLEN] = 0,
|
||||
[NEIGH_VAR_ANYCAST_DELAY] = 0,
|
||||
[NEIGH_VAR_PROXY_DELAY] = 0,
|
||||
[NEIGH_VAR_LOCKTIME] = 1 * HZ,
|
||||
},
|
||||
},
|
||||
.gc_interval = 30 * HZ,
|
||||
.gc_thresh1 = 128,
|
||||
.gc_thresh2 = 512,
|
||||
.gc_thresh3 = 1024,
|
||||
};
|
||||
|
||||
static int dn_neigh_construct(struct neighbour *neigh)
|
||||
{
|
||||
struct net_device *dev = neigh->dev;
|
||||
struct dn_neigh *dn = container_of(neigh, struct dn_neigh, n);
|
||||
struct dn_dev *dn_db;
|
||||
struct neigh_parms *parms;
|
||||
|
||||
rcu_read_lock();
|
||||
dn_db = rcu_dereference(dev->dn_ptr);
|
||||
if (dn_db == NULL) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
parms = dn_db->neigh_parms;
|
||||
if (!parms) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__neigh_parms_put(neigh->parms);
|
||||
neigh->parms = neigh_parms_clone(parms);
|
||||
rcu_read_unlock();
|
||||
|
||||
neigh->ops = &dn_neigh_ops;
|
||||
neigh->nud_state = NUD_NOARP;
|
||||
neigh->output = neigh->ops->connected_output;
|
||||
|
||||
if ((dev->type == ARPHRD_IPGRE) || (dev->flags & IFF_POINTOPOINT))
|
||||
memcpy(neigh->ha, dev->broadcast, dev->addr_len);
|
||||
else if ((dev->type == ARPHRD_ETHER) || (dev->type == ARPHRD_LOOPBACK))
|
||||
dn_dn2eth(neigh->ha, dn->addr);
|
||||
else {
|
||||
net_dbg_ratelimited("Trying to create neigh for hw %d\n",
|
||||
dev->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make an estimate of the remote block size by assuming that its
|
||||
* two less then the device mtu, which it true for ethernet (and
|
||||
* other things which support long format headers) since there is
|
||||
* an extra length field (of 16 bits) which isn't part of the
|
||||
* ethernet headers and which the DECnet specs won't admit is part
|
||||
* of the DECnet routing headers either.
|
||||
*
|
||||
* If we over estimate here its no big deal, the NSP negotiations
|
||||
* will prevent us from sending packets which are too large for the
|
||||
* remote node to handle. In any case this figure is normally updated
|
||||
* by a hello message in most cases.
|
||||
*/
|
||||
dn->blksize = dev->mtu - 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dn_neigh_error_report(struct neighbour *neigh, struct sk_buff *skb)
|
||||
{
|
||||
printk(KERN_DEBUG "dn_neigh_error_report: called\n");
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static int dn_neigh_output(struct neighbour *neigh, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct dn_route *rt = (struct dn_route *)dst;
|
||||
struct net_device *dev = neigh->dev;
|
||||
char mac_addr[ETH_ALEN];
|
||||
unsigned int seq;
|
||||
int err;
|
||||
|
||||
dn_dn2eth(mac_addr, rt->rt_local_src);
|
||||
do {
|
||||
seq = read_seqbegin(&neigh->ha_lock);
|
||||
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
|
||||
neigh->ha, mac_addr, skb->len);
|
||||
} while (read_seqretry(&neigh->ha_lock, seq));
|
||||
|
||||
if (err >= 0)
|
||||
err = dev_queue_xmit(skb);
|
||||
else {
|
||||
kfree_skb(skb);
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dn_neigh_output_packet(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct dn_route *rt = (struct dn_route *)dst;
|
||||
struct neighbour *neigh = rt->n;
|
||||
|
||||
return neigh->output(neigh, skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* For talking to broadcast devices: Ethernet & PPP
|
||||
*/
|
||||
static int dn_long_output(struct neighbour *neigh, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = neigh->dev;
|
||||
int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
|
||||
unsigned char *data;
|
||||
struct dn_long_packet *lp;
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
|
||||
|
||||
if (skb_headroom(skb) < headroom) {
|
||||
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
|
||||
if (skb2 == NULL) {
|
||||
net_crit_ratelimited("dn_long_output: no memory\n");
|
||||
kfree_skb(skb);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
consume_skb(skb);
|
||||
skb = skb2;
|
||||
net_info_ratelimited("dn_long_output: Increasing headroom\n");
|
||||
}
|
||||
|
||||
data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
|
||||
lp = (struct dn_long_packet *)(data+3);
|
||||
|
||||
*((__le16 *)data) = cpu_to_le16(skb->len - 2);
|
||||
*(data + 2) = 1 | DN_RT_F_PF; /* Padding */
|
||||
|
||||
lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS));
|
||||
lp->d_area = lp->d_subarea = 0;
|
||||
dn_dn2eth(lp->d_id, cb->dst);
|
||||
lp->s_area = lp->s_subarea = 0;
|
||||
dn_dn2eth(lp->s_id, cb->src);
|
||||
lp->nl2 = 0;
|
||||
lp->visit_ct = cb->hops & 0x3f;
|
||||
lp->s_class = 0;
|
||||
lp->pt = 0;
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING,
|
||||
&init_net, sk, skb, NULL, neigh->dev,
|
||||
dn_neigh_output_packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* For talking to pointopoint and multidrop devices: DDCMP and X.25
|
||||
*/
|
||||
static int dn_short_output(struct neighbour *neigh, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = neigh->dev;
|
||||
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
|
||||
struct dn_short_packet *sp;
|
||||
unsigned char *data;
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
|
||||
|
||||
if (skb_headroom(skb) < headroom) {
|
||||
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
|
||||
if (skb2 == NULL) {
|
||||
net_crit_ratelimited("dn_short_output: no memory\n");
|
||||
kfree_skb(skb);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
consume_skb(skb);
|
||||
skb = skb2;
|
||||
net_info_ratelimited("dn_short_output: Increasing headroom\n");
|
||||
}
|
||||
|
||||
data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
|
||||
*((__le16 *)data) = cpu_to_le16(skb->len - 2);
|
||||
sp = (struct dn_short_packet *)(data+2);
|
||||
|
||||
sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
|
||||
sp->dstnode = cb->dst;
|
||||
sp->srcnode = cb->src;
|
||||
sp->forward = cb->hops & 0x3f;
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING,
|
||||
&init_net, sk, skb, NULL, neigh->dev,
|
||||
dn_neigh_output_packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* For talking to DECnet phase III nodes
|
||||
* Phase 3 output is the same as short output, execpt that
|
||||
* it clears the area bits before transmission.
|
||||
*/
|
||||
static int dn_phase3_output(struct neighbour *neigh, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = neigh->dev;
|
||||
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
|
||||
struct dn_short_packet *sp;
|
||||
unsigned char *data;
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
|
||||
if (skb_headroom(skb) < headroom) {
|
||||
struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
|
||||
if (skb2 == NULL) {
|
||||
net_crit_ratelimited("dn_phase3_output: no memory\n");
|
||||
kfree_skb(skb);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
consume_skb(skb);
|
||||
skb = skb2;
|
||||
net_info_ratelimited("dn_phase3_output: Increasing headroom\n");
|
||||
}
|
||||
|
||||
data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
|
||||
*((__le16 *)data) = cpu_to_le16(skb->len - 2);
|
||||
sp = (struct dn_short_packet *)(data + 2);
|
||||
|
||||
sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
|
||||
sp->dstnode = cb->dst & cpu_to_le16(0x03ff);
|
||||
sp->srcnode = cb->src & cpu_to_le16(0x03ff);
|
||||
sp->forward = cb->hops & 0x3f;
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING,
|
||||
&init_net, sk, skb, NULL, neigh->dev,
|
||||
dn_neigh_output_packet);
|
||||
}
|
||||
|
||||
int dn_to_neigh_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct dn_route *rt = (struct dn_route *) dst;
|
||||
struct neighbour *neigh = rt->n;
|
||||
struct dn_neigh *dn = container_of(neigh, struct dn_neigh, n);
|
||||
struct dn_dev *dn_db;
|
||||
bool use_long;
|
||||
|
||||
rcu_read_lock();
|
||||
dn_db = rcu_dereference(neigh->dev->dn_ptr);
|
||||
if (dn_db == NULL) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
use_long = dn_db->use_long;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (dn->flags & DN_NDFLAG_P3)
|
||||
return dn_phase3_output(neigh, sk, skb);
|
||||
if (use_long)
|
||||
return dn_long_output(neigh, sk, skb);
|
||||
else
|
||||
return dn_short_output(neigh, sk, skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately, the neighbour code uses the device in its hash
|
||||
* function, so we don't get any advantage from it. This function
|
||||
* basically does a neigh_lookup(), but without comparing the device
|
||||
* field. This is required for the On-Ethernet cache
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pointopoint link receives a hello message
|
||||
*/
|
||||
void dn_neigh_pointopoint_hello(struct sk_buff *skb)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ethernet router hello message received
|
||||
*/
|
||||
int dn_neigh_router_hello(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct rtnode_hello_message *msg = (struct rtnode_hello_message *)skb->data;
|
||||
|
||||
struct neighbour *neigh;
|
||||
struct dn_neigh *dn;
|
||||
struct dn_dev *dn_db;
|
||||
__le16 src;
|
||||
|
||||
src = dn_eth2dn(msg->id);
|
||||
|
||||
neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
|
||||
|
||||
dn = container_of(neigh, struct dn_neigh, n);
|
||||
|
||||
if (neigh) {
|
||||
write_lock(&neigh->lock);
|
||||
|
||||
neigh->used = jiffies;
|
||||
dn_db = rcu_dereference(neigh->dev->dn_ptr);
|
||||
|
||||
if (!(neigh->nud_state & NUD_PERMANENT)) {
|
||||
neigh->updated = jiffies;
|
||||
|
||||
if (neigh->dev->type == ARPHRD_ETHER)
|
||||
memcpy(neigh->ha, ð_hdr(skb)->h_source, ETH_ALEN);
|
||||
|
||||
dn->blksize = le16_to_cpu(msg->blksize);
|
||||
dn->priority = msg->priority;
|
||||
|
||||
dn->flags &= ~DN_NDFLAG_P3;
|
||||
|
||||
switch (msg->iinfo & DN_RT_INFO_TYPE) {
|
||||
case DN_RT_INFO_L1RT:
|
||||
dn->flags &=~DN_NDFLAG_R2;
|
||||
dn->flags |= DN_NDFLAG_R1;
|
||||
break;
|
||||
case DN_RT_INFO_L2RT:
|
||||
dn->flags |= DN_NDFLAG_R2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only use routers in our area */
|
||||
if ((le16_to_cpu(src)>>10) == (le16_to_cpu((decnet_address))>>10)) {
|
||||
if (!dn_db->router) {
|
||||
dn_db->router = neigh_clone(neigh);
|
||||
} else {
|
||||
if (msg->priority > ((struct dn_neigh *)dn_db->router)->priority)
|
||||
neigh_release(xchg(&dn_db->router, neigh_clone(neigh)));
|
||||
}
|
||||
}
|
||||
write_unlock(&neigh->lock);
|
||||
neigh_release(neigh);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Endnode hello message received
|
||||
*/
|
||||
int dn_neigh_endnode_hello(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data;
|
||||
struct neighbour *neigh;
|
||||
struct dn_neigh *dn;
|
||||
__le16 src;
|
||||
|
||||
src = dn_eth2dn(msg->id);
|
||||
|
||||
neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
|
||||
|
||||
dn = container_of(neigh, struct dn_neigh, n);
|
||||
|
||||
if (neigh) {
|
||||
write_lock(&neigh->lock);
|
||||
|
||||
neigh->used = jiffies;
|
||||
|
||||
if (!(neigh->nud_state & NUD_PERMANENT)) {
|
||||
neigh->updated = jiffies;
|
||||
|
||||
if (neigh->dev->type == ARPHRD_ETHER)
|
||||
memcpy(neigh->ha, ð_hdr(skb)->h_source, ETH_ALEN);
|
||||
dn->flags &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2);
|
||||
dn->blksize = le16_to_cpu(msg->blksize);
|
||||
dn->priority = 0;
|
||||
}
|
||||
|
||||
write_unlock(&neigh->lock);
|
||||
neigh_release(neigh);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *dn_find_slot(char *base, int max, int priority)
|
||||
{
|
||||
int i;
|
||||
unsigned char *min = NULL;
|
||||
|
||||
base += 6; /* skip first id */
|
||||
|
||||
for(i = 0; i < max; i++) {
|
||||
if (!min || (*base < *min))
|
||||
min = base;
|
||||
base += 7; /* find next priority */
|
||||
}
|
||||
|
||||
if (!min)
|
||||
return NULL;
|
||||
|
||||
return (*min < priority) ? (min - 6) : NULL;
|
||||
}
|
||||
|
||||
struct elist_cb_state {
|
||||
struct net_device *dev;
|
||||
unsigned char *ptr;
|
||||
unsigned char *rs;
|
||||
int t, n;
|
||||
};
|
||||
|
||||
static void neigh_elist_cb(struct neighbour *neigh, void *_info)
|
||||
{
|
||||
struct elist_cb_state *s = _info;
|
||||
struct dn_neigh *dn;
|
||||
|
||||
if (neigh->dev != s->dev)
|
||||
return;
|
||||
|
||||
dn = container_of(neigh, struct dn_neigh, n);
|
||||
if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
|
||||
return;
|
||||
|
||||
if (s->t == s->n)
|
||||
s->rs = dn_find_slot(s->ptr, s->n, dn->priority);
|
||||
else
|
||||
s->t++;
|
||||
if (s->rs == NULL)
|
||||
return;
|
||||
|
||||
dn_dn2eth(s->rs, dn->addr);
|
||||
s->rs += 6;
|
||||
*(s->rs) = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0;
|
||||
*(s->rs) |= dn->priority;
|
||||
s->rs++;
|
||||
}
|
||||
|
||||
int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n)
|
||||
{
|
||||
struct elist_cb_state state;
|
||||
|
||||
state.dev = dev;
|
||||
state.t = 0;
|
||||
state.n = n;
|
||||
state.ptr = ptr;
|
||||
state.rs = ptr;
|
||||
|
||||
neigh_for_each(&dn_neigh_table, neigh_elist_cb, &state);
|
||||
|
||||
return state.t;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static inline void dn_neigh_format_entry(struct seq_file *seq,
|
||||
struct neighbour *n)
|
||||
{
|
||||
struct dn_neigh *dn = container_of(n, struct dn_neigh, n);
|
||||
char buf[DN_ASCBUF_LEN];
|
||||
|
||||
read_lock(&n->lock);
|
||||
seq_printf(seq, "%-7s %s%s%s %02x %02d %07ld %-8s\n",
|
||||
dn_addr2asc(le16_to_cpu(dn->addr), buf),
|
||||
(dn->flags&DN_NDFLAG_R1) ? "1" : "-",
|
||||
(dn->flags&DN_NDFLAG_R2) ? "2" : "-",
|
||||
(dn->flags&DN_NDFLAG_P3) ? "3" : "-",
|
||||
dn->n.nud_state,
|
||||
refcount_read(&dn->n.refcnt),
|
||||
dn->blksize,
|
||||
(dn->n.dev) ? dn->n.dev->name : "?");
|
||||
read_unlock(&n->lock);
|
||||
}
|
||||
|
||||
static int dn_neigh_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
seq_puts(seq, "Addr Flags State Use Blksize Dev\n");
|
||||
} else {
|
||||
dn_neigh_format_entry(seq, v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
return neigh_seq_start(seq, pos, &dn_neigh_table,
|
||||
NEIGH_SEQ_NEIGH_ONLY);
|
||||
}
|
||||
|
||||
static const struct seq_operations dn_neigh_seq_ops = {
|
||||
.start = dn_neigh_seq_start,
|
||||
.next = neigh_seq_next,
|
||||
.stop = neigh_seq_stop,
|
||||
.show = dn_neigh_seq_show,
|
||||
};
|
||||
#endif
|
||||
|
||||
void __init dn_neigh_init(void)
|
||||
{
|
||||
neigh_table_init(NEIGH_DN_TABLE, &dn_neigh_table);
|
||||
proc_create_net("decnet_neigh", 0444, init_net.proc_net,
|
||||
&dn_neigh_seq_ops, sizeof(struct neigh_seq_state));
|
||||
}
|
||||
|
||||
void __exit dn_neigh_cleanup(void)
|
||||
{
|
||||
remove_proc_entry("decnet_neigh", init_net.proc_net);
|
||||
neigh_table_clear(NEIGH_DN_TABLE, &dn_neigh_table);
|
||||
}
|
@ -1,906 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* DECnet An implementation of the DECnet protocol suite for the LINUX
|
||||
* operating system. DECnet is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DECnet Network Services Protocol (Input)
|
||||
*
|
||||
* Author: Eduardo Marcelo Serrat <emserrat@geocities.com>
|
||||
*
|
||||
* Changes:
|
||||
*
|
||||
* Steve Whitehouse: Split into dn_nsp_in.c and dn_nsp_out.c from
|
||||
* original dn_nsp.c.
|
||||
* Steve Whitehouse: Updated to work with my new routing architecture.
|
||||
* Steve Whitehouse: Add changes from Eduardo Serrat's patches.
|
||||
* Steve Whitehouse: Put all ack handling code in a common routine.
|
||||
* Steve Whitehouse: Put other common bits into dn_nsp_rx()
|
||||
* Steve Whitehouse: More checks on skb->len to catch bogus packets
|
||||
* Fixed various race conditions and possible nasties.
|
||||
* Steve Whitehouse: Now handles returned conninit frames.
|
||||
* David S. Miller: New socket locking
|
||||
* Steve Whitehouse: Fixed lockup when socket filtering was enabled.
|
||||
* Paul Koning: Fix to push CC sockets into RUN when acks are
|
||||
* received.
|
||||
* Steve Whitehouse:
|
||||
* Patrick Caulfield: Checking conninits for correctness & sending of error
|
||||
* responses.
|
||||
* Steve Whitehouse: Added backlog congestion level return codes.
|
||||
* Patrick Caulfield:
|
||||
* Steve Whitehouse: Added flow control support (outbound)
|
||||
* Steve Whitehouse: Prepare for nonlinear skbs
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/netfilter_decnet.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/dn.h>
|
||||
#include <net/dn_nsp.h>
|
||||
#include <net/dn_dev.h>
|
||||
#include <net/dn_route.h>
|
||||
|
||||
extern int decnet_log_martians;
|
||||
|
||||
static void dn_log_martian(struct sk_buff *skb, const char *msg)
|
||||
{
|
||||
if (decnet_log_martians) {
|
||||
char *devname = skb->dev ? skb->dev->name : "???";
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
net_info_ratelimited("DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n",
|
||||
msg, devname,
|
||||
le16_to_cpu(cb->src),
|
||||
le16_to_cpu(cb->dst),
|
||||
le16_to_cpu(cb->src_port),
|
||||
le16_to_cpu(cb->dst_port));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For this function we've flipped the cross-subchannel bit
|
||||
* if the message is an otherdata or linkservice message. Thus
|
||||
* we can use it to work out what to update.
|
||||
*/
|
||||
static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
unsigned short type = ((ack >> 12) & 0x0003);
|
||||
int wakeup = 0;
|
||||
|
||||
switch (type) {
|
||||
case 0: /* ACK - Data */
|
||||
if (dn_after(ack, scp->ackrcv_dat)) {
|
||||
scp->ackrcv_dat = ack & 0x0fff;
|
||||
wakeup |= dn_nsp_check_xmit_queue(sk, skb,
|
||||
&scp->data_xmit_queue,
|
||||
ack);
|
||||
}
|
||||
break;
|
||||
case 1: /* NAK - Data */
|
||||
break;
|
||||
case 2: /* ACK - OtherData */
|
||||
if (dn_after(ack, scp->ackrcv_oth)) {
|
||||
scp->ackrcv_oth = ack & 0x0fff;
|
||||
wakeup |= dn_nsp_check_xmit_queue(sk, skb,
|
||||
&scp->other_xmit_queue,
|
||||
ack);
|
||||
}
|
||||
break;
|
||||
case 3: /* NAK - OtherData */
|
||||
break;
|
||||
}
|
||||
|
||||
if (wakeup && !sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is a universal ack processor.
|
||||
*/
|
||||
static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth)
|
||||
{
|
||||
__le16 *ptr = (__le16 *)skb->data;
|
||||
int len = 0;
|
||||
unsigned short ack;
|
||||
|
||||
if (skb->len < 2)
|
||||
return len;
|
||||
|
||||
if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
|
||||
skb_pull(skb, 2);
|
||||
ptr++;
|
||||
len += 2;
|
||||
if ((ack & 0x4000) == 0) {
|
||||
if (oth)
|
||||
ack ^= 0x2000;
|
||||
dn_ack(sk, skb, ack);
|
||||
}
|
||||
}
|
||||
|
||||
if (skb->len < 2)
|
||||
return len;
|
||||
|
||||
if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
|
||||
skb_pull(skb, 2);
|
||||
len += 2;
|
||||
if ((ack & 0x4000) == 0) {
|
||||
if (oth)
|
||||
ack ^= 0x2000;
|
||||
dn_ack(sk, skb, ack);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dn_check_idf - Check an image data field format is correct.
|
||||
* @pptr: Pointer to pointer to image data
|
||||
* @len: Pointer to length of image data
|
||||
* @max: The maximum allowed length of the data in the image data field
|
||||
* @follow_on: Check that this many bytes exist beyond the end of the image data
|
||||
*
|
||||
* Returns: 0 if ok, -1 on error
|
||||
*/
|
||||
static inline int dn_check_idf(unsigned char **pptr, int *len, unsigned char max, unsigned char follow_on)
|
||||
{
|
||||
unsigned char *ptr = *pptr;
|
||||
unsigned char flen = *ptr++;
|
||||
|
||||
(*len)--;
|
||||
if (flen > max)
|
||||
return -1;
|
||||
if ((flen + follow_on) > *len)
|
||||
return -1;
|
||||
|
||||
*len -= flen;
|
||||
*pptr = ptr + flen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Table of reason codes to pass back to node which sent us a badly
|
||||
* formed message, plus text messages for the log. A zero entry in
|
||||
* the reason field means "don't reply" otherwise a disc init is sent with
|
||||
* the specified reason code.
|
||||
*/
|
||||
static struct {
|
||||
unsigned short reason;
|
||||
const char *text;
|
||||
} ci_err_table[] = {
|
||||
{ 0, "CI: Truncated message" },
|
||||
{ NSP_REASON_ID, "CI: Destination username error" },
|
||||
{ NSP_REASON_ID, "CI: Destination username type" },
|
||||
{ NSP_REASON_US, "CI: Source username error" },
|
||||
{ 0, "CI: Truncated at menuver" },
|
||||
{ 0, "CI: Truncated before access or user data" },
|
||||
{ NSP_REASON_IO, "CI: Access data format error" },
|
||||
{ NSP_REASON_IO, "CI: User data format error" }
|
||||
};
|
||||
|
||||
/*
|
||||
* This function uses a slightly different lookup method
|
||||
* to find its sockets, since it searches on object name/number
|
||||
* rather than port numbers. Various tests are done to ensure that
|
||||
* the incoming data is in the correct format before it is queued to
|
||||
* a socket.
|
||||
*/
|
||||
static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason)
|
||||
{
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
struct nsp_conn_init_msg *msg = (struct nsp_conn_init_msg *)skb->data;
|
||||
struct sockaddr_dn dstaddr;
|
||||
struct sockaddr_dn srcaddr;
|
||||
unsigned char type = 0;
|
||||
int dstlen;
|
||||
int srclen;
|
||||
unsigned char *ptr;
|
||||
int len;
|
||||
int err = 0;
|
||||
unsigned char menuver;
|
||||
|
||||
memset(&dstaddr, 0, sizeof(struct sockaddr_dn));
|
||||
memset(&srcaddr, 0, sizeof(struct sockaddr_dn));
|
||||
|
||||
/*
|
||||
* 1. Decode & remove message header
|
||||
*/
|
||||
cb->src_port = msg->srcaddr;
|
||||
cb->dst_port = msg->dstaddr;
|
||||
cb->services = msg->services;
|
||||
cb->info = msg->info;
|
||||
cb->segsize = le16_to_cpu(msg->segsize);
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(*msg)))
|
||||
goto err_out;
|
||||
|
||||
skb_pull(skb, sizeof(*msg));
|
||||
|
||||
len = skb->len;
|
||||
ptr = skb->data;
|
||||
|
||||
/*
|
||||
* 2. Check destination end username format
|
||||
*/
|
||||
dstlen = dn_username2sockaddr(ptr, len, &dstaddr, &type);
|
||||
err++;
|
||||
if (dstlen < 0)
|
||||
goto err_out;
|
||||
|
||||
err++;
|
||||
if (type > 1)
|
||||
goto err_out;
|
||||
|
||||
len -= dstlen;
|
||||
ptr += dstlen;
|
||||
|
||||
/*
|
||||
* 3. Check source end username format
|
||||
*/
|
||||
srclen = dn_username2sockaddr(ptr, len, &srcaddr, &type);
|
||||
err++;
|
||||
if (srclen < 0)
|
||||
goto err_out;
|
||||
|
||||
len -= srclen;
|
||||
ptr += srclen;
|
||||
err++;
|
||||
if (len < 1)
|
||||
goto err_out;
|
||||
|
||||
menuver = *ptr;
|
||||
ptr++;
|
||||
len--;
|
||||
|
||||
/*
|
||||
* 4. Check that optional data actually exists if menuver says it does
|
||||
*/
|
||||
err++;
|
||||
if ((menuver & (DN_MENUVER_ACC | DN_MENUVER_USR)) && (len < 1))
|
||||
goto err_out;
|
||||
|
||||
/*
|
||||
* 5. Check optional access data format
|
||||
*/
|
||||
err++;
|
||||
if (menuver & DN_MENUVER_ACC) {
|
||||
if (dn_check_idf(&ptr, &len, 39, 1))
|
||||
goto err_out;
|
||||
if (dn_check_idf(&ptr, &len, 39, 1))
|
||||
goto err_out;
|
||||
if (dn_check_idf(&ptr, &len, 39, (menuver & DN_MENUVER_USR) ? 1 : 0))
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 6. Check optional user data format
|
||||
*/
|
||||
err++;
|
||||
if (menuver & DN_MENUVER_USR) {
|
||||
if (dn_check_idf(&ptr, &len, 16, 0))
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 7. Look up socket based on destination end username
|
||||
*/
|
||||
return dn_sklist_find_listener(&dstaddr);
|
||||
err_out:
|
||||
dn_log_martian(skb, ci_err_table[err].text);
|
||||
*reason = ci_err_table[err].reason;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
if (sk_acceptq_is_full(sk)) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
sk->sk_ack_backlog++;
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb);
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
unsigned char *ptr;
|
||||
|
||||
if (skb->len < 4)
|
||||
goto out;
|
||||
|
||||
ptr = skb->data;
|
||||
cb->services = *ptr++;
|
||||
cb->info = *ptr++;
|
||||
cb->segsize = le16_to_cpu(*(__le16 *)ptr);
|
||||
|
||||
if ((scp->state == DN_CI) || (scp->state == DN_CD)) {
|
||||
scp->persist = 0;
|
||||
scp->addrrem = cb->src_port;
|
||||
sk->sk_state = TCP_ESTABLISHED;
|
||||
scp->state = DN_RUN;
|
||||
scp->services_rem = cb->services;
|
||||
scp->info_rem = cb->info;
|
||||
scp->segsize_rem = cb->segsize;
|
||||
|
||||
if ((scp->services_rem & NSP_FC_MASK) == NSP_FC_NONE)
|
||||
scp->max_window = decnet_no_fc_max_cwnd;
|
||||
|
||||
if (skb->len > 0) {
|
||||
u16 dlen = *skb->data;
|
||||
if ((dlen <= 16) && (dlen <= skb->len)) {
|
||||
scp->conndata_in.opt_optl = cpu_to_le16(dlen);
|
||||
skb_copy_from_linear_data_offset(skb, 1,
|
||||
scp->conndata_in.opt_data, dlen);
|
||||
}
|
||||
}
|
||||
dn_nsp_send_link(sk, DN_NOCHANGE, 0);
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void dn_nsp_conn_ack(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
if (scp->state == DN_CI) {
|
||||
scp->state = DN_CD;
|
||||
scp->persist = 0;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
unsigned short reason;
|
||||
|
||||
if (skb->len < 2)
|
||||
goto out;
|
||||
|
||||
reason = le16_to_cpu(*(__le16 *)skb->data);
|
||||
skb_pull(skb, 2);
|
||||
|
||||
scp->discdata_in.opt_status = cpu_to_le16(reason);
|
||||
scp->discdata_in.opt_optl = 0;
|
||||
memset(scp->discdata_in.opt_data, 0, 16);
|
||||
|
||||
if (skb->len > 0) {
|
||||
u16 dlen = *skb->data;
|
||||
if ((dlen <= 16) && (dlen <= skb->len)) {
|
||||
scp->discdata_in.opt_optl = cpu_to_le16(dlen);
|
||||
skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen);
|
||||
}
|
||||
}
|
||||
|
||||
scp->addrrem = cb->src_port;
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
|
||||
switch (scp->state) {
|
||||
case DN_CI:
|
||||
case DN_CD:
|
||||
scp->state = DN_RJ;
|
||||
sk->sk_err = ECONNREFUSED;
|
||||
break;
|
||||
case DN_RUN:
|
||||
sk->sk_shutdown |= SHUTDOWN_MASK;
|
||||
scp->state = DN_DN;
|
||||
break;
|
||||
case DN_DI:
|
||||
scp->state = DN_DIC;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sock_flag(sk, SOCK_DEAD)) {
|
||||
if (sk->sk_socket->state != SS_UNCONNECTED)
|
||||
sk->sk_socket->state = SS_DISCONNECTING;
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
/*
|
||||
* It appears that its possible for remote machines to send disc
|
||||
* init messages with no port identifier if we are in the CI and
|
||||
* possibly also the CD state. Obviously we shouldn't reply with
|
||||
* a message if we don't know what the end point is.
|
||||
*/
|
||||
if (scp->addrrem) {
|
||||
dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
|
||||
}
|
||||
scp->persist_fxn = dn_destroy_timer;
|
||||
scp->persist = dn_nsp_persist(sk);
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* disc_conf messages are also called no_resources or no_link
|
||||
* messages depending upon the "reason" field.
|
||||
*/
|
||||
static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
unsigned short reason;
|
||||
|
||||
if (skb->len != 2)
|
||||
goto out;
|
||||
|
||||
reason = le16_to_cpu(*(__le16 *)skb->data);
|
||||
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
|
||||
switch (scp->state) {
|
||||
case DN_CI:
|
||||
scp->state = DN_NR;
|
||||
break;
|
||||
case DN_DR:
|
||||
if (reason == NSP_REASON_DC)
|
||||
scp->state = DN_DRC;
|
||||
if (reason == NSP_REASON_NL)
|
||||
scp->state = DN_CN;
|
||||
break;
|
||||
case DN_DI:
|
||||
scp->state = DN_DIC;
|
||||
break;
|
||||
case DN_RUN:
|
||||
sk->sk_shutdown |= SHUTDOWN_MASK;
|
||||
/* fall through */
|
||||
case DN_CC:
|
||||
scp->state = DN_CN;
|
||||
}
|
||||
|
||||
if (!sock_flag(sk, SOCK_DEAD)) {
|
||||
if (sk->sk_socket->state != SS_UNCONNECTED)
|
||||
sk->sk_socket->state = SS_DISCONNECTING;
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
scp->persist_fxn = dn_destroy_timer;
|
||||
scp->persist = dn_nsp_persist(sk);
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
unsigned short segnum;
|
||||
unsigned char lsflags;
|
||||
signed char fcval;
|
||||
int wake_up = 0;
|
||||
char *ptr = skb->data;
|
||||
unsigned char fctype = scp->services_rem & NSP_FC_MASK;
|
||||
|
||||
if (skb->len != 4)
|
||||
goto out;
|
||||
|
||||
segnum = le16_to_cpu(*(__le16 *)ptr);
|
||||
ptr += 2;
|
||||
lsflags = *(unsigned char *)ptr++;
|
||||
fcval = *ptr;
|
||||
|
||||
/*
|
||||
* Here we ignore erronous packets which should really
|
||||
* should cause a connection abort. It is not critical
|
||||
* for now though.
|
||||
*/
|
||||
if (lsflags & 0xf8)
|
||||
goto out;
|
||||
|
||||
if (seq_next(scp->numoth_rcv, segnum)) {
|
||||
seq_add(&scp->numoth_rcv, 1);
|
||||
switch(lsflags & 0x04) { /* FCVAL INT */
|
||||
case 0x00: /* Normal Request */
|
||||
switch(lsflags & 0x03) { /* FCVAL MOD */
|
||||
case 0x00: /* Request count */
|
||||
if (fcval < 0) {
|
||||
unsigned char p_fcval = -fcval;
|
||||
if ((scp->flowrem_dat > p_fcval) &&
|
||||
(fctype == NSP_FC_SCMC)) {
|
||||
scp->flowrem_dat -= p_fcval;
|
||||
}
|
||||
} else if (fcval > 0) {
|
||||
scp->flowrem_dat += fcval;
|
||||
wake_up = 1;
|
||||
}
|
||||
break;
|
||||
case 0x01: /* Stop outgoing data */
|
||||
scp->flowrem_sw = DN_DONTSEND;
|
||||
break;
|
||||
case 0x02: /* Ok to start again */
|
||||
scp->flowrem_sw = DN_SEND;
|
||||
dn_nsp_output(sk);
|
||||
wake_up = 1;
|
||||
}
|
||||
break;
|
||||
case 0x04: /* Interrupt Request */
|
||||
if (fcval > 0) {
|
||||
scp->flowrem_oth += fcval;
|
||||
wake_up = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (wake_up && !sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
dn_nsp_send_oth_ack(sk);
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy of sock_queue_rcv_skb (from sock.h) without
|
||||
* bh_lock_sock() (its already held when this is called) which
|
||||
* also allows data and other data to be queued to a socket.
|
||||
*/
|
||||
static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
|
||||
number of warnings when compiling with -W --ANK
|
||||
*/
|
||||
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
|
||||
(unsigned int)sk->sk_rcvbuf) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = sk_filter(sk, skb);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
skb_set_owner_r(skb, sk);
|
||||
skb_queue_tail(queue, skb);
|
||||
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_data_ready(sk);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
unsigned short segnum;
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
int queued = 0;
|
||||
|
||||
if (skb->len < 2)
|
||||
goto out;
|
||||
|
||||
cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
|
||||
skb_pull(skb, 2);
|
||||
|
||||
if (seq_next(scp->numoth_rcv, segnum)) {
|
||||
|
||||
if (dn_queue_skb(sk, skb, SIGURG, &scp->other_receive_queue) == 0) {
|
||||
seq_add(&scp->numoth_rcv, 1);
|
||||
scp->other_report = 0;
|
||||
queued = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dn_nsp_send_oth_ack(sk);
|
||||
out:
|
||||
if (!queued)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void dn_nsp_data(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
int queued = 0;
|
||||
unsigned short segnum;
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
if (skb->len < 2)
|
||||
goto out;
|
||||
|
||||
cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
|
||||
skb_pull(skb, 2);
|
||||
|
||||
if (seq_next(scp->numdat_rcv, segnum)) {
|
||||
if (dn_queue_skb(sk, skb, SIGIO, &sk->sk_receive_queue) == 0) {
|
||||
seq_add(&scp->numdat_rcv, 1);
|
||||
queued = 1;
|
||||
}
|
||||
|
||||
if ((scp->flowloc_sw == DN_SEND) && dn_congested(sk)) {
|
||||
scp->flowloc_sw = DN_DONTSEND;
|
||||
dn_nsp_send_link(sk, DN_DONTSEND, 0);
|
||||
}
|
||||
}
|
||||
|
||||
dn_nsp_send_data_ack(sk);
|
||||
out:
|
||||
if (!queued)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* If one of our conninit messages is returned, this function
|
||||
* deals with it. It puts the socket into the NO_COMMUNICATION
|
||||
* state.
|
||||
*/
|
||||
static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
if (scp->state == DN_CI) {
|
||||
scp->state = DN_NC;
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static int dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason)
|
||||
{
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
int ret = NET_RX_DROP;
|
||||
|
||||
/* Must not reply to returned packets */
|
||||
if (cb->rt_flags & DN_RT_F_RTS)
|
||||
goto out;
|
||||
|
||||
if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {
|
||||
switch (cb->nsp_flags & 0x70) {
|
||||
case 0x10:
|
||||
case 0x60: /* (Retransmitted) Connect Init */
|
||||
dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
|
||||
ret = NET_RX_SUCCESS;
|
||||
break;
|
||||
case 0x20: /* Connect Confirm */
|
||||
dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
|
||||
ret = NET_RX_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dn_nsp_rx_packet(struct net *net, struct sock *sk2,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
struct sock *sk = NULL;
|
||||
unsigned char *ptr = (unsigned char *)skb->data;
|
||||
unsigned short reason = NSP_REASON_NL;
|
||||
|
||||
if (!pskb_may_pull(skb, 2))
|
||||
goto free_out;
|
||||
|
||||
skb_reset_transport_header(skb);
|
||||
cb->nsp_flags = *ptr++;
|
||||
|
||||
if (decnet_debug_level & 2)
|
||||
printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
|
||||
|
||||
if (cb->nsp_flags & 0x83)
|
||||
goto free_out;
|
||||
|
||||
/*
|
||||
* Filter out conninits and useless packet types
|
||||
*/
|
||||
if ((cb->nsp_flags & 0x0c) == 0x08) {
|
||||
switch (cb->nsp_flags & 0x70) {
|
||||
case 0x00: /* NOP */
|
||||
case 0x70: /* Reserved */
|
||||
case 0x50: /* Reserved, Phase II node init */
|
||||
goto free_out;
|
||||
case 0x10:
|
||||
case 0x60:
|
||||
if (unlikely(cb->rt_flags & DN_RT_F_RTS))
|
||||
goto free_out;
|
||||
sk = dn_find_listener(skb, &reason);
|
||||
goto got_it;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pskb_may_pull(skb, 3))
|
||||
goto free_out;
|
||||
|
||||
/*
|
||||
* Grab the destination address.
|
||||
*/
|
||||
cb->dst_port = *(__le16 *)ptr;
|
||||
cb->src_port = 0;
|
||||
ptr += 2;
|
||||
|
||||
/*
|
||||
* If not a connack, grab the source address too.
|
||||
*/
|
||||
if (pskb_may_pull(skb, 5)) {
|
||||
cb->src_port = *(__le16 *)ptr;
|
||||
ptr += 2;
|
||||
skb_pull(skb, 5);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returned packets...
|
||||
* Swap src & dst and look up in the normal way.
|
||||
*/
|
||||
if (unlikely(cb->rt_flags & DN_RT_F_RTS)) {
|
||||
swap(cb->dst_port, cb->src_port);
|
||||
swap(cb->dst, cb->src);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the socket to which this skb is destined.
|
||||
*/
|
||||
sk = dn_find_by_skb(skb);
|
||||
got_it:
|
||||
if (sk != NULL) {
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
/* Reset backoff */
|
||||
scp->nsp_rxtshift = 0;
|
||||
|
||||
/*
|
||||
* We linearize everything except data segments here.
|
||||
*/
|
||||
if (cb->nsp_flags & ~0x60) {
|
||||
if (unlikely(skb_linearize(skb)))
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
return sk_receive_skb(sk, skb, 0);
|
||||
}
|
||||
|
||||
return dn_nsp_no_socket(skb, reason);
|
||||
|
||||
free_out:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
int dn_nsp_rx(struct sk_buff *skb)
|
||||
{
|
||||
return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_IN,
|
||||
&init_net, NULL, skb, skb->dev, NULL,
|
||||
dn_nsp_rx_packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main receive routine for sockets. It is called
|
||||
* from the above when the socket is not busy, and also from
|
||||
* sock_release() when there is a backlog queued up.
|
||||
*/
|
||||
int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
|
||||
if (cb->rt_flags & DN_RT_F_RTS) {
|
||||
if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
|
||||
dn_returned_conn_init(sk, skb);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Control packet.
|
||||
*/
|
||||
if ((cb->nsp_flags & 0x0c) == 0x08) {
|
||||
switch (cb->nsp_flags & 0x70) {
|
||||
case 0x10:
|
||||
case 0x60:
|
||||
dn_nsp_conn_init(sk, skb);
|
||||
break;
|
||||
case 0x20:
|
||||
dn_nsp_conn_conf(sk, skb);
|
||||
break;
|
||||
case 0x30:
|
||||
dn_nsp_disc_init(sk, skb);
|
||||
break;
|
||||
case 0x40:
|
||||
dn_nsp_disc_conf(sk, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (cb->nsp_flags == 0x24) {
|
||||
/*
|
||||
* Special for connacks, 'cos they don't have
|
||||
* ack data or ack otherdata info.
|
||||
*/
|
||||
dn_nsp_conn_ack(sk, skb);
|
||||
} else {
|
||||
int other = 1;
|
||||
|
||||
/* both data and ack frames can kick a CC socket into RUN */
|
||||
if ((scp->state == DN_CC) && !sock_flag(sk, SOCK_DEAD)) {
|
||||
scp->state = DN_RUN;
|
||||
sk->sk_state = TCP_ESTABLISHED;
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
if ((cb->nsp_flags & 0x1c) == 0)
|
||||
other = 0;
|
||||
if (cb->nsp_flags == 0x04)
|
||||
other = 0;
|
||||
|
||||
/*
|
||||
* Read out ack data here, this applies equally
|
||||
* to data, other data, link serivce and both
|
||||
* ack data and ack otherdata.
|
||||
*/
|
||||
dn_process_ack(sk, skb, other);
|
||||
|
||||
/*
|
||||
* If we've some sort of data here then call a
|
||||
* suitable routine for dealing with it, otherwise
|
||||
* the packet is an ack and can be discarded.
|
||||
*/
|
||||
if ((cb->nsp_flags & 0x0c) == 0) {
|
||||
|
||||
if (scp->state != DN_RUN)
|
||||
goto free_out;
|
||||
|
||||
switch (cb->nsp_flags) {
|
||||
case 0x10: /* LS */
|
||||
dn_nsp_linkservice(sk, skb);
|
||||
break;
|
||||
case 0x30: /* OD */
|
||||
dn_nsp_otherdata(sk, skb);
|
||||
break;
|
||||
default:
|
||||
dn_nsp_data(sk, skb);
|
||||
}
|
||||
|
||||
} else { /* Ack, chuck it out here */
|
||||
free_out:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
@ -1,695 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* DECnet An implementation of the DECnet protocol suite for the LINUX
|
||||
* operating system. DECnet is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DECnet Network Services Protocol (Output)
|
||||
*
|
||||
* Author: Eduardo Marcelo Serrat <emserrat@geocities.com>
|
||||
*
|
||||
* Changes:
|
||||
*
|
||||
* Steve Whitehouse: Split into dn_nsp_in.c and dn_nsp_out.c from
|
||||
* original dn_nsp.c.
|
||||
* Steve Whitehouse: Updated to work with my new routing architecture.
|
||||
* Steve Whitehouse: Added changes from Eduardo Serrat's patches.
|
||||
* Steve Whitehouse: Now conninits have the "return" bit set.
|
||||
* Steve Whitehouse: Fixes to check alloc'd skbs are non NULL!
|
||||
* Moved output state machine into one function
|
||||
* Steve Whitehouse: New output state machine
|
||||
* Paul Koning: Connect Confirm message fix.
|
||||
* Eduardo Serrat: Fix to stop dn_nsp_do_disc() sending malformed packets.
|
||||
* Steve Whitehouse: dn_nsp_output() and friends needed a spring clean
|
||||
* Steve Whitehouse: Moved dn_nsp_send() in here from route.h
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
(c) 1995-1998 E.M. Serrat emserrat@geocities.com
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/dn.h>
|
||||
#include <net/dn_nsp.h>
|
||||
#include <net/dn_dev.h>
|
||||
#include <net/dn_route.h>
|
||||
|
||||
|
||||
static int nsp_backoff[NSP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
|
||||
|
||||
static void dn_nsp_send(struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk = skb->sk;
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct dst_entry *dst;
|
||||
struct flowidn fld;
|
||||
|
||||
skb_reset_transport_header(skb);
|
||||
scp->stamp = jiffies;
|
||||
|
||||
dst = sk_dst_check(sk, 0);
|
||||
if (dst) {
|
||||
try_again:
|
||||
skb_dst_set(skb, dst);
|
||||
dst_output(&init_net, skb->sk, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&fld, 0, sizeof(fld));
|
||||
fld.flowidn_oif = sk->sk_bound_dev_if;
|
||||
fld.saddr = dn_saddr2dn(&scp->addr);
|
||||
fld.daddr = dn_saddr2dn(&scp->peer);
|
||||
dn_sk_ports_copy(&fld, scp);
|
||||
fld.flowidn_proto = DNPROTO_NSP;
|
||||
if (dn_route_output_sock(&sk->sk_dst_cache, &fld, sk, 0) == 0) {
|
||||
dst = sk_dst_get(sk);
|
||||
sk->sk_route_caps = dst->dev->features;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
sk->sk_err = EHOSTUNREACH;
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If sk == NULL, then we assume that we are supposed to be making
|
||||
* a routing layer skb. If sk != NULL, then we are supposed to be
|
||||
* creating an skb for the NSP layer.
|
||||
*
|
||||
* The eventual aim is for each socket to have a cached header size
|
||||
* for its outgoing packets, and to set hdr from this when sk != NULL.
|
||||
*/
|
||||
struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int hdr = 64;
|
||||
|
||||
if ((skb = alloc_skb(size + hdr, pri)) == NULL)
|
||||
return NULL;
|
||||
|
||||
skb->protocol = htons(ETH_P_DNA_RT);
|
||||
skb->pkt_type = PACKET_OUTGOING;
|
||||
|
||||
if (sk)
|
||||
skb_set_owner_w(skb, sk);
|
||||
|
||||
skb_reserve(skb, hdr);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate persist timer based upon the smoothed round
|
||||
* trip time and the variance. Backoff according to the
|
||||
* nsp_backoff[] array.
|
||||
*/
|
||||
unsigned long dn_nsp_persist(struct sock *sk)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
|
||||
|
||||
t *= nsp_backoff[scp->nsp_rxtshift];
|
||||
|
||||
if (t < HZ) t = HZ;
|
||||
if (t > (600*HZ)) t = (600*HZ);
|
||||
|
||||
if (scp->nsp_rxtshift < NSP_MAXRXTSHIFT)
|
||||
scp->nsp_rxtshift++;
|
||||
|
||||
/* printk(KERN_DEBUG "rxtshift %lu, t=%lu\n", scp->nsp_rxtshift, t); */
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called each time we get an estimate for the rtt
|
||||
* on the link.
|
||||
*/
|
||||
static void dn_nsp_rtt(struct sock *sk, long rtt)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
long srtt = (long)scp->nsp_srtt;
|
||||
long rttvar = (long)scp->nsp_rttvar;
|
||||
long delta;
|
||||
|
||||
/*
|
||||
* If the jiffies clock flips over in the middle of timestamp
|
||||
* gathering this value might turn out negative, so we make sure
|
||||
* that is it always positive here.
|
||||
*/
|
||||
if (rtt < 0)
|
||||
rtt = -rtt;
|
||||
/*
|
||||
* Add new rtt to smoothed average
|
||||
*/
|
||||
delta = ((rtt << 3) - srtt);
|
||||
srtt += (delta >> 3);
|
||||
if (srtt >= 1)
|
||||
scp->nsp_srtt = (unsigned long)srtt;
|
||||
else
|
||||
scp->nsp_srtt = 1;
|
||||
|
||||
/*
|
||||
* Add new rtt varience to smoothed varience
|
||||
*/
|
||||
delta >>= 1;
|
||||
rttvar += ((((delta>0)?(delta):(-delta)) - rttvar) >> 2);
|
||||
if (rttvar >= 1)
|
||||
scp->nsp_rttvar = (unsigned long)rttvar;
|
||||
else
|
||||
scp->nsp_rttvar = 1;
|
||||
|
||||
/* printk(KERN_DEBUG "srtt=%lu rttvar=%lu\n", scp->nsp_srtt, scp->nsp_rttvar); */
|
||||
}
|
||||
|
||||
/**
|
||||
* dn_nsp_clone_and_send - Send a data packet by cloning it
|
||||
* @skb: The packet to clone and transmit
|
||||
* @gfp: memory allocation flag
|
||||
*
|
||||
* Clone a queued data or other data packet and transmit it.
|
||||
*
|
||||
* Returns: The number of times the packet has been sent previously
|
||||
*/
|
||||
static inline unsigned int dn_nsp_clone_and_send(struct sk_buff *skb,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
struct sk_buff *skb2;
|
||||
int ret = 0;
|
||||
|
||||
if ((skb2 = skb_clone(skb, gfp)) != NULL) {
|
||||
ret = cb->xmit_count;
|
||||
cb->xmit_count++;
|
||||
cb->stamp = jiffies;
|
||||
skb2->sk = skb->sk;
|
||||
dn_nsp_send(skb2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dn_nsp_output - Try and send something from socket queues
|
||||
* @sk: The socket whose queues are to be investigated
|
||||
*
|
||||
* Try and send the packet on the end of the data and other data queues.
|
||||
* Other data gets priority over data, and if we retransmit a packet we
|
||||
* reduce the window by dividing it in two.
|
||||
*
|
||||
*/
|
||||
void dn_nsp_output(struct sock *sk)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct sk_buff *skb;
|
||||
unsigned int reduce_win = 0;
|
||||
|
||||
/*
|
||||
* First we check for otherdata/linkservice messages
|
||||
*/
|
||||
if ((skb = skb_peek(&scp->other_xmit_queue)) != NULL)
|
||||
reduce_win = dn_nsp_clone_and_send(skb, GFP_ATOMIC);
|
||||
|
||||
/*
|
||||
* If we may not send any data, we don't.
|
||||
* If we are still trying to get some other data down the
|
||||
* channel, we don't try and send any data.
|
||||
*/
|
||||
if (reduce_win || (scp->flowrem_sw != DN_SEND))
|
||||
goto recalc_window;
|
||||
|
||||
if ((skb = skb_peek(&scp->data_xmit_queue)) != NULL)
|
||||
reduce_win = dn_nsp_clone_and_send(skb, GFP_ATOMIC);
|
||||
|
||||
/*
|
||||
* If we've sent any frame more than once, we cut the
|
||||
* send window size in half. There is always a minimum
|
||||
* window size of one available.
|
||||
*/
|
||||
recalc_window:
|
||||
if (reduce_win) {
|
||||
scp->snd_window >>= 1;
|
||||
if (scp->snd_window < NSP_MIN_WINDOW)
|
||||
scp->snd_window = NSP_MIN_WINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
int dn_nsp_xmit_timeout(struct sock *sk)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
dn_nsp_output(sk);
|
||||
|
||||
if (!skb_queue_empty(&scp->data_xmit_queue) ||
|
||||
!skb_queue_empty(&scp->other_xmit_queue))
|
||||
scp->persist = dn_nsp_persist(sk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline __le16 *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len)
|
||||
{
|
||||
unsigned char *ptr = skb_push(skb, len);
|
||||
|
||||
BUG_ON(len < 5);
|
||||
|
||||
*ptr++ = msgflag;
|
||||
*((__le16 *)ptr) = scp->addrrem;
|
||||
ptr += 2;
|
||||
*((__le16 *)ptr) = scp->addrloc;
|
||||
ptr += 2;
|
||||
return (__le16 __force *)ptr;
|
||||
}
|
||||
|
||||
static __le16 *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
unsigned short acknum = scp->numdat_rcv & 0x0FFF;
|
||||
unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
|
||||
__le16 *ptr;
|
||||
|
||||
BUG_ON(hlen < 9);
|
||||
|
||||
scp->ackxmt_dat = acknum;
|
||||
scp->ackxmt_oth = ackcrs;
|
||||
acknum |= 0x8000;
|
||||
ackcrs |= 0x8000;
|
||||
|
||||
/* If this is an "other data/ack" message, swap acknum and ackcrs */
|
||||
if (other)
|
||||
swap(acknum, ackcrs);
|
||||
|
||||
/* Set "cross subchannel" bit in ackcrs */
|
||||
ackcrs |= 0x2000;
|
||||
|
||||
ptr = dn_mk_common_header(scp, skb, msgflag, hlen);
|
||||
|
||||
*ptr++ = cpu_to_le16(acknum);
|
||||
*ptr++ = cpu_to_le16(ackcrs);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static __le16 *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
__le16 *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth);
|
||||
|
||||
if (unlikely(oth)) {
|
||||
cb->segnum = scp->numoth;
|
||||
seq_add(&scp->numoth, 1);
|
||||
} else {
|
||||
cb->segnum = scp->numdat;
|
||||
seq_add(&scp->numdat, 1);
|
||||
}
|
||||
*(ptr++) = cpu_to_le16(cb->segnum);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb,
|
||||
gfp_t gfp, int oth)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
|
||||
|
||||
cb->xmit_count = 0;
|
||||
dn_nsp_mk_data_header(sk, skb, oth);
|
||||
|
||||
/*
|
||||
* Slow start: If we have been idle for more than
|
||||
* one RTT, then reset window to min size.
|
||||
*/
|
||||
if ((jiffies - scp->stamp) > t)
|
||||
scp->snd_window = NSP_MIN_WINDOW;
|
||||
|
||||
if (oth)
|
||||
skb_queue_tail(&scp->other_xmit_queue, skb);
|
||||
else
|
||||
skb_queue_tail(&scp->data_xmit_queue, skb);
|
||||
|
||||
if (scp->flowrem_sw != DN_SEND)
|
||||
return;
|
||||
|
||||
dn_nsp_clone_and_send(skb, gfp);
|
||||
}
|
||||
|
||||
|
||||
int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *q, unsigned short acknum)
|
||||
{
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct sk_buff *skb2, *n, *ack = NULL;
|
||||
int wakeup = 0;
|
||||
int try_retrans = 0;
|
||||
unsigned long reftime = cb->stamp;
|
||||
unsigned long pkttime;
|
||||
unsigned short xmit_count;
|
||||
unsigned short segnum;
|
||||
|
||||
skb_queue_walk_safe(q, skb2, n) {
|
||||
struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);
|
||||
|
||||
if (dn_before_or_equal(cb2->segnum, acknum))
|
||||
ack = skb2;
|
||||
|
||||
/* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */
|
||||
|
||||
if (ack == NULL)
|
||||
continue;
|
||||
|
||||
/* printk(KERN_DEBUG "check_xmit_queue: %04x, %d\n", acknum, cb2->xmit_count); */
|
||||
|
||||
/* Does _last_ packet acked have xmit_count > 1 */
|
||||
try_retrans = 0;
|
||||
/* Remember to wake up the sending process */
|
||||
wakeup = 1;
|
||||
/* Keep various statistics */
|
||||
pkttime = cb2->stamp;
|
||||
xmit_count = cb2->xmit_count;
|
||||
segnum = cb2->segnum;
|
||||
/* Remove and drop ack'ed packet */
|
||||
skb_unlink(ack, q);
|
||||
kfree_skb(ack);
|
||||
ack = NULL;
|
||||
|
||||
/*
|
||||
* We don't expect to see acknowledgements for packets we
|
||||
* haven't sent yet.
|
||||
*/
|
||||
WARN_ON(xmit_count == 0);
|
||||
|
||||
/*
|
||||
* If the packet has only been sent once, we can use it
|
||||
* to calculate the RTT and also open the window a little
|
||||
* further.
|
||||
*/
|
||||
if (xmit_count == 1) {
|
||||
if (dn_equal(segnum, acknum))
|
||||
dn_nsp_rtt(sk, (long)(pkttime - reftime));
|
||||
|
||||
if (scp->snd_window < scp->max_window)
|
||||
scp->snd_window++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Packet has been sent more than once. If this is the last
|
||||
* packet to be acknowledged then we want to send the next
|
||||
* packet in the send queue again (assumes the remote host does
|
||||
* go-back-N error control).
|
||||
*/
|
||||
if (xmit_count > 1)
|
||||
try_retrans = 1;
|
||||
}
|
||||
|
||||
if (try_retrans)
|
||||
dn_nsp_output(sk);
|
||||
|
||||
return wakeup;
|
||||
}
|
||||
|
||||
void dn_nsp_send_data_ack(struct sock *sk)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
if ((skb = dn_alloc_skb(sk, 9, GFP_ATOMIC)) == NULL)
|
||||
return;
|
||||
|
||||
skb_reserve(skb, 9);
|
||||
dn_mk_ack_header(sk, skb, 0x04, 9, 0);
|
||||
dn_nsp_send(skb);
|
||||
}
|
||||
|
||||
void dn_nsp_send_oth_ack(struct sock *sk)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
if ((skb = dn_alloc_skb(sk, 9, GFP_ATOMIC)) == NULL)
|
||||
return;
|
||||
|
||||
skb_reserve(skb, 9);
|
||||
dn_mk_ack_header(sk, skb, 0x14, 9, 1);
|
||||
dn_nsp_send(skb);
|
||||
}
|
||||
|
||||
|
||||
void dn_send_conn_ack (struct sock *sk)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct sk_buff *skb = NULL;
|
||||
struct nsp_conn_ack_msg *msg;
|
||||
|
||||
if ((skb = dn_alloc_skb(sk, 3, sk->sk_allocation)) == NULL)
|
||||
return;
|
||||
|
||||
msg = skb_put(skb, 3);
|
||||
msg->msgflg = 0x24;
|
||||
msg->dstaddr = scp->addrrem;
|
||||
|
||||
dn_nsp_send(skb);
|
||||
}
|
||||
|
||||
static int dn_nsp_retrans_conn_conf(struct sock *sk)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
if (scp->state == DN_CC)
|
||||
dn_send_conn_conf(sk, GFP_ATOMIC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dn_send_conn_conf(struct sock *sk, gfp_t gfp)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct sk_buff *skb = NULL;
|
||||
struct nsp_conn_init_msg *msg;
|
||||
__u8 len = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
|
||||
|
||||
if ((skb = dn_alloc_skb(sk, 50 + len, gfp)) == NULL)
|
||||
return;
|
||||
|
||||
msg = skb_put(skb, sizeof(*msg));
|
||||
msg->msgflg = 0x28;
|
||||
msg->dstaddr = scp->addrrem;
|
||||
msg->srcaddr = scp->addrloc;
|
||||
msg->services = scp->services_loc;
|
||||
msg->info = scp->info_loc;
|
||||
msg->segsize = cpu_to_le16(scp->segsize_loc);
|
||||
|
||||
skb_put_u8(skb, len);
|
||||
|
||||
if (len > 0)
|
||||
skb_put_data(skb, scp->conndata_out.opt_data, len);
|
||||
|
||||
|
||||
dn_nsp_send(skb);
|
||||
|
||||
scp->persist = dn_nsp_persist(sk);
|
||||
scp->persist_fxn = dn_nsp_retrans_conn_conf;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
|
||||
unsigned short reason, gfp_t gfp,
|
||||
struct dst_entry *dst,
|
||||
int ddl, unsigned char *dd, __le16 rem, __le16 loc)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0);
|
||||
unsigned char *msg;
|
||||
|
||||
if ((dst == NULL) || (rem == 0)) {
|
||||
net_dbg_ratelimited("DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n",
|
||||
le16_to_cpu(rem), dst);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((skb = dn_alloc_skb(sk, size, gfp)) == NULL)
|
||||
return;
|
||||
|
||||
msg = skb_put(skb, size);
|
||||
*msg++ = msgflg;
|
||||
*(__le16 *)msg = rem;
|
||||
msg += 2;
|
||||
*(__le16 *)msg = loc;
|
||||
msg += 2;
|
||||
*(__le16 *)msg = cpu_to_le16(reason);
|
||||
msg += 2;
|
||||
if (msgflg == NSP_DISCINIT)
|
||||
*msg++ = ddl;
|
||||
|
||||
if (ddl) {
|
||||
memcpy(msg, dd, ddl);
|
||||
}
|
||||
|
||||
/*
|
||||
* This doesn't go via the dn_nsp_send() function since we need
|
||||
* to be able to send disc packets out which have no socket
|
||||
* associations.
|
||||
*/
|
||||
skb_dst_set(skb, dst_clone(dst));
|
||||
dst_output(&init_net, skb->sk, skb);
|
||||
}
|
||||
|
||||
|
||||
void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg,
|
||||
unsigned short reason, gfp_t gfp)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
int ddl = 0;
|
||||
|
||||
if (msgflg == NSP_DISCINIT)
|
||||
ddl = le16_to_cpu(scp->discdata_out.opt_optl);
|
||||
|
||||
if (reason == 0)
|
||||
reason = le16_to_cpu(scp->discdata_out.opt_status);
|
||||
|
||||
dn_nsp_do_disc(sk, msgflg, reason, gfp, __sk_dst_get(sk), ddl,
|
||||
scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
|
||||
}
|
||||
|
||||
|
||||
void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg,
|
||||
unsigned short reason)
|
||||
{
|
||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||
int ddl = 0;
|
||||
gfp_t gfp = GFP_ATOMIC;
|
||||
|
||||
dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb_dst(skb), ddl,
|
||||
NULL, cb->src_port, cb->dst_port);
|
||||
}
|
||||
|
||||
|
||||
void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct sk_buff *skb;
|
||||
unsigned char *ptr;
|
||||
gfp_t gfp = GFP_ATOMIC;
|
||||
|
||||
if ((skb = dn_alloc_skb(sk, DN_MAX_NSP_DATA_HEADER + 2, gfp)) == NULL)
|
||||
return;
|
||||
|
||||
skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
|
||||
ptr = skb_put(skb, 2);
|
||||
DN_SKB_CB(skb)->nsp_flags = 0x10;
|
||||
*ptr++ = lsflags;
|
||||
*ptr = fcval;
|
||||
|
||||
dn_nsp_queue_xmit(sk, skb, gfp, 1);
|
||||
|
||||
scp->persist = dn_nsp_persist(sk);
|
||||
scp->persist_fxn = dn_nsp_xmit_timeout;
|
||||
}
|
||||
|
||||
static int dn_nsp_retrans_conninit(struct sock *sk)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
if (scp->state == DN_CI)
|
||||
dn_nsp_send_conninit(sk, NSP_RCI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
|
||||
{
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
struct nsp_conn_init_msg *msg;
|
||||
unsigned char aux;
|
||||
unsigned char menuver;
|
||||
struct dn_skb_cb *cb;
|
||||
unsigned char type = 1;
|
||||
gfp_t allocation = (msgflg == NSP_CI) ? sk->sk_allocation : GFP_ATOMIC;
|
||||
struct sk_buff *skb = dn_alloc_skb(sk, 200, allocation);
|
||||
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
cb = DN_SKB_CB(skb);
|
||||
msg = skb_put(skb, sizeof(*msg));
|
||||
|
||||
msg->msgflg = msgflg;
|
||||
msg->dstaddr = 0x0000; /* Remote Node will assign it*/
|
||||
|
||||
msg->srcaddr = scp->addrloc;
|
||||
msg->services = scp->services_loc; /* Requested flow control */
|
||||
msg->info = scp->info_loc; /* Version Number */
|
||||
msg->segsize = cpu_to_le16(scp->segsize_loc); /* Max segment size */
|
||||
|
||||
if (scp->peer.sdn_objnum)
|
||||
type = 0;
|
||||
|
||||
skb_put(skb, dn_sockaddr2username(&scp->peer,
|
||||
skb_tail_pointer(skb), type));
|
||||
skb_put(skb, dn_sockaddr2username(&scp->addr,
|
||||
skb_tail_pointer(skb), 2));
|
||||
|
||||
menuver = DN_MENUVER_ACC | DN_MENUVER_USR;
|
||||
if (scp->peer.sdn_flags & SDF_PROXY)
|
||||
menuver |= DN_MENUVER_PRX;
|
||||
if (scp->peer.sdn_flags & SDF_UICPROXY)
|
||||
menuver |= DN_MENUVER_UIC;
|
||||
|
||||
skb_put_u8(skb, menuver); /* Menu Version */
|
||||
|
||||
aux = scp->accessdata.acc_userl;
|
||||
skb_put_u8(skb, aux);
|
||||
if (aux > 0)
|
||||
skb_put_data(skb, scp->accessdata.acc_user, aux);
|
||||
|
||||
aux = scp->accessdata.acc_passl;
|
||||
skb_put_u8(skb, aux);
|
||||
if (aux > 0)
|
||||
skb_put_data(skb, scp->accessdata.acc_pass, aux);
|
||||
|
||||
aux = scp->accessdata.acc_accl;
|
||||
skb_put_u8(skb, aux);
|
||||
if (aux > 0)
|
||||
skb_put_data(skb, scp->accessdata.acc_acc, aux);
|
||||
|
||||
aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
|
||||
skb_put_u8(skb, aux);
|
||||
if (aux > 0)
|
||||
skb_put_data(skb, scp->conndata_out.opt_data, aux);
|
||||
|
||||
scp->persist = dn_nsp_persist(sk);
|
||||
scp->persist_fxn = dn_nsp_retrans_conninit;
|
||||
|
||||
cb->rt_flags = DN_RT_F_RQR;
|
||||
|
||||
dn_nsp_send(skb);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,258 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* DECnet An implementation of the DECnet protocol suite for the LINUX
|
||||
* operating system. DECnet is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DECnet Routing Forwarding Information Base (Rules)
|
||||
*
|
||||
* Author: Steve Whitehouse <SteveW@ACM.org>
|
||||
* Mostly copied from Alexey Kuznetsov's ipv4/fib_rules.c
|
||||
*
|
||||
*
|
||||
* Changes:
|
||||
* Steve Whitehouse <steve@chygwyn.com>
|
||||
* Updated for Thomas Graf's generic rules
|
||||
*
|
||||
*/
|
||||
#include <linux/net.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/export.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/fib_rules.h>
|
||||
#include <net/dn.h>
|
||||
#include <net/dn_fib.h>
|
||||
#include <net/dn_neigh.h>
|
||||
#include <net/dn_dev.h>
|
||||
#include <net/dn_route.h>
|
||||
|
||||
static struct fib_rules_ops *dn_fib_rules_ops;
|
||||
|
||||
struct dn_fib_rule
|
||||
{
|
||||
struct fib_rule common;
|
||||
unsigned char dst_len;
|
||||
unsigned char src_len;
|
||||
__le16 src;
|
||||
__le16 srcmask;
|
||||
__le16 dst;
|
||||
__le16 dstmask;
|
||||
__le16 srcmap;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
|
||||
int dn_fib_lookup(struct flowidn *flp, struct dn_fib_res *res)
|
||||
{
|
||||
struct fib_lookup_arg arg = {
|
||||
.result = res,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = fib_rules_lookup(dn_fib_rules_ops,
|
||||
flowidn_to_flowi(flp), 0, &arg);
|
||||
res->r = arg.rule;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp,
|
||||
int flags, struct fib_lookup_arg *arg)
|
||||
{
|
||||
struct flowidn *fld = &flp->u.dn;
|
||||
int err = -EAGAIN;
|
||||
struct dn_fib_table *tbl;
|
||||
|
||||
switch(rule->action) {
|
||||
case FR_ACT_TO_TBL:
|
||||
break;
|
||||
|
||||
case FR_ACT_UNREACHABLE:
|
||||
err = -ENETUNREACH;
|
||||
goto errout;
|
||||
|
||||
case FR_ACT_PROHIBIT:
|
||||
err = -EACCES;
|
||||
goto errout;
|
||||
|
||||
case FR_ACT_BLACKHOLE:
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tbl = dn_fib_get_table(rule->table, 0);
|
||||
if (tbl == NULL)
|
||||
goto errout;
|
||||
|
||||
err = tbl->lookup(tbl, fld, (struct dn_fib_res *)arg->result);
|
||||
if (err > 0)
|
||||
err = -EAGAIN;
|
||||
errout:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct nla_policy dn_fib_rule_policy[FRA_MAX+1] = {
|
||||
FRA_GENERIC_POLICY,
|
||||
};
|
||||
|
||||
static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
|
||||
{
|
||||
struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
|
||||
struct flowidn *fld = &fl->u.dn;
|
||||
__le16 daddr = fld->daddr;
|
||||
__le16 saddr = fld->saddr;
|
||||
|
||||
if (((saddr ^ r->src) & r->srcmask) ||
|
||||
((daddr ^ r->dst) & r->dstmask))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
|
||||
struct fib_rule_hdr *frh,
|
||||
struct nlattr **tb,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
|
||||
|
||||
if (frh->tos) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid tos value");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (rule->table == RT_TABLE_UNSPEC) {
|
||||
if (rule->action == FR_ACT_TO_TBL) {
|
||||
struct dn_fib_table *table;
|
||||
|
||||
table = dn_fib_empty_table();
|
||||
if (table == NULL) {
|
||||
err = -ENOBUFS;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rule->table = table->n;
|
||||
}
|
||||
}
|
||||
|
||||
if (frh->src_len)
|
||||
r->src = nla_get_le16(tb[FRA_SRC]);
|
||||
|
||||
if (frh->dst_len)
|
||||
r->dst = nla_get_le16(tb[FRA_DST]);
|
||||
|
||||
r->src_len = frh->src_len;
|
||||
r->srcmask = dnet_make_mask(r->src_len);
|
||||
r->dst_len = frh->dst_len;
|
||||
r->dstmask = dnet_make_mask(r->dst_len);
|
||||
err = 0;
|
||||
errout:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
|
||||
struct nlattr **tb)
|
||||
{
|
||||
struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
|
||||
|
||||
if (frh->src_len && (r->src_len != frh->src_len))
|
||||
return 0;
|
||||
|
||||
if (frh->dst_len && (r->dst_len != frh->dst_len))
|
||||
return 0;
|
||||
|
||||
if (frh->src_len && (r->src != nla_get_le16(tb[FRA_SRC])))
|
||||
return 0;
|
||||
|
||||
if (frh->dst_len && (r->dst != nla_get_le16(tb[FRA_DST])))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int dnet_addr_type(__le16 addr)
|
||||
{
|
||||
struct flowidn fld = { .daddr = addr };
|
||||
struct dn_fib_res res;
|
||||
unsigned int ret = RTN_UNICAST;
|
||||
struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0);
|
||||
|
||||
res.r = NULL;
|
||||
|
||||
if (tb) {
|
||||
if (!tb->lookup(tb, &fld, &res)) {
|
||||
ret = res.type;
|
||||
dn_fib_res_put(&res);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
|
||||
struct fib_rule_hdr *frh)
|
||||
{
|
||||
struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
|
||||
|
||||
frh->dst_len = r->dst_len;
|
||||
frh->src_len = r->src_len;
|
||||
frh->tos = 0;
|
||||
|
||||
if ((r->dst_len &&
|
||||
nla_put_le16(skb, FRA_DST, r->dst)) ||
|
||||
(r->src_len &&
|
||||
nla_put_le16(skb, FRA_SRC, r->src)))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static void dn_fib_rule_flush_cache(struct fib_rules_ops *ops)
|
||||
{
|
||||
dn_rt_cache_flush(-1);
|
||||
}
|
||||
|
||||
static const struct fib_rules_ops __net_initconst dn_fib_rules_ops_template = {
|
||||
.family = AF_DECnet,
|
||||
.rule_size = sizeof(struct dn_fib_rule),
|
||||
.addr_size = sizeof(u16),
|
||||
.action = dn_fib_rule_action,
|
||||
.match = dn_fib_rule_match,
|
||||
.configure = dn_fib_rule_configure,
|
||||
.compare = dn_fib_rule_compare,
|
||||
.fill = dn_fib_rule_fill,
|
||||
.flush_cache = dn_fib_rule_flush_cache,
|
||||
.nlgroup = RTNLGRP_DECnet_RULE,
|
||||
.policy = dn_fib_rule_policy,
|
||||
.owner = THIS_MODULE,
|
||||
.fro_net = &init_net,
|
||||
};
|
||||
|
||||
void __init dn_fib_rules_init(void)
|
||||
{
|
||||
dn_fib_rules_ops =
|
||||
fib_rules_register(&dn_fib_rules_ops_template, &init_net);
|
||||
BUG_ON(IS_ERR(dn_fib_rules_ops));
|
||||
BUG_ON(fib_default_rule_add(dn_fib_rules_ops, 0x7fff,
|
||||
RT_TABLE_MAIN, 0));
|
||||
}
|
||||
|
||||
void __exit dn_fib_rules_cleanup(void)
|
||||
{
|
||||
rtnl_lock();
|
||||
fib_rules_unregister(dn_fib_rules_ops);
|
||||
rtnl_unlock();
|
||||
rcu_barrier();
|
||||
}
|
@ -1,929 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DECnet An implementation of the DECnet protocol suite for the LINUX
|
||||
* operating system. DECnet is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DECnet Routing Forwarding Information Base (Routing Tables)
|
||||
*
|
||||
* Author: Steve Whitehouse <SteveW@ACM.org>
|
||||
* Mostly copied from the IPv4 routing code
|
||||
*
|
||||
*
|
||||
* Changes:
|
||||
*
|
||||
*/
|
||||
#include <linux/string.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/route.h> /* RTF_xxx */
|
||||
#include <net/neighbour.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/fib_rules.h>
|
||||
#include <net/dn.h>
|
||||
#include <net/dn_route.h>
|
||||
#include <net/dn_fib.h>
|
||||
#include <net/dn_neigh.h>
|
||||
#include <net/dn_dev.h>
|
||||
|
||||
struct dn_zone
|
||||
{
|
||||
struct dn_zone *dz_next;
|
||||
struct dn_fib_node **dz_hash;
|
||||
int dz_nent;
|
||||
int dz_divisor;
|
||||
u32 dz_hashmask;
|
||||
#define DZ_HASHMASK(dz) ((dz)->dz_hashmask)
|
||||
int dz_order;
|
||||
__le16 dz_mask;
|
||||
#define DZ_MASK(dz) ((dz)->dz_mask)
|
||||
};
|
||||
|
||||
struct dn_hash
|
||||
{
|
||||
struct dn_zone *dh_zones[17];
|
||||
struct dn_zone *dh_zone_list;
|
||||
};
|
||||
|
||||
#define dz_key_0(key) ((key).datum = 0)
|
||||
|
||||
#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
|
||||
for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
|
||||
|
||||
#define endfor_nexthops(fi) }
|
||||
|
||||
#define DN_MAX_DIVISOR 1024
|
||||
#define DN_S_ZOMBIE 1
|
||||
#define DN_S_ACCESSED 2
|
||||
|
||||
#define DN_FIB_SCAN(f, fp) \
|
||||
for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
|
||||
|
||||
#define DN_FIB_SCAN_KEY(f, fp, key) \
|
||||
for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
|
||||
|
||||
#define RT_TABLE_MIN 1
|
||||
#define DN_FIB_TABLE_HASHSZ 256
|
||||
static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ];
|
||||
static DEFINE_RWLOCK(dn_fib_tables_lock);
|
||||
|
||||
static struct kmem_cache *dn_hash_kmem __read_mostly;
|
||||
static int dn_fib_hash_zombies;
|
||||
|
||||
static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
|
||||
{
|
||||
u16 h = le16_to_cpu(key.datum)>>(16 - dz->dz_order);
|
||||
h ^= (h >> 10);
|
||||
h ^= (h >> 6);
|
||||
h &= DZ_HASHMASK(dz);
|
||||
return *(dn_fib_idx_t *)&h;
|
||||
}
|
||||
|
||||
static inline dn_fib_key_t dz_key(__le16 dst, struct dn_zone *dz)
|
||||
{
|
||||
dn_fib_key_t k;
|
||||
k.datum = dst & DZ_MASK(dz);
|
||||
return k;
|
||||
}
|
||||
|
||||
static inline struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz)
|
||||
{
|
||||
return &dz->dz_hash[dn_hash(key, dz).datum];
|
||||
}
|
||||
|
||||
static inline struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz)
|
||||
{
|
||||
return dz->dz_hash[dn_hash(key, dz).datum];
|
||||
}
|
||||
|
||||
static inline int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b)
|
||||
{
|
||||
return a.datum == b.datum;
|
||||
}
|
||||
|
||||
static inline int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b)
|
||||
{
|
||||
return a.datum <= b.datum;
|
||||
}
|
||||
|
||||
static inline void dn_rebuild_zone(struct dn_zone *dz,
|
||||
struct dn_fib_node **old_ht,
|
||||
int old_divisor)
|
||||
{
|
||||
struct dn_fib_node *f, **fp, *next;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < old_divisor; i++) {
|
||||
for(f = old_ht[i]; f; f = next) {
|
||||
next = f->fn_next;
|
||||
for(fp = dn_chain_p(f->fn_key, dz);
|
||||
*fp && dn_key_leq((*fp)->fn_key, f->fn_key);
|
||||
fp = &(*fp)->fn_next)
|
||||
/* NOTHING */;
|
||||
f->fn_next = *fp;
|
||||
*fp = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dn_rehash_zone(struct dn_zone *dz)
|
||||
{
|
||||
struct dn_fib_node **ht, **old_ht;
|
||||
int old_divisor, new_divisor;
|
||||
u32 new_hashmask;
|
||||
|
||||
old_divisor = dz->dz_divisor;
|
||||
|
||||
switch (old_divisor) {
|
||||
case 16:
|
||||
new_divisor = 256;
|
||||
new_hashmask = 0xFF;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d\n",
|
||||
old_divisor);
|
||||
/* fall through */
|
||||
case 256:
|
||||
new_divisor = 1024;
|
||||
new_hashmask = 0x3FF;
|
||||
break;
|
||||
}
|
||||
|
||||
ht = kcalloc(new_divisor, sizeof(struct dn_fib_node*), GFP_KERNEL);
|
||||
if (ht == NULL)
|
||||
return;
|
||||
|
||||
write_lock_bh(&dn_fib_tables_lock);
|
||||
old_ht = dz->dz_hash;
|
||||
dz->dz_hash = ht;
|
||||
dz->dz_hashmask = new_hashmask;
|
||||
dz->dz_divisor = new_divisor;
|
||||
dn_rebuild_zone(dz, old_ht, old_divisor);
|
||||
write_unlock_bh(&dn_fib_tables_lock);
|
||||
kfree(old_ht);
|
||||
}
|
||||
|
||||
static void dn_free_node(struct dn_fib_node *f)
|
||||
{
|
||||
dn_fib_release_info(DN_FIB_INFO(f));
|
||||
kmem_cache_free(dn_hash_kmem, f);
|
||||
}
|
||||
|
||||
|
||||
static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
|
||||
{
|
||||
int i;
|
||||
struct dn_zone *dz = kzalloc(sizeof(struct dn_zone), GFP_KERNEL);
|
||||
if (!dz)
|
||||
return NULL;
|
||||
|
||||
if (z) {
|
||||
dz->dz_divisor = 16;
|
||||
dz->dz_hashmask = 0x0F;
|
||||
} else {
|
||||
dz->dz_divisor = 1;
|
||||
dz->dz_hashmask = 0;
|
||||
}
|
||||
|
||||
dz->dz_hash = kcalloc(dz->dz_divisor, sizeof(struct dn_fib_node *), GFP_KERNEL);
|
||||
if (!dz->dz_hash) {
|
||||
kfree(dz);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dz->dz_order = z;
|
||||
dz->dz_mask = dnet_make_mask(z);
|
||||
|
||||
for(i = z + 1; i <= 16; i++)
|
||||
if (table->dh_zones[i])
|
||||
break;
|
||||
|
||||
write_lock_bh(&dn_fib_tables_lock);
|
||||
if (i>16) {
|
||||
dz->dz_next = table->dh_zone_list;
|
||||
table->dh_zone_list = dz;
|
||||
} else {
|
||||
dz->dz_next = table->dh_zones[i]->dz_next;
|
||||
table->dh_zones[i]->dz_next = dz;
|
||||
}
|
||||
table->dh_zones[z] = dz;
|
||||
write_unlock_bh(&dn_fib_tables_lock);
|
||||
return dz;
|
||||
}
|
||||
|
||||
|
||||
static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct nlattr *attrs[], struct dn_fib_info *fi)
|
||||
{
|
||||
struct rtnexthop *nhp;
|
||||
int nhlen;
|
||||
|
||||
if (attrs[RTA_PRIORITY] &&
|
||||
nla_get_u32(attrs[RTA_PRIORITY]) != fi->fib_priority)
|
||||
return 1;
|
||||
|
||||
if (attrs[RTA_OIF] || attrs[RTA_GATEWAY]) {
|
||||
if ((!attrs[RTA_OIF] || nla_get_u32(attrs[RTA_OIF]) == fi->fib_nh->nh_oif) &&
|
||||
(!attrs[RTA_GATEWAY] || nla_get_le16(attrs[RTA_GATEWAY]) != fi->fib_nh->nh_gw))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!attrs[RTA_MULTIPATH])
|
||||
return 0;
|
||||
|
||||
nhp = nla_data(attrs[RTA_MULTIPATH]);
|
||||
nhlen = nla_len(attrs[RTA_MULTIPATH]);
|
||||
|
||||
for_nexthops(fi) {
|
||||
int attrlen = nhlen - sizeof(struct rtnexthop);
|
||||
__le16 gw;
|
||||
|
||||
if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
|
||||
return -EINVAL;
|
||||
if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
|
||||
return 1;
|
||||
if (attrlen) {
|
||||
struct nlattr *gw_attr;
|
||||
|
||||
gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
|
||||
gw = gw_attr ? nla_get_le16(gw_attr) : 0;
|
||||
|
||||
if (gw && gw != nh->nh_gw)
|
||||
return 1;
|
||||
}
|
||||
nhp = RTNH_NEXT(nhp);
|
||||
} endfor_nexthops(fi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi)
|
||||
{
|
||||
size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg))
|
||||
+ nla_total_size(4) /* RTA_TABLE */
|
||||
+ nla_total_size(2) /* RTA_DST */
|
||||
+ nla_total_size(4) /* RTA_PRIORITY */
|
||||
+ nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
|
||||
|
||||
/* space for nested metrics */
|
||||
payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
|
||||
|
||||
if (fi->fib_nhs) {
|
||||
/* Also handles the special case fib_nhs == 1 */
|
||||
|
||||
/* each nexthop is packed in an attribute */
|
||||
size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
|
||||
|
||||
/* may contain a gateway attribute */
|
||||
nhsize += nla_total_size(4);
|
||||
|
||||
/* all nexthops are packed in a nested attribute */
|
||||
payload += nla_total_size(fi->fib_nhs * nhsize);
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
static int dn_fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
|
||||
u32 tb_id, u8 type, u8 scope, void *dst, int dst_len,
|
||||
struct dn_fib_info *fi, unsigned int flags)
|
||||
{
|
||||
struct rtmsg *rtm;
|
||||
struct nlmsghdr *nlh;
|
||||
|
||||
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags);
|
||||
if (!nlh)
|
||||
return -EMSGSIZE;
|
||||
|
||||
rtm = nlmsg_data(nlh);
|
||||
rtm->rtm_family = AF_DECnet;
|
||||
rtm->rtm_dst_len = dst_len;
|
||||
rtm->rtm_src_len = 0;
|
||||
rtm->rtm_tos = 0;
|
||||
rtm->rtm_table = tb_id;
|
||||
rtm->rtm_flags = fi->fib_flags;
|
||||
rtm->rtm_scope = scope;
|
||||
rtm->rtm_type = type;
|
||||
rtm->rtm_protocol = fi->fib_protocol;
|
||||
|
||||
if (nla_put_u32(skb, RTA_TABLE, tb_id) < 0)
|
||||
goto errout;
|
||||
|
||||
if (rtm->rtm_dst_len &&
|
||||
nla_put(skb, RTA_DST, 2, dst) < 0)
|
||||
goto errout;
|
||||
|
||||
if (fi->fib_priority &&
|
||||
nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority) < 0)
|
||||
goto errout;
|
||||
|
||||
if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
|
||||
goto errout;
|
||||
|
||||
if (fi->fib_nhs == 1) {
|
||||
if (fi->fib_nh->nh_gw &&
|
||||
nla_put_le16(skb, RTA_GATEWAY, fi->fib_nh->nh_gw) < 0)
|
||||
goto errout;
|
||||
|
||||
if (fi->fib_nh->nh_oif &&
|
||||
nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif) < 0)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (fi->fib_nhs > 1) {
|
||||
struct rtnexthop *nhp;
|
||||
struct nlattr *mp_head;
|
||||
|
||||
mp_head = nla_nest_start_noflag(skb, RTA_MULTIPATH);
|
||||
if (!mp_head)
|
||||
goto errout;
|
||||
|
||||
for_nexthops(fi) {
|
||||
if (!(nhp = nla_reserve_nohdr(skb, sizeof(*nhp))))
|
||||
goto errout;
|
||||
|
||||
nhp->rtnh_flags = nh->nh_flags & 0xFF;
|
||||
nhp->rtnh_hops = nh->nh_weight - 1;
|
||||
nhp->rtnh_ifindex = nh->nh_oif;
|
||||
|
||||
if (nh->nh_gw &&
|
||||
nla_put_le16(skb, RTA_GATEWAY, nh->nh_gw) < 0)
|
||||
goto errout;
|
||||
|
||||
nhp->rtnh_len = skb_tail_pointer(skb) - (unsigned char *)nhp;
|
||||
} endfor_nexthops(fi);
|
||||
|
||||
nla_nest_end(skb, mp_head);
|
||||
}
|
||||
|
||||
nlmsg_end(skb, nlh);
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
nlmsg_cancel(skb, nlh);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
|
||||
static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
|
||||
struct nlmsghdr *nlh, struct netlink_skb_parms *req)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 portid = req ? req->portid : 0;
|
||||
int err = -ENOBUFS;
|
||||
|
||||
skb = nlmsg_new(dn_fib_nlmsg_size(DN_FIB_INFO(f)), GFP_KERNEL);
|
||||
if (skb == NULL)
|
||||
goto errout;
|
||||
|
||||
err = dn_fib_dump_info(skb, portid, nlh->nlmsg_seq, event, tb_id,
|
||||
f->fn_type, f->fn_scope, &f->fn_key, z,
|
||||
DN_FIB_INFO(f), 0);
|
||||
if (err < 0) {
|
||||
/* -EMSGSIZE implies BUG in dn_fib_nlmsg_size() */
|
||||
WARN_ON(err == -EMSGSIZE);
|
||||
kfree_skb(skb);
|
||||
goto errout;
|
||||
}
|
||||
rtnl_notify(skb, &init_net, portid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
|
||||
return;
|
||||
errout:
|
||||
if (err < 0)
|
||||
rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
|
||||
}
|
||||
|
||||
static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
struct dn_fib_table *tb,
|
||||
struct dn_zone *dz,
|
||||
struct dn_fib_node *f)
|
||||
{
|
||||
int i, s_i;
|
||||
|
||||
s_i = cb->args[4];
|
||||
for(i = 0; f; i++, f = f->fn_next) {
|
||||
if (i < s_i)
|
||||
continue;
|
||||
if (f->fn_state & DN_S_ZOMBIE)
|
||||
continue;
|
||||
if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
RTM_NEWROUTE,
|
||||
tb->n,
|
||||
(f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
|
||||
f->fn_scope, &f->fn_key, dz->dz_order,
|
||||
f->fn_info, NLM_F_MULTI) < 0) {
|
||||
cb->args[4] = i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
cb->args[4] = i;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
struct dn_fib_table *tb,
|
||||
struct dn_zone *dz)
|
||||
{
|
||||
int h, s_h;
|
||||
|
||||
s_h = cb->args[3];
|
||||
for(h = 0; h < dz->dz_divisor; h++) {
|
||||
if (h < s_h)
|
||||
continue;
|
||||
if (h > s_h)
|
||||
memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0]));
|
||||
if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
|
||||
continue;
|
||||
if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
|
||||
cb->args[3] = h;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
cb->args[3] = h;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
int m, s_m;
|
||||
struct dn_zone *dz;
|
||||
struct dn_hash *table = (struct dn_hash *)tb->data;
|
||||
|
||||
s_m = cb->args[2];
|
||||
read_lock(&dn_fib_tables_lock);
|
||||
for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
|
||||
if (m < s_m)
|
||||
continue;
|
||||
if (m > s_m)
|
||||
memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
|
||||
|
||||
if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
|
||||
cb->args[2] = m;
|
||||
read_unlock(&dn_fib_tables_lock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
read_unlock(&dn_fib_tables_lock);
|
||||
cb->args[2] = m;
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
unsigned int h, s_h;
|
||||
unsigned int e = 0, s_e;
|
||||
struct dn_fib_table *tb;
|
||||
int dumped = 0;
|
||||
|
||||
if (!net_eq(net, &init_net))
|
||||
return 0;
|
||||
|
||||
if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
|
||||
((struct rtmsg *)nlmsg_data(cb->nlh))->rtm_flags&RTM_F_CLONED)
|
||||
return dn_cache_dump(skb, cb);
|
||||
|
||||
s_h = cb->args[0];
|
||||
s_e = cb->args[1];
|
||||
|
||||
for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) {
|
||||
e = 0;
|
||||
hlist_for_each_entry(tb, &dn_fib_table_hash[h], hlist) {
|
||||
if (e < s_e)
|
||||
goto next;
|
||||
if (dumped)
|
||||
memset(&cb->args[2], 0, sizeof(cb->args) -
|
||||
2 * sizeof(cb->args[0]));
|
||||
if (tb->dump(tb, skb, cb) < 0)
|
||||
goto out;
|
||||
dumped = 1;
|
||||
next:
|
||||
e++;
|
||||
}
|
||||
}
|
||||
out:
|
||||
cb->args[1] = e;
|
||||
cb->args[0] = h;
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
|
||||
struct nlmsghdr *n, struct netlink_skb_parms *req)
|
||||
{
|
||||
struct dn_hash *table = (struct dn_hash *)tb->data;
|
||||
struct dn_fib_node *new_f, *f, **fp, **del_fp;
|
||||
struct dn_zone *dz;
|
||||
struct dn_fib_info *fi;
|
||||
int z = r->rtm_dst_len;
|
||||
int type = r->rtm_type;
|
||||
dn_fib_key_t key;
|
||||
int err;
|
||||
|
||||
if (z > 16)
|
||||
return -EINVAL;
|
||||
|
||||
dz = table->dh_zones[z];
|
||||
if (!dz && !(dz = dn_new_zone(table, z)))
|
||||
return -ENOBUFS;
|
||||
|
||||
dz_key_0(key);
|
||||
if (attrs[RTA_DST]) {
|
||||
__le16 dst = nla_get_le16(attrs[RTA_DST]);
|
||||
if (dst & ~DZ_MASK(dz))
|
||||
return -EINVAL;
|
||||
key = dz_key(dst, dz);
|
||||
}
|
||||
|
||||
if ((fi = dn_fib_create_info(r, attrs, n, &err)) == NULL)
|
||||
return err;
|
||||
|
||||
if (dz->dz_nent > (dz->dz_divisor << 2) &&
|
||||
dz->dz_divisor > DN_MAX_DIVISOR &&
|
||||
(z==16 || (1<<z) > dz->dz_divisor))
|
||||
dn_rehash_zone(dz);
|
||||
|
||||
fp = dn_chain_p(key, dz);
|
||||
|
||||
DN_FIB_SCAN(f, fp) {
|
||||
if (dn_key_leq(key, f->fn_key))
|
||||
break;
|
||||
}
|
||||
|
||||
del_fp = NULL;
|
||||
|
||||
if (f && (f->fn_state & DN_S_ZOMBIE) &&
|
||||
dn_key_eq(f->fn_key, key)) {
|
||||
del_fp = fp;
|
||||
fp = &f->fn_next;
|
||||
f = *fp;
|
||||
goto create;
|
||||
}
|
||||
|
||||
DN_FIB_SCAN_KEY(f, fp, key) {
|
||||
if (fi->fib_priority <= DN_FIB_INFO(f)->fib_priority)
|
||||
break;
|
||||
}
|
||||
|
||||
if (f && dn_key_eq(f->fn_key, key) &&
|
||||
fi->fib_priority == DN_FIB_INFO(f)->fib_priority) {
|
||||
struct dn_fib_node **ins_fp;
|
||||
|
||||
err = -EEXIST;
|
||||
if (n->nlmsg_flags & NLM_F_EXCL)
|
||||
goto out;
|
||||
|
||||
if (n->nlmsg_flags & NLM_F_REPLACE) {
|
||||
del_fp = fp;
|
||||
fp = &f->fn_next;
|
||||
f = *fp;
|
||||
goto replace;
|
||||
}
|
||||
|
||||
ins_fp = fp;
|
||||
err = -EEXIST;
|
||||
|
||||
DN_FIB_SCAN_KEY(f, fp, key) {
|
||||
if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority)
|
||||
break;
|
||||
if (f->fn_type == type &&
|
||||
f->fn_scope == r->rtm_scope &&
|
||||
DN_FIB_INFO(f) == fi)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(n->nlmsg_flags & NLM_F_APPEND)) {
|
||||
fp = ins_fp;
|
||||
f = *fp;
|
||||
}
|
||||
}
|
||||
|
||||
create:
|
||||
err = -ENOENT;
|
||||
if (!(n->nlmsg_flags & NLM_F_CREATE))
|
||||
goto out;
|
||||
|
||||
replace:
|
||||
err = -ENOBUFS;
|
||||
new_f = kmem_cache_zalloc(dn_hash_kmem, GFP_KERNEL);
|
||||
if (new_f == NULL)
|
||||
goto out;
|
||||
|
||||
new_f->fn_key = key;
|
||||
new_f->fn_type = type;
|
||||
new_f->fn_scope = r->rtm_scope;
|
||||
DN_FIB_INFO(new_f) = fi;
|
||||
|
||||
new_f->fn_next = f;
|
||||
write_lock_bh(&dn_fib_tables_lock);
|
||||
*fp = new_f;
|
||||
write_unlock_bh(&dn_fib_tables_lock);
|
||||
dz->dz_nent++;
|
||||
|
||||
if (del_fp) {
|
||||
f = *del_fp;
|
||||
write_lock_bh(&dn_fib_tables_lock);
|
||||
*del_fp = f->fn_next;
|
||||
write_unlock_bh(&dn_fib_tables_lock);
|
||||
|
||||
if (!(f->fn_state & DN_S_ZOMBIE))
|
||||
dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
|
||||
if (f->fn_state & DN_S_ACCESSED)
|
||||
dn_rt_cache_flush(-1);
|
||||
dn_free_node(f);
|
||||
dz->dz_nent--;
|
||||
} else {
|
||||
dn_rt_cache_flush(-1);
|
||||
}
|
||||
|
||||
dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
dn_fib_release_info(fi);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
|
||||
struct nlmsghdr *n, struct netlink_skb_parms *req)
|
||||
{
|
||||
struct dn_hash *table = (struct dn_hash*)tb->data;
|
||||
struct dn_fib_node **fp, **del_fp, *f;
|
||||
int z = r->rtm_dst_len;
|
||||
struct dn_zone *dz;
|
||||
dn_fib_key_t key;
|
||||
int matched;
|
||||
|
||||
|
||||
if (z > 16)
|
||||
return -EINVAL;
|
||||
|
||||
if ((dz = table->dh_zones[z]) == NULL)
|
||||
return -ESRCH;
|
||||
|
||||
dz_key_0(key);
|
||||
if (attrs[RTA_DST]) {
|
||||
__le16 dst = nla_get_le16(attrs[RTA_DST]);
|
||||
if (dst & ~DZ_MASK(dz))
|
||||
return -EINVAL;
|
||||
key = dz_key(dst, dz);
|
||||
}
|
||||
|
||||
fp = dn_chain_p(key, dz);
|
||||
|
||||
DN_FIB_SCAN(f, fp) {
|
||||
if (dn_key_eq(f->fn_key, key))
|
||||
break;
|
||||
if (dn_key_leq(key, f->fn_key))
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
matched = 0;
|
||||
del_fp = NULL;
|
||||
DN_FIB_SCAN_KEY(f, fp, key) {
|
||||
struct dn_fib_info *fi = DN_FIB_INFO(f);
|
||||
|
||||
if (f->fn_state & DN_S_ZOMBIE)
|
||||
return -ESRCH;
|
||||
|
||||
matched++;
|
||||
|
||||
if (del_fp == NULL &&
|
||||
(!r->rtm_type || f->fn_type == r->rtm_type) &&
|
||||
(r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
|
||||
(!r->rtm_protocol ||
|
||||
fi->fib_protocol == r->rtm_protocol) &&
|
||||
dn_fib_nh_match(r, n, attrs, fi) == 0)
|
||||
del_fp = fp;
|
||||
}
|
||||
|
||||
if (del_fp) {
|
||||
f = *del_fp;
|
||||
dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
|
||||
|
||||
if (matched != 1) {
|
||||
write_lock_bh(&dn_fib_tables_lock);
|
||||
*del_fp = f->fn_next;
|
||||
write_unlock_bh(&dn_fib_tables_lock);
|
||||
|
||||
if (f->fn_state & DN_S_ACCESSED)
|
||||
dn_rt_cache_flush(-1);
|
||||
dn_free_node(f);
|
||||
dz->dz_nent--;
|
||||
} else {
|
||||
f->fn_state |= DN_S_ZOMBIE;
|
||||
if (f->fn_state & DN_S_ACCESSED) {
|
||||
f->fn_state &= ~DN_S_ACCESSED;
|
||||
dn_rt_cache_flush(-1);
|
||||
}
|
||||
if (++dn_fib_hash_zombies > 128)
|
||||
dn_fib_flush();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
static inline int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
|
||||
{
|
||||
int found = 0;
|
||||
struct dn_fib_node *f;
|
||||
|
||||
while((f = *fp) != NULL) {
|
||||
struct dn_fib_info *fi = DN_FIB_INFO(f);
|
||||
|
||||
if (fi && ((f->fn_state & DN_S_ZOMBIE) || (fi->fib_flags & RTNH_F_DEAD))) {
|
||||
write_lock_bh(&dn_fib_tables_lock);
|
||||
*fp = f->fn_next;
|
||||
write_unlock_bh(&dn_fib_tables_lock);
|
||||
|
||||
dn_free_node(f);
|
||||
found++;
|
||||
continue;
|
||||
}
|
||||
fp = &f->fn_next;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static int dn_fib_table_flush(struct dn_fib_table *tb)
|
||||
{
|
||||
struct dn_hash *table = (struct dn_hash *)tb->data;
|
||||
struct dn_zone *dz;
|
||||
int found = 0;
|
||||
|
||||
dn_fib_hash_zombies = 0;
|
||||
for(dz = table->dh_zone_list; dz; dz = dz->dz_next) {
|
||||
int i;
|
||||
int tmp = 0;
|
||||
for(i = dz->dz_divisor-1; i >= 0; i--)
|
||||
tmp += dn_flush_list(&dz->dz_hash[i], dz->dz_order, table);
|
||||
dz->dz_nent -= tmp;
|
||||
found += tmp;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowidn *flp, struct dn_fib_res *res)
|
||||
{
|
||||
int err;
|
||||
struct dn_zone *dz;
|
||||
struct dn_hash *t = (struct dn_hash *)tb->data;
|
||||
|
||||
read_lock(&dn_fib_tables_lock);
|
||||
for(dz = t->dh_zone_list; dz; dz = dz->dz_next) {
|
||||
struct dn_fib_node *f;
|
||||
dn_fib_key_t k = dz_key(flp->daddr, dz);
|
||||
|
||||
for(f = dz_chain(k, dz); f; f = f->fn_next) {
|
||||
if (!dn_key_eq(k, f->fn_key)) {
|
||||
if (dn_key_leq(k, f->fn_key))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
f->fn_state |= DN_S_ACCESSED;
|
||||
|
||||
if (f->fn_state&DN_S_ZOMBIE)
|
||||
continue;
|
||||
|
||||
if (f->fn_scope < flp->flowidn_scope)
|
||||
continue;
|
||||
|
||||
err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), flp, res);
|
||||
|
||||
if (err == 0) {
|
||||
res->type = f->fn_type;
|
||||
res->scope = f->fn_scope;
|
||||
res->prefixlen = dz->dz_order;
|
||||
goto out;
|
||||
}
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
err = 1;
|
||||
out:
|
||||
read_unlock(&dn_fib_tables_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
struct dn_fib_table *dn_fib_get_table(u32 n, int create)
|
||||
{
|
||||
struct dn_fib_table *t;
|
||||
unsigned int h;
|
||||
|
||||
if (n < RT_TABLE_MIN)
|
||||
return NULL;
|
||||
|
||||
if (n > RT_TABLE_MAX)
|
||||
return NULL;
|
||||
|
||||
h = n & (DN_FIB_TABLE_HASHSZ - 1);
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(t, &dn_fib_table_hash[h], hlist) {
|
||||
if (t->n == n) {
|
||||
rcu_read_unlock();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!create)
|
||||
return NULL;
|
||||
|
||||
if (in_interrupt()) {
|
||||
net_dbg_ratelimited("DECnet: BUG! Attempt to create routing table from interrupt\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = kzalloc(sizeof(struct dn_fib_table) + sizeof(struct dn_hash),
|
||||
GFP_KERNEL);
|
||||
if (t == NULL)
|
||||
return NULL;
|
||||
|
||||
t->n = n;
|
||||
t->insert = dn_fib_table_insert;
|
||||
t->delete = dn_fib_table_delete;
|
||||
t->lookup = dn_fib_table_lookup;
|
||||
t->flush = dn_fib_table_flush;
|
||||
t->dump = dn_fib_table_dump;
|
||||
hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
struct dn_fib_table *dn_fib_empty_table(void)
|
||||
{
|
||||
u32 id;
|
||||
|
||||
for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
|
||||
if (dn_fib_get_table(id, 0) == NULL)
|
||||
return dn_fib_get_table(id, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dn_fib_flush(void)
|
||||
{
|
||||
int flushed = 0;
|
||||
struct dn_fib_table *tb;
|
||||
unsigned int h;
|
||||
|
||||
for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
|
||||
hlist_for_each_entry(tb, &dn_fib_table_hash[h], hlist)
|
||||
flushed += tb->flush(tb);
|
||||
}
|
||||
|
||||
if (flushed)
|
||||
dn_rt_cache_flush(-1);
|
||||
}
|
||||
|
||||
void __init dn_fib_table_init(void)
|
||||
{
|
||||
dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
|
||||
sizeof(struct dn_fib_info),
|
||||
0, SLAB_HWCACHE_ALIGN,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void __exit dn_fib_table_cleanup(void)
|
||||
{
|
||||
struct dn_fib_table *t;
|
||||
struct hlist_node *next;
|
||||
unsigned int h;
|
||||
|
||||
write_lock(&dn_fib_tables_lock);
|
||||
for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
|
||||
hlist_for_each_entry_safe(t, next, &dn_fib_table_hash[h],
|
||||
hlist) {
|
||||
hlist_del(&t->hlist);
|
||||
kfree(t);
|
||||
}
|
||||
}
|
||||
write_unlock(&dn_fib_tables_lock);
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DECnet An implementation of the DECnet protocol suite for the LINUX
|
||||
* operating system. DECnet is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DECnet Socket Timer Functions
|
||||
*
|
||||
* Author: Steve Whitehouse <SteveW@ACM.org>
|
||||
*
|
||||
*
|
||||
* Changes:
|
||||
* Steve Whitehouse : Made keepalive timer part of the same
|
||||
* timer idea.
|
||||
* Steve Whitehouse : Added checks for sk->sock_readers
|
||||
* David S. Miller : New socket locking
|
||||
* Steve Whitehouse : Timer grabs socket ref.
|
||||
*/
|
||||
#include <linux/net.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/dn.h>
|
||||
|
||||
/*
|
||||
* Slow timer is for everything else (n * 500mS)
|
||||
*/
|
||||
|
||||
#define SLOW_INTERVAL (HZ/2)
|
||||
|
||||
static void dn_slow_timer(struct timer_list *t);
|
||||
|
||||
void dn_start_slow_timer(struct sock *sk)
|
||||
{
|
||||
timer_setup(&sk->sk_timer, dn_slow_timer, 0);
|
||||
sk_reset_timer(sk, &sk->sk_timer, jiffies + SLOW_INTERVAL);
|
||||
}
|
||||
|
||||
void dn_stop_slow_timer(struct sock *sk)
|
||||
{
|
||||
sk_stop_timer(sk, &sk->sk_timer);
|
||||
}
|
||||
|
||||
static void dn_slow_timer(struct timer_list *t)
|
||||
{
|
||||
struct sock *sk = from_timer(sk, t, sk_timer);
|
||||
struct dn_scp *scp = DN_SK(sk);
|
||||
|
||||
bh_lock_sock(sk);
|
||||
|
||||
if (sock_owned_by_user(sk)) {
|
||||
sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ / 10);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The persist timer is the standard slow timer used for retransmits
|
||||
* in both connection establishment and disconnection as well as
|
||||
* in the RUN state. The different states are catered for by changing
|
||||
* the function pointer in the socket. Setting the timer to a value
|
||||
* of zero turns it off. We allow the persist_fxn to turn the
|
||||
* timer off in a permant way by returning non-zero, so that
|
||||
* timer based routines may remove sockets. This is why we have a
|
||||
* sock_hold()/sock_put() around the timer to prevent the socket
|
||||
* going away in the middle.
|
||||
*/
|
||||
if (scp->persist && scp->persist_fxn) {
|
||||
if (scp->persist <= SLOW_INTERVAL) {
|
||||
scp->persist = 0;
|
||||
|
||||
if (scp->persist_fxn(sk))
|
||||
goto out;
|
||||
} else {
|
||||
scp->persist -= SLOW_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for keepalive timeout. After the other timer 'cos if
|
||||
* the previous timer caused a retransmit, we don't need to
|
||||
* do this. scp->stamp is the last time that we sent a packet.
|
||||
* The keepalive function sends a link service packet to the
|
||||
* other end. If it remains unacknowledged, the standard
|
||||
* socket timers will eventually shut the socket down. Each
|
||||
* time we do this, scp->stamp will be updated, thus
|
||||
* we won't try and send another until scp->keepalive has passed
|
||||
* since the last successful transmission.
|
||||
*/
|
||||
if (scp->keepalive && scp->keepalive_fxn && (scp->state == DN_RUN)) {
|
||||
if (time_after_eq(jiffies, scp->stamp + scp->keepalive))
|
||||
scp->keepalive_fxn(sk);
|
||||
}
|
||||
|
||||
sk_reset_timer(sk, &sk->sk_timer, jiffies + SLOW_INTERVAL);
|
||||
out:
|
||||
bh_unlock_sock(sk);
|
||||
sock_put(sk);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# DECnet netfilter configuration
|
||||
#
|
||||
|
||||
menu "DECnet: Netfilter Configuration"
|
||||
depends on DECNET && NETFILTER
|
||||
depends on NETFILTER_ADVANCED
|
||||
|
||||
config DECNET_NF_GRABULATOR
|
||||
tristate "Routing message grabulator (for userland routing daemon)"
|
||||
help
|
||||
Enable this module if you want to use the userland DECnet routing
|
||||
daemon. You will also need to enable routing support for DECnet
|
||||
unless you just want to monitor routing messages from other nodes.
|
||||
|
||||
endmenu
|
@ -1,6 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Makefile for DECnet netfilter modules
|
||||
#
|
||||
|
||||
obj-$(CONFIG_DECNET_NF_GRABULATOR) += dn_rtmsg.o
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user