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, ð_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, ð_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