244 lines · c
1/*2 * Linux ARCnet driver - RFC1051 ("simple" standard) packet encapsulation3 *4 * Written 1994-1999 by Avery Pennarun.5 * Derived from skeleton.c by Donald Becker.6 *7 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)8 * for sponsoring the further development of this driver.9 *10 * **********************11 *12 * The original copyright of skeleton.c was as follows:13 *14 * skeleton.c Written 1993 by Donald Becker.15 * Copyright 1993 United States Government as represented by the16 * Director, National Security Agency. This software may only be used17 * and distributed according to the terms of the GNU General Public License as18 * modified by SRC, incorporated herein by reference.19 *20 * **********************21 *22 * For more details, see drivers/net/arcnet.c23 *24 * **********************25 */26 27#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt28 29#include <linux/module.h>30#include <linux/gfp.h>31#include <linux/init.h>32#include <linux/if_arp.h>33#include <net/arp.h>34#include <linux/netdevice.h>35#include <linux/skbuff.h>36 37#include "arcdevice.h"38 39static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);40static void rx(struct net_device *dev, int bufnum,41 struct archdr *pkthdr, int length);42static int build_header(struct sk_buff *skb, struct net_device *dev,43 unsigned short type, uint8_t daddr);44static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,45 int bufnum);46 47static struct ArcProto rfc1051_proto = {48 .suffix = 's',49 .mtu = XMTU - RFC1051_HDR_SIZE,50 .is_ip = 1,51 .rx = rx,52 .build_header = build_header,53 .prepare_tx = prepare_tx,54 .continue_tx = NULL,55 .ack_tx = NULL56};57 58static int __init arcnet_rfc1051_init(void)59{60 pr_info("%s\n", "RFC1051 \"simple standard\" (`s') encapsulation support loaded");61 62 arc_proto_map[ARC_P_IP_RFC1051]63 = arc_proto_map[ARC_P_ARP_RFC1051]64 = &rfc1051_proto;65 66 /* if someone else already owns the broadcast, we won't take it */67 if (arc_bcast_proto == arc_proto_default)68 arc_bcast_proto = &rfc1051_proto;69 70 return 0;71}72 73static void __exit arcnet_rfc1051_exit(void)74{75 arcnet_unregister_proto(&rfc1051_proto);76}77 78module_init(arcnet_rfc1051_init);79module_exit(arcnet_rfc1051_exit);80 81MODULE_DESCRIPTION("ARCNet packet format (RFC 1051) module");82MODULE_LICENSE("GPL");83 84/* Determine a packet's protocol ID.85 *86 * With ARCnet we have to convert everything to Ethernet-style stuff.87 */88static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)89{90 struct archdr *pkt = (struct archdr *)skb->data;91 struct arc_rfc1051 *soft = &pkt->soft.rfc1051;92 int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;93 94 /* Pull off the arcnet header. */95 skb_reset_mac_header(skb);96 skb_pull(skb, hdr_size);97 98 if (pkt->hard.dest == 0) {99 skb->pkt_type = PACKET_BROADCAST;100 } else if (dev->flags & IFF_PROMISC) {101 /* if we're not sending to ourselves :) */102 if (pkt->hard.dest != dev->dev_addr[0])103 skb->pkt_type = PACKET_OTHERHOST;104 }105 /* now return the protocol number */106 switch (soft->proto) {107 case ARC_P_IP_RFC1051:108 return htons(ETH_P_IP);109 case ARC_P_ARP_RFC1051:110 return htons(ETH_P_ARP);111 112 default:113 dev->stats.rx_errors++;114 dev->stats.rx_crc_errors++;115 return 0;116 }117 118 return htons(ETH_P_IP);119}120 121/* packet receiver */122static void rx(struct net_device *dev, int bufnum,123 struct archdr *pkthdr, int length)124{125 struct arcnet_local *lp = netdev_priv(dev);126 struct sk_buff *skb;127 struct archdr *pkt = pkthdr;128 int ofs;129 130 arc_printk(D_DURING, dev, "it's a raw packet (length=%d)\n", length);131 132 if (length >= MinTU)133 ofs = 512 - length;134 else135 ofs = 256 - length;136 137 skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);138 if (!skb) {139 dev->stats.rx_dropped++;140 return;141 }142 skb_put(skb, length + ARC_HDR_SIZE);143 skb->dev = dev;144 145 pkt = (struct archdr *)skb->data;146 147 /* up to sizeof(pkt->soft) has already been copied from the card */148 memcpy(pkt, pkthdr, sizeof(struct archdr));149 if (length > sizeof(pkt->soft))150 lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),151 pkt->soft.raw + sizeof(pkt->soft),152 length - sizeof(pkt->soft));153 154 if (BUGLVL(D_SKB))155 arcnet_dump_skb(dev, skb, "rx");156 157 skb->protocol = type_trans(skb, dev);158 netif_rx(skb);159}160 161/* Create the ARCnet hard/soft headers for RFC1051 */162static int build_header(struct sk_buff *skb, struct net_device *dev,163 unsigned short type, uint8_t daddr)164{165 int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;166 struct archdr *pkt = skb_push(skb, hdr_size);167 struct arc_rfc1051 *soft = &pkt->soft.rfc1051;168 169 /* set the protocol ID according to RFC1051 */170 switch (type) {171 case ETH_P_IP:172 soft->proto = ARC_P_IP_RFC1051;173 break;174 case ETH_P_ARP:175 soft->proto = ARC_P_ARP_RFC1051;176 break;177 default:178 arc_printk(D_NORMAL, dev, "RFC1051: I don't understand protocol %d (%Xh)\n",179 type, type);180 dev->stats.tx_errors++;181 dev->stats.tx_aborted_errors++;182 return 0;183 }184 185 /* Set the source hardware address.186 *187 * This is pretty pointless for most purposes, but it can help in188 * debugging. ARCnet does not allow us to change the source address189 * in the actual packet sent.190 */191 pkt->hard.source = *dev->dev_addr;192 193 /* see linux/net/ethernet/eth.c to see where I got the following */194 195 if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {196 /* FIXME: fill in the last byte of the dest ipaddr here to197 * better comply with RFC1051 in "noarp" mode.198 */199 pkt->hard.dest = 0;200 return hdr_size;201 }202 /* otherwise, just fill it in and go! */203 pkt->hard.dest = daddr;204 205 return hdr_size; /* success */206}207 208static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,209 int bufnum)210{211 struct arcnet_local *lp = netdev_priv(dev);212 struct arc_hardware *hard = &pkt->hard;213 int ofs;214 215 arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",216 lp->next_tx, lp->cur_tx, bufnum);217 218 /* hard header is not included in packet length */219 length -= ARC_HDR_SIZE;220 221 if (length > XMTU) {222 /* should never happen! other people already check for this. */223 arc_printk(D_NORMAL, dev, "Bug! prepare_tx with size %d (> %d)\n",224 length, XMTU);225 length = XMTU;226 }227 if (length > MinTU) {228 hard->offset[0] = 0;229 hard->offset[1] = ofs = 512 - length;230 } else if (length > MTU) {231 hard->offset[0] = 0;232 hard->offset[1] = ofs = 512 - length - 3;233 } else {234 hard->offset[0] = ofs = 256 - length;235 }236 237 lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);238 lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length);239 240 lp->lastload_dest = hard->dest;241 242 return 1; /* done */243}244