rose_dev.c (2994B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * 4 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 5 */ 6#include <linux/module.h> 7#include <linux/proc_fs.h> 8#include <linux/kernel.h> 9#include <linux/interrupt.h> 10#include <linux/fs.h> 11#include <linux/types.h> 12#include <linux/sysctl.h> 13#include <linux/string.h> 14#include <linux/socket.h> 15#include <linux/errno.h> 16#include <linux/fcntl.h> 17#include <linux/in.h> 18#include <linux/if_ether.h> 19#include <linux/slab.h> 20 21#include <asm/io.h> 22 23#include <linux/inet.h> 24#include <linux/netdevice.h> 25#include <linux/etherdevice.h> 26#include <linux/if_arp.h> 27#include <linux/skbuff.h> 28 29#include <net/ip.h> 30#include <net/arp.h> 31 32#include <net/ax25.h> 33#include <net/rose.h> 34 35static int rose_header(struct sk_buff *skb, struct net_device *dev, 36 unsigned short type, 37 const void *daddr, const void *saddr, unsigned int len) 38{ 39 unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2); 40 41 if (daddr) 42 memcpy(buff + 7, daddr, dev->addr_len); 43 44 *buff++ = ROSE_GFI | ROSE_Q_BIT; 45 *buff++ = 0x00; 46 *buff++ = ROSE_DATA; 47 *buff++ = 0x7F; 48 *buff++ = AX25_P_IP; 49 50 if (daddr != NULL) 51 return 37; 52 53 return -37; 54} 55 56static int rose_set_mac_address(struct net_device *dev, void *addr) 57{ 58 struct sockaddr *sa = addr; 59 int err; 60 61 if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) 62 return 0; 63 64 if (dev->flags & IFF_UP) { 65 err = rose_add_loopback_node((rose_address *)sa->sa_data); 66 if (err) 67 return err; 68 69 rose_del_loopback_node((const rose_address *)dev->dev_addr); 70 } 71 72 dev_addr_set(dev, sa->sa_data); 73 74 return 0; 75} 76 77static int rose_open(struct net_device *dev) 78{ 79 int err; 80 81 err = rose_add_loopback_node((const rose_address *)dev->dev_addr); 82 if (err) 83 return err; 84 85 netif_start_queue(dev); 86 87 return 0; 88} 89 90static int rose_close(struct net_device *dev) 91{ 92 netif_stop_queue(dev); 93 rose_del_loopback_node((const rose_address *)dev->dev_addr); 94 return 0; 95} 96 97static netdev_tx_t rose_xmit(struct sk_buff *skb, struct net_device *dev) 98{ 99 struct net_device_stats *stats = &dev->stats; 100 unsigned int len = skb->len; 101 102 if (!netif_running(dev)) { 103 printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); 104 return NETDEV_TX_BUSY; 105 } 106 107 if (!rose_route_frame(skb, NULL)) { 108 dev_kfree_skb(skb); 109 stats->tx_errors++; 110 return NETDEV_TX_OK; 111 } 112 113 stats->tx_packets++; 114 stats->tx_bytes += len; 115 return NETDEV_TX_OK; 116} 117 118static const struct header_ops rose_header_ops = { 119 .create = rose_header, 120}; 121 122static const struct net_device_ops rose_netdev_ops = { 123 .ndo_open = rose_open, 124 .ndo_stop = rose_close, 125 .ndo_start_xmit = rose_xmit, 126 .ndo_set_mac_address = rose_set_mac_address, 127}; 128 129void rose_setup(struct net_device *dev) 130{ 131 dev->mtu = ROSE_MAX_PACKET_SIZE - 2; 132 dev->netdev_ops = &rose_netdev_ops; 133 134 dev->header_ops = &rose_header_ops; 135 dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; 136 dev->addr_len = ROSE_ADDR_LEN; 137 dev->type = ARPHRD_ROSE; 138 139 /* New-style flags. */ 140 dev->flags = IFF_NOARP; 141}