11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysctl.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ether.h> 225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inet.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ip.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/arp.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ax25.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/rose.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 383b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemmingerstatic int rose_header(struct sk_buff *skb, struct net_device *dev, 393b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemminger unsigned short type, 4095c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet const void *daddr, const void *saddr, unsigned int len) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buff++ = ROSE_GFI | ROSE_Q_BIT; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buff++ = 0x00; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buff++ = ROSE_DATA; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buff++ = 0x7F; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buff++ = AX25_P_IP; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (daddr != NULL) 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 37; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -37; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rose_rebuild_header(struct sk_buff *skb) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5878f150bf94f5430fe8c34edeafe8d01706f38148Pavel Emelyanov#ifdef CONFIG_INET 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = skb->dev; 60d289d120b46d9b6c68448b1d1c6d3edb94cdbde6Stephen Hemminger struct net_device_stats *stats = &dev->stats; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *bp = (unsigned char *)skb->data; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skbn; 638dc22d2b642f8a6f14ef8878777a05311e5d1d7eRalf Baechle unsigned int len; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (arp_find(bp + 7, skb)) { 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->sk != NULL) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_set_owner_w(skbn, skb->sk); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 798dc22d2b642f8a6f14ef8878777a05311e5d1d7eRalf Baechle len = skbn->len; 808dc22d2b642f8a6f14ef8878777a05311e5d1d7eRalf Baechle 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rose_route_frame(skbn, NULL)) { 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skbn); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->tx_errors++; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->tx_packets++; 888dc22d2b642f8a6f14ef8878777a05311e5d1d7eRalf Baechle stats->tx_bytes += len; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rose_set_mac_address(struct net_device *dev, void *addr) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr *sa = addr; 96a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle int err; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9881213b5e8ae68e204aa7a3f83c4f9100405dbff9danborkmann@iogearbox.net if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) 99a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle return 0; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle if (dev->flags & IFF_UP) { 10281213b5e8ae68e204aa7a3f83c4f9100405dbff9danborkmann@iogearbox.net err = rose_add_loopback_node((rose_address *)sa->sa_data); 103a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle if (err) 104a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle return err; 105a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle 106a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle rose_del_loopback_node((rose_address *)dev->dev_addr); 107a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle } 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 109a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rose_open(struct net_device *dev) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 116a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle int err; 117a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle 118a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle err = rose_add_loopback_node((rose_address *)dev->dev_addr); 119a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle if (err) 120a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle return err; 121a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 123a159aaa328a02b0189774c58ae7d917b25d26852Ralf Baechle 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rose_close(struct net_device *dev) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rose_del_loopback_node((rose_address *)dev->dev_addr); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13436e4d64a82d9a91a73a2b9b32117aedfe2211fb3Stephen Hemmingerstatic netdev_tx_t rose_xmit(struct sk_buff *skb, struct net_device *dev) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 136d289d120b46d9b6c68448b1d1c6d3edb94cdbde6Stephen Hemminger struct net_device_stats *stats = &dev->stats; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!netif_running(dev)) { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); 1405b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy return NETDEV_TX_BUSY; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stats->tx_errors++; 1446ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1473b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemmingerstatic const struct header_ops rose_header_ops = { 1483b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemminger .create = rose_header, 149db34de939ae28954441c18b331c2c0aafec2d6acWeilong Chen .rebuild = rose_rebuild_header, 1503b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemminger}; 1513b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemminger 1523170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemmingerstatic const struct net_device_ops rose_netdev_ops = { 1533170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemminger .ndo_open = rose_open, 1543170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemminger .ndo_stop = rose_close, 1553170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemminger .ndo_start_xmit = rose_xmit, 1563170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemminger .ndo_set_mac_address = rose_set_mac_address, 1573170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemminger}; 1583170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemminger 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid rose_setup(struct net_device *dev) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mtu = ROSE_MAX_PACKET_SIZE - 2; 1623170c6568776a58e1eeec8ff949a65f5cf5d7cebStephen Hemminger dev->netdev_ops = &rose_netdev_ops; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1643b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemminger dev->header_ops = &rose_header_ops; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->addr_len = ROSE_ADDR_LEN; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->type = ARPHRD_ROSE; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* New-style flags. */ 170d2ce4bc340946d5b78484d638ac10df958c4c3bfRalf Baechle dev->flags = IFF_NOARP; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 172