11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DECnet       An implementation of the DECnet protocol suite for the LINUX
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              operating system.  DECnet is implemented using the  BSD Socket
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              interface as the means of communication with the user level.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki *              DECnet Neighbour Functions (Adjacency Database and
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                                        On-Ethernet Cache)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author:      Steve Whitehouse <SteveW@ACM.org>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Changes:
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Fixed router listing routine
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Added error_report functions
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Added default router detection
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Hop counts in outgoing messages
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Fixed src/dst in outgoing messages so
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                            forwarding now stands a good chance of
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                            working.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Fixed neighbour states (for now anyway).
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Made error_report functions dummies. This
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                            is not the right place to return skbs.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Steve Whitehouse     : Convert to seq_file
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h>
315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ether.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netfilter_decnet.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rcupdate.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jhash.h>
4160063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
42457c4cbc5a3dde259d2a1f15d5f9785290397267Eric W. Biederman#include <net/net_namespace.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/neighbour.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/dst.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/flow.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/dn.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/dn_dev.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/dn_neigh.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/dn_route.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dn_neigh_construct(struct neighbour *);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dn_long_error_report(struct neighbour *, struct sk_buff *);
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dn_short_error_report(struct neighbour *, struct sk_buff *);
548f40b161de4f27402b4c0659ad2ae83fad5a0cddDavid S. Millerstatic int dn_long_output(struct neighbour *, struct sk_buff *);
558f40b161de4f27402b4c0659ad2ae83fad5a0cddDavid S. Millerstatic int dn_short_output(struct neighbour *, struct sk_buff *);
568f40b161de4f27402b4c0659ad2ae83fad5a0cddDavid S. Millerstatic int dn_phase3_output(struct neighbour *, struct sk_buff *);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For talking to broadcast devices: Ethernet & PPP
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6289d69d2b75a8f7e258f4b634cd985374cfd3202eStephen Hemmingerstatic const struct neigh_ops dn_long_ops = {
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family =		AF_DECnet,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.error_report =		dn_long_error_report,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.output =		dn_long_output,
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.connected_output =	dn_long_output,
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For talking to pointopoint and multidrop devices: DDCMP and X.25
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7289d69d2b75a8f7e258f4b634cd985374cfd3202eStephen Hemmingerstatic const struct neigh_ops dn_short_ops = {
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family =		AF_DECnet,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.error_report =		dn_short_error_report,
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.output =		dn_short_output,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.connected_output =	dn_short_output,
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For talking to DECnet phase III nodes
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8289d69d2b75a8f7e258f4b634cd985374cfd3202eStephen Hemmingerstatic const struct neigh_ops dn_phase3_ops = {
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family =		AF_DECnet,
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.error_report =		dn_short_error_report, /* Can use short version here */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.output =		dn_phase3_output,
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.connected_output =	dn_phase3_output,
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89d6bf781712a1d25cc8987036b3a48535b331eb91Eric Dumazetstatic u32 dn_neigh_hash(const void *pkey,
90d6bf781712a1d25cc8987036b3a48535b331eb91Eric Dumazet			 const struct net_device *dev,
912c2aba6c561ac425602f4a0be61422224cb87151David S. Miller			 __u32 *hash_rnd)
92d6bf781712a1d25cc8987036b3a48535b331eb91Eric Dumazet{
932c2aba6c561ac425602f4a0be61422224cb87151David S. Miller	return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]);
94d6bf781712a1d25cc8987036b3a48535b331eb91Eric Dumazet}
95d6bf781712a1d25cc8987036b3a48535b331eb91Eric Dumazet
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct neigh_table dn_neigh_table = {
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.family =			PF_DECnet,
98daaba4fa17d7826807b0b131f796543b4099ef4aYOSHIFUJI Hideaki / 吉藤英明	.entry_size =			NEIGH_ENTRY_SIZE(sizeof(struct dn_neigh)),
99c4ea94ab3710eb2434abe2eab1a479c2dc01f8acSteven Whitehouse	.key_len =			sizeof(__le16),
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hash =				dn_neigh_hash,
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.constructor =			dn_neigh_construct,
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id =				"dn_neigh_cache",
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.parms ={
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.tbl =			&dn_neigh_table,
1051f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko		.reachable_time =	30 * HZ,
1061f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko		.data = {
1071f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_MCAST_PROBES] = 0,
1081f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_UCAST_PROBES] = 0,
1091f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_APP_PROBES] = 0,
1101f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_RETRANS_TIME] = 1 * HZ,
1111f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ,
1121f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
1131f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_GC_STALETIME] = 60 * HZ,
1141f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_QUEUE_LEN_BYTES] = 64*1024,
1151f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_PROXY_QLEN] = 0,
1161f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_ANYCAST_DELAY] = 0,
1171f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_PROXY_DELAY] = 0,
1181f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko			[NEIGH_VAR_LOCKTIME] = 1 * HZ,
1191f9248e5606afc6485255e38ad57bdac08fa7711Jiri Pirko		},
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.gc_interval =			30 * HZ,
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.gc_thresh1 =			128,
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.gc_thresh2 =			512,
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.gc_thresh3 =			1024,
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dn_neigh_construct(struct neighbour *neigh)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = neigh->dev;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_neigh *dn = (struct dn_neigh *)neigh;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_dev *dn_db;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct neigh_parms *parms;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rcu_read_lock();
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn_db = rcu_dereference(dev->dn_ptr);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dn_db == NULL) {
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rcu_read_unlock();
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	parms = dn_db->neigh_parms;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!parms) {
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rcu_read_unlock();
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__neigh_parms_put(neigh->parms);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh->parms = neigh_parms_clone(parms);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dn_db->use_long)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		neigh->ops = &dn_long_ops;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		neigh->ops = &dn_short_ops;
1541f07247de51efd30c88ad8e3e06a8b5382fc7d35Paul E. McKenney	rcu_read_unlock();
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dn->flags & DN_NDFLAG_P3)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		neigh->ops = &dn_phase3_ops;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh->nud_state = NUD_NOARP;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh->output = neigh->ops->connected_output;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->type == ARPHRD_IPGRE) || (dev->flags & IFF_POINTOPOINT))
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(neigh->ha, dev->broadcast, dev->addr_len);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if ((dev->type == ARPHRD_ETHER) || (dev->type == ARPHRD_LOOPBACK))
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dn_dn2eth(neigh->ha, dn->addr);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
167e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches		net_dbg_ratelimited("Trying to create neigh for hw %d\n",
168e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches				    dev->type);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Make an estimate of the remote block size by assuming that its
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * two less then the device mtu, which it true for ethernet (and
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * other things which support long format headers) since there is
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * an extra length field (of 16 bits) which isn't part of the
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ethernet headers and which the DECnet specs won't admit is part
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * of the DECnet routing headers either.
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we over estimate here its no big deal, the NSP negotiations
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * will prevent us from sending packets which are too large for the
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * remote node to handle. In any case this figure is normally updated
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * by a hello message in most cases.
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn->blksize = dev->mtu - 2;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dn_long_error_report(struct neighbour *neigh, struct sk_buff *skb)
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_DEBUG "dn_long_error_report: called\n");
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dn_short_error_report(struct neighbour *neigh, struct sk_buff *skb)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_DEBUG "dn_short_error_report: called\n");
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dn_neigh_output_packet(struct sk_buff *skb)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
205adf30907d63893e4208dfe3f5c88ae12bc2f25d5Eric Dumazet	struct dst_entry *dst = skb_dst(skb);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_route *rt = (struct dn_route *)dst;
207fccd7d5c77ff61d5283e7ce8242791d5f00dcc17David S. Miller	struct neighbour *neigh = rt->n;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = neigh->dev;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char mac_addr[ETH_ALEN];
2103329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	unsigned int seq;
2113329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	int err;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn_dn2eth(mac_addr, rt->rt_local_src);
2143329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	do {
2153329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller		seq = read_seqbegin(&neigh->ha_lock);
2163329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
2173329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller				      neigh->ha, mac_addr, skb->len);
2183329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	} while (read_seqretry(&neigh->ha_lock, seq));
2193329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller
2203329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	if (err >= 0)
2213329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller		err = dev_queue_xmit(skb);
2223329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	else {
2233329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller		kfree_skb(skb);
2243329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller		err = -EINVAL;
2253329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	}
2263329bdfc4071840816d6666c6463fdb0bd4c8264David S. Miller	return err;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2298f40b161de4f27402b4c0659ad2ae83fad5a0cddDavid S. Millerstatic int dn_long_output(struct neighbour *neigh, struct sk_buff *skb)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = neigh->dev;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_long_packet *lp;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_skb_cb *cb = DN_SKB_CB(skb);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb_headroom(skb) < headroom) {
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb2 == NULL) {
241e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches			net_crit_ratelimited("dn_long_output: no memory\n");
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree_skb(skb);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOBUFS;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2455d0ba55b6486f58cc890918d7167063d83f7fbb4Eric Dumazet		consume_skb(skb);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = skb2;
247e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches		net_info_ratelimited("dn_long_output: Increasing headroom\n");
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp = (struct dn_long_packet *)(data+3);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison	*((__le16 *)data) = cpu_to_le16(skb->len - 2);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(data + 2) = 1 | DN_RT_F_PF; /* Padding */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->msgflg   = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS));
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->d_area   = lp->d_subarea = 0;
258c4ea94ab3710eb2434abe2eab1a479c2dc01f8acSteven Whitehouse	dn_dn2eth(lp->d_id, cb->dst);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->s_area   = lp->s_subarea = 0;
260c4ea94ab3710eb2434abe2eab1a479c2dc01f8acSteven Whitehouse	dn_dn2eth(lp->s_id, cb->src);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->nl2      = 0;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->visit_ct = cb->hops & 0x3f;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->s_class  = 0;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->pt       = 0;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
266c1d2bbe1cd6c7bbdc6d532cefebb66c7efb789ceArnaldo Carvalho de Melo	skb_reset_network_header(skb);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2685d877d876cfb96c0c3254184171b4767501f4f95Jan Engelhardt	return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
2695d877d876cfb96c0c3254184171b4767501f4f95Jan Engelhardt		       neigh->dev, dn_neigh_output_packet);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2728f40b161de4f27402b4c0659ad2ae83fad5a0cddDavid S. Millerstatic int dn_short_output(struct neighbour *neigh, struct sk_buff *skb)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = neigh->dev;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_short_packet *sp;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_skb_cb *cb = DN_SKB_CB(skb);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki	if (skb_headroom(skb) < headroom) {
282429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki		struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
283429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki		if (skb2 == NULL) {
284e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches			net_crit_ratelimited("dn_short_output: no memory\n");
285429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki			kfree_skb(skb);
286429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki			return -ENOBUFS;
287429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki		}
2885d0ba55b6486f58cc890918d7167063d83f7fbb4Eric Dumazet		consume_skb(skb);
289429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki		skb = skb2;
290e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches		net_info_ratelimited("dn_short_output: Increasing headroom\n");
291429eb0fae6c06c9adcda03401c09c2b9ccaa7ebdYOSHIFUJI Hideaki	}
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
294c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison	*((__le16 *)data) = cpu_to_le16(skb->len - 2);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp = (struct dn_short_packet *)(data+2);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->msgflg     = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->dstnode    = cb->dst;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->srcnode    = cb->src;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->forward    = cb->hops & 0x3f;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
302c1d2bbe1cd6c7bbdc6d532cefebb66c7efb789ceArnaldo Carvalho de Melo	skb_reset_network_header(skb);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3045d877d876cfb96c0c3254184171b4767501f4f95Jan Engelhardt	return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
3055d877d876cfb96c0c3254184171b4767501f4f95Jan Engelhardt		       neigh->dev, dn_neigh_output_packet);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Phase 3 output is the same is short output, execpt that
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it clears the area bits before transmission.
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3128f40b161de4f27402b4c0659ad2ae83fad5a0cddDavid S. Millerstatic int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb)
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = neigh->dev;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_short_packet *sp;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_skb_cb *cb = DN_SKB_CB(skb);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb_headroom(skb) < headroom) {
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb2 == NULL) {
323e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches			net_crit_ratelimited("dn_phase3_output: no memory\n");
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree_skb(skb);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOBUFS;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3275d0ba55b6486f58cc890918d7167063d83f7fbb4Eric Dumazet		consume_skb(skb);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = skb2;
329e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches		net_info_ratelimited("dn_phase3_output: Increasing headroom\n");
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
333c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison	*((__le16 *)data) = cpu_to_le16(skb->len - 2);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp = (struct dn_short_packet *)(data + 2);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->msgflg   = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
337c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison	sp->dstnode  = cb->dst & cpu_to_le16(0x03ff);
338c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison	sp->srcnode  = cb->src & cpu_to_le16(0x03ff);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->forward  = cb->hops & 0x3f;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341c1d2bbe1cd6c7bbdc6d532cefebb66c7efb789ceArnaldo Carvalho de Melo	skb_reset_network_header(skb);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3435d877d876cfb96c0c3254184171b4767501f4f95Jan Engelhardt	return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
3445d877d876cfb96c0c3254184171b4767501f4f95Jan Engelhardt		       neigh->dev, dn_neigh_output_packet);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unfortunately, the neighbour code uses the device in its hash
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * function, so we don't get any advantage from it. This function
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * basically does a neigh_lookup(), but without comparing the device
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * field. This is required for the On-Ethernet cache
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Pointopoint link receives a hello message
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dn_neigh_pointopoint_hello(struct sk_buff *skb)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ethernet router hello message received
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dn_neigh_router_hello(struct sk_buff *skb)
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rtnode_hello_message *msg = (struct rtnode_hello_message *)skb->data;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct neighbour *neigh;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_neigh *dn;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_dev *dn_db;
372c4ea94ab3710eb2434abe2eab1a479c2dc01f8acSteven Whitehouse	__le16 src;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
374c4ea94ab3710eb2434abe2eab1a479c2dc01f8acSteven Whitehouse	src = dn_eth2dn(msg->id);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn = (struct dn_neigh *)neigh;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (neigh) {
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_lock(&neigh->lock);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		neigh->used = jiffies;
384fc766e4c4965915ab52a1d1fa3c7a7b3e7bc07f0Eric Dumazet		dn_db = rcu_dereference(neigh->dev->dn_ptr);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(neigh->nud_state & NUD_PERMANENT)) {
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			neigh->updated = jiffies;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (neigh->dev->type == ARPHRD_ETHER)
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy(neigh->ha, &eth_hdr(skb)->h_source, ETH_ALEN);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
392c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison			dn->blksize  = le16_to_cpu(msg->blksize);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dn->priority = msg->priority;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dn->flags &= ~DN_NDFLAG_P3;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39706f8fe11bb4a84de9d9faa50c7ffbe40b90d395aJoe Perches			switch (msg->iinfo & DN_RT_INFO_TYPE) {
39806f8fe11bb4a84de9d9faa50c7ffbe40b90d395aJoe Perches			case DN_RT_INFO_L1RT:
39906f8fe11bb4a84de9d9faa50c7ffbe40b90d395aJoe Perches				dn->flags &=~DN_NDFLAG_R2;
40006f8fe11bb4a84de9d9faa50c7ffbe40b90d395aJoe Perches				dn->flags |= DN_NDFLAG_R1;
40106f8fe11bb4a84de9d9faa50c7ffbe40b90d395aJoe Perches				break;
40206f8fe11bb4a84de9d9faa50c7ffbe40b90d395aJoe Perches			case DN_RT_INFO_L2RT:
40306f8fe11bb4a84de9d9faa50c7ffbe40b90d395aJoe Perches				dn->flags |= DN_NDFLAG_R2;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4075062430c5cc526655e3d10c670fc9c263656f66cPatrick Caulfield		/* Only use routers in our area */
408c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison		if ((le16_to_cpu(src)>>10) == (le16_to_cpu((decnet_address))>>10)) {
4095062430c5cc526655e3d10c670fc9c263656f66cPatrick Caulfield			if (!dn_db->router) {
4105062430c5cc526655e3d10c670fc9c263656f66cPatrick Caulfield				dn_db->router = neigh_clone(neigh);
4115062430c5cc526655e3d10c670fc9c263656f66cPatrick Caulfield			} else {
4125062430c5cc526655e3d10c670fc9c263656f66cPatrick Caulfield				if (msg->priority > ((struct dn_neigh *)dn_db->router)->priority)
4135062430c5cc526655e3d10c670fc9c263656f66cPatrick Caulfield					neigh_release(xchg(&dn_db->router, neigh_clone(neigh)));
4145062430c5cc526655e3d10c670fc9c263656f66cPatrick Caulfield			}
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock(&neigh->lock);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		neigh_release(neigh);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Endnode hello message received
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dn_neigh_endnode_hello(struct sk_buff *skb)
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct neighbour *neigh;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_neigh *dn;
432c4ea94ab3710eb2434abe2eab1a479c2dc01f8acSteven Whitehouse	__le16 src;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
434c4ea94ab3710eb2434abe2eab1a479c2dc01f8acSteven Whitehouse	src = dn_eth2dn(msg->id);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn = (struct dn_neigh *)neigh;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (neigh) {
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_lock(&neigh->lock);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		neigh->used = jiffies;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(neigh->nud_state & NUD_PERMANENT)) {
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			neigh->updated = jiffies;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (neigh->dev->type == ARPHRD_ETHER)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy(neigh->ha, &eth_hdr(skb)->h_source, ETH_ALEN);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dn->flags   &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2);
451c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison			dn->blksize  = le16_to_cpu(msg->blksize);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dn->priority = 0;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_unlock(&neigh->lock);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		neigh_release(neigh);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *dn_find_slot(char *base, int max, int priority)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *min = NULL;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	base += 6; /* skip first id */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < max; i++) {
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!min || (*base < *min))
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			min = base;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		base += 7; /* find next priority */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!min)
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (*min < priority) ? (min - 6) : NULL;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct elist_cb_state {
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *ptr;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *rs;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int t, n;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void neigh_elist_cb(struct neighbour *neigh, void *_info)
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct elist_cb_state *s = _info;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_neigh *dn;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (neigh->dev != s->dev)
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn = (struct dn_neigh *) neigh;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (s->t == s->n)
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s->rs = dn_find_slot(s->ptr, s->n, dn->priority);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s->t++;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (s->rs == NULL)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dn_dn2eth(s->rs, dn->addr);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s->rs += 6;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(s->rs) = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(s->rs) |= dn->priority;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s->rs++;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct elist_cb_state state;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state.dev = dev;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state.t = 0;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state.n = n;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state.ptr = ptr;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state.rs = ptr;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh_for_each(&dn_neigh_table, neigh_elist_cb, &state);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return state.t;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void dn_neigh_format_entry(struct seq_file *seq,
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 struct neighbour *n)
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dn_neigh *dn = (struct dn_neigh *) n;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buf[DN_ASCBUF_LEN];
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock(&n->lock);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seq_printf(seq, "%-7s %s%s%s   %02x    %02d  %07ld %-8s\n",
541c4106aa88a440430d387e022f2ad6dc1e0d52e98Harvey Harrison		   dn_addr2asc(le16_to_cpu(dn->addr), buf),
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (dn->flags&DN_NDFLAG_R1) ? "1" : "-",
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (dn->flags&DN_NDFLAG_R2) ? "2" : "-",
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (dn->flags&DN_NDFLAG_P3) ? "3" : "-",
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dn->n.nud_state,
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   atomic_read(&dn->n.refcnt),
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dn->blksize,
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (dn->n.dev) ? dn->n.dev->name : "?");
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&n->lock);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dn_neigh_seq_show(struct seq_file *seq, void *v)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (v == SEQ_START_TOKEN) {
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seq_puts(seq, "Addr    Flags State Use Blksize Dev\n");
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dn_neigh_format_entry(seq, v);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return neigh_seq_start(seq, pos, &dn_neigh_table,
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       NEIGH_SEQ_NEIGH_ONLY);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56956b3d975bbce65f655c5612b4822da671f9fd9b2Philippe De Muyterstatic const struct seq_operations dn_neigh_seq_ops = {
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start = dn_neigh_seq_start,
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.next  = neigh_seq_next,
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop  = neigh_seq_stop,
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.show  = dn_neigh_seq_show,
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dn_neigh_seq_open(struct inode *inode, struct file *file)
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
578426b5303eb435d98b9bee37a807be386bc2b3320Eric W. Biederman	return seq_open_net(inode, file, &dn_neigh_seq_ops,
579426b5303eb435d98b9bee37a807be386bc2b3320Eric W. Biederman			    sizeof(struct neigh_seq_state));
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5829a32144e9d7b4e21341174b1a83b82a82353be86Arjan van de Venstatic const struct file_operations dn_neigh_seq_fops = {
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open		= dn_neigh_seq_open,
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read		= seq_read,
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek		= seq_lseek,
587426b5303eb435d98b9bee37a807be386bc2b3320Eric W. Biederman	.release	= seq_release_net,
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init dn_neigh_init(void)
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh_table_init(&dn_neigh_table);
595d4beaa66add8aebf83ab16d2fde4e4de8dac36dfGao feng	proc_create("decnet_neigh", S_IRUGO, init_net.proc_net,
596d4beaa66add8aebf83ab16d2fde4e4de8dac36dfGao feng		    &dn_neigh_seq_fops);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit dn_neigh_cleanup(void)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
601ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng	remove_proc_entry("decnet_neigh", init_net.proc_net);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	neigh_table_clear(&dn_neigh_table);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
604