12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds #include <linux/module.h> 71da177e4SLinus Torvalds #include <linux/proc_fs.h> 81da177e4SLinus Torvalds #include <linux/kernel.h> 91da177e4SLinus Torvalds #include <linux/interrupt.h> 101da177e4SLinus Torvalds #include <linux/fs.h> 111da177e4SLinus Torvalds #include <linux/types.h> 121da177e4SLinus Torvalds #include <linux/sysctl.h> 131da177e4SLinus Torvalds #include <linux/string.h> 141da177e4SLinus Torvalds #include <linux/socket.h> 151da177e4SLinus Torvalds #include <linux/errno.h> 161da177e4SLinus Torvalds #include <linux/fcntl.h> 171da177e4SLinus Torvalds #include <linux/in.h> 181da177e4SLinus Torvalds #include <linux/if_ether.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include <asm/io.h> 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/inet.h> 241da177e4SLinus Torvalds #include <linux/netdevice.h> 251da177e4SLinus Torvalds #include <linux/etherdevice.h> 261da177e4SLinus Torvalds #include <linux/if_arp.h> 271da177e4SLinus Torvalds #include <linux/skbuff.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #include <net/ip.h> 301da177e4SLinus Torvalds #include <net/arp.h> 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds #include <net/ax25.h> 331da177e4SLinus Torvalds #include <net/rose.h> 341da177e4SLinus Torvalds 353b04dddeSStephen Hemminger static int rose_header(struct sk_buff *skb, struct net_device *dev, 363b04dddeSStephen Hemminger unsigned short type, 3795c96174SEric Dumazet const void *daddr, const void *saddr, unsigned int len) 381da177e4SLinus Torvalds { 391da177e4SLinus Torvalds unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2); 401da177e4SLinus Torvalds 41b753af31SEric W. Biederman if (daddr) 42b753af31SEric W. Biederman memcpy(buff + 7, daddr, dev->addr_len); 43b753af31SEric W. Biederman 441da177e4SLinus Torvalds *buff++ = ROSE_GFI | ROSE_Q_BIT; 451da177e4SLinus Torvalds *buff++ = 0x00; 461da177e4SLinus Torvalds *buff++ = ROSE_DATA; 471da177e4SLinus Torvalds *buff++ = 0x7F; 481da177e4SLinus Torvalds *buff++ = AX25_P_IP; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds if (daddr != NULL) 511da177e4SLinus Torvalds return 37; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds return -37; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds static int rose_set_mac_address(struct net_device *dev, void *addr) 571da177e4SLinus Torvalds { 581da177e4SLinus Torvalds struct sockaddr *sa = addr; 59a159aaa3SRalf Baechle int err; 60a159aaa3SRalf Baechle 6181213b5eSdanborkmann@iogearbox.net if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) 62a159aaa3SRalf Baechle return 0; 63a159aaa3SRalf Baechle 64a159aaa3SRalf Baechle if (dev->flags & IFF_UP) { 6581213b5eSdanborkmann@iogearbox.net err = rose_add_loopback_node((rose_address *)sa->sa_data); 66a159aaa3SRalf Baechle if (err) 67a159aaa3SRalf Baechle return err; 681da177e4SLinus Torvalds 69*db957324SJakub Kicinski rose_del_loopback_node((const rose_address *)dev->dev_addr); 70a159aaa3SRalf Baechle } 711da177e4SLinus Torvalds 72ea52a0b5SJakub Kicinski dev_addr_set(dev, sa->sa_data); 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds return 0; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds static int rose_open(struct net_device *dev) 781da177e4SLinus Torvalds { 79a159aaa3SRalf Baechle int err; 80a159aaa3SRalf Baechle 81*db957324SJakub Kicinski err = rose_add_loopback_node((const rose_address *)dev->dev_addr); 82a159aaa3SRalf Baechle if (err) 83a159aaa3SRalf Baechle return err; 84a159aaa3SRalf Baechle 851da177e4SLinus Torvalds netif_start_queue(dev); 86a159aaa3SRalf Baechle 871da177e4SLinus Torvalds return 0; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds static int rose_close(struct net_device *dev) 911da177e4SLinus Torvalds { 921da177e4SLinus Torvalds netif_stop_queue(dev); 93*db957324SJakub Kicinski rose_del_loopback_node((const rose_address *)dev->dev_addr); 941da177e4SLinus Torvalds return 0; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 9736e4d64aSStephen Hemminger static netdev_tx_t rose_xmit(struct sk_buff *skb, struct net_device *dev) 981da177e4SLinus Torvalds { 99d289d120SStephen Hemminger struct net_device_stats *stats = &dev->stats; 10003ec2ac0SEric W. Biederman unsigned int len = skb->len; 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds if (!netif_running(dev)) { 1031da177e4SLinus Torvalds printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); 1045b548140SPatrick McHardy return NETDEV_TX_BUSY; 1051da177e4SLinus Torvalds } 10603ec2ac0SEric W. Biederman 10703ec2ac0SEric W. Biederman if (!rose_route_frame(skb, NULL)) { 1081da177e4SLinus Torvalds dev_kfree_skb(skb); 1091da177e4SLinus Torvalds stats->tx_errors++; 1106ed10654SPatrick McHardy return NETDEV_TX_OK; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 11303ec2ac0SEric W. Biederman stats->tx_packets++; 11403ec2ac0SEric W. Biederman stats->tx_bytes += len; 11503ec2ac0SEric W. Biederman return NETDEV_TX_OK; 11603ec2ac0SEric W. Biederman } 11703ec2ac0SEric W. Biederman 1183b04dddeSStephen Hemminger static const struct header_ops rose_header_ops = { 1193b04dddeSStephen Hemminger .create = rose_header, 1203b04dddeSStephen Hemminger }; 1213b04dddeSStephen Hemminger 1223170c656SStephen Hemminger static const struct net_device_ops rose_netdev_ops = { 1233170c656SStephen Hemminger .ndo_open = rose_open, 1243170c656SStephen Hemminger .ndo_stop = rose_close, 1253170c656SStephen Hemminger .ndo_start_xmit = rose_xmit, 1263170c656SStephen Hemminger .ndo_set_mac_address = rose_set_mac_address, 1273170c656SStephen Hemminger }; 1283170c656SStephen Hemminger 1291da177e4SLinus Torvalds void rose_setup(struct net_device *dev) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds dev->mtu = ROSE_MAX_PACKET_SIZE - 2; 1323170c656SStephen Hemminger dev->netdev_ops = &rose_netdev_ops; 1331da177e4SLinus Torvalds 1343b04dddeSStephen Hemminger dev->header_ops = &rose_header_ops; 1351da177e4SLinus Torvalds dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; 1361da177e4SLinus Torvalds dev->addr_len = ROSE_ADDR_LEN; 1371da177e4SLinus Torvalds dev->type = ARPHRD_ROSE; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* New-style flags. */ 140d2ce4bc3SRalf Baechle dev->flags = IFF_NOARP; 1411da177e4SLinus Torvalds } 142