162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Linux ARCnet driver - RFC1201 (standard) packet encapsulation
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Written 1994-1999 by Avery Pennarun.
562306a36Sopenharmony_ci * Derived from skeleton.c by Donald Becker.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
862306a36Sopenharmony_ci *  for sponsoring the further development of this driver.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * **********************
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * The original copyright of skeleton.c was as follows:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * skeleton.c Written 1993 by Donald Becker.
1562306a36Sopenharmony_ci * Copyright 1993 United States Government as represented by the
1662306a36Sopenharmony_ci * Director, National Security Agency.  This software may only be used
1762306a36Sopenharmony_ci * and distributed according to the terms of the GNU General Public License as
1862306a36Sopenharmony_ci * modified by SRC, incorporated herein by reference.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * **********************
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * For more details, see drivers/net/arcnet.c
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * **********************
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/gfp.h>
3062306a36Sopenharmony_ci#include <linux/module.h>
3162306a36Sopenharmony_ci#include <linux/init.h>
3262306a36Sopenharmony_ci#include <linux/if_arp.h>
3362306a36Sopenharmony_ci#include <linux/netdevice.h>
3462306a36Sopenharmony_ci#include <linux/skbuff.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "arcdevice.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
4162306a36Sopenharmony_cistatic void rx(struct net_device *dev, int bufnum,
4262306a36Sopenharmony_ci	       struct archdr *pkthdr, int length);
4362306a36Sopenharmony_cistatic int build_header(struct sk_buff *skb, struct net_device *dev,
4462306a36Sopenharmony_ci			unsigned short type, uint8_t daddr);
4562306a36Sopenharmony_cistatic int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
4662306a36Sopenharmony_ci		      int bufnum);
4762306a36Sopenharmony_cistatic int continue_tx(struct net_device *dev, int bufnum);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct ArcProto rfc1201_proto = {
5062306a36Sopenharmony_ci	.suffix		= 'a',
5162306a36Sopenharmony_ci	.mtu		= 1500,	/* could be more, but some receivers can't handle it... */
5262306a36Sopenharmony_ci	.is_ip          = 1,    /* This is for sending IP and ARP packages */
5362306a36Sopenharmony_ci	.rx		= rx,
5462306a36Sopenharmony_ci	.build_header	= build_header,
5562306a36Sopenharmony_ci	.prepare_tx	= prepare_tx,
5662306a36Sopenharmony_ci	.continue_tx	= continue_tx,
5762306a36Sopenharmony_ci	.ack_tx         = NULL
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int __init arcnet_rfc1201_init(void)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	pr_info("%s\n", "RFC1201 \"standard\" (`a') encapsulation support loaded");
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	arc_proto_map[ARC_P_IP]
6562306a36Sopenharmony_ci	    = arc_proto_map[ARC_P_IPV6]
6662306a36Sopenharmony_ci	    = arc_proto_map[ARC_P_ARP]
6762306a36Sopenharmony_ci	    = arc_proto_map[ARC_P_RARP]
6862306a36Sopenharmony_ci	    = arc_proto_map[ARC_P_IPX]
6962306a36Sopenharmony_ci	    = arc_proto_map[ARC_P_NOVELL_EC]
7062306a36Sopenharmony_ci	    = &rfc1201_proto;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* if someone else already owns the broadcast, we won't take it */
7362306a36Sopenharmony_ci	if (arc_bcast_proto == arc_proto_default)
7462306a36Sopenharmony_ci		arc_bcast_proto = &rfc1201_proto;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return 0;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic void __exit arcnet_rfc1201_exit(void)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	arcnet_unregister_proto(&rfc1201_proto);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cimodule_init(arcnet_rfc1201_init);
8562306a36Sopenharmony_cimodule_exit(arcnet_rfc1201_exit);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Determine a packet's protocol ID.
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * With ARCnet we have to convert everything to Ethernet-style stuff.
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistatic __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct archdr *pkt = (struct archdr *)skb->data;
9462306a36Sopenharmony_ci	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
9562306a36Sopenharmony_ci	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* Pull off the arcnet header. */
9862306a36Sopenharmony_ci	skb_reset_mac_header(skb);
9962306a36Sopenharmony_ci	skb_pull(skb, hdr_size);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (pkt->hard.dest == 0) {
10262306a36Sopenharmony_ci		skb->pkt_type = PACKET_BROADCAST;
10362306a36Sopenharmony_ci	} else if (dev->flags & IFF_PROMISC) {
10462306a36Sopenharmony_ci		/* if we're not sending to ourselves :) */
10562306a36Sopenharmony_ci		if (pkt->hard.dest != dev->dev_addr[0])
10662306a36Sopenharmony_ci			skb->pkt_type = PACKET_OTHERHOST;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci	/* now return the protocol number */
10962306a36Sopenharmony_ci	switch (soft->proto) {
11062306a36Sopenharmony_ci	case ARC_P_IP:
11162306a36Sopenharmony_ci		return htons(ETH_P_IP);
11262306a36Sopenharmony_ci	case ARC_P_IPV6:
11362306a36Sopenharmony_ci		return htons(ETH_P_IPV6);
11462306a36Sopenharmony_ci	case ARC_P_ARP:
11562306a36Sopenharmony_ci		return htons(ETH_P_ARP);
11662306a36Sopenharmony_ci	case ARC_P_RARP:
11762306a36Sopenharmony_ci		return htons(ETH_P_RARP);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	case ARC_P_IPX:
12062306a36Sopenharmony_ci	case ARC_P_NOVELL_EC:
12162306a36Sopenharmony_ci		return htons(ETH_P_802_3);
12262306a36Sopenharmony_ci	default:
12362306a36Sopenharmony_ci		dev->stats.rx_errors++;
12462306a36Sopenharmony_ci		dev->stats.rx_crc_errors++;
12562306a36Sopenharmony_ci		return 0;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return htons(ETH_P_IP);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* packet receiver */
13262306a36Sopenharmony_cistatic void rx(struct net_device *dev, int bufnum,
13362306a36Sopenharmony_ci	       struct archdr *pkthdr, int length)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	struct arcnet_local *lp = netdev_priv(dev);
13662306a36Sopenharmony_ci	struct sk_buff *skb;
13762306a36Sopenharmony_ci	struct archdr *pkt = pkthdr;
13862306a36Sopenharmony_ci	struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201;
13962306a36Sopenharmony_ci	int saddr = pkt->hard.source, ofs;
14062306a36Sopenharmony_ci	struct Incoming *in = &lp->rfc1201.incoming[saddr];
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	arc_printk(D_DURING, dev, "it's an RFC1201 packet (length=%d)\n",
14362306a36Sopenharmony_ci		   length);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (length >= MinTU)
14662306a36Sopenharmony_ci		ofs = 512 - length;
14762306a36Sopenharmony_ci	else
14862306a36Sopenharmony_ci		ofs = 256 - length;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (soft->split_flag == 0xFF) {		/* Exception Packet */
15162306a36Sopenharmony_ci		if (length >= 4 + RFC1201_HDR_SIZE) {
15262306a36Sopenharmony_ci			arc_printk(D_DURING, dev, "compensating for exception packet\n");
15362306a36Sopenharmony_ci		} else {
15462306a36Sopenharmony_ci			arc_printk(D_EXTRA, dev, "short RFC1201 exception packet from %02Xh",
15562306a36Sopenharmony_ci				   saddr);
15662306a36Sopenharmony_ci			return;
15762306a36Sopenharmony_ci		}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		/* skip over 4-byte junkola */
16062306a36Sopenharmony_ci		length -= 4;
16162306a36Sopenharmony_ci		ofs += 4;
16262306a36Sopenharmony_ci		lp->hw.copy_from_card(dev, bufnum, 512 - length,
16362306a36Sopenharmony_ci				      soft, sizeof(pkt->soft));
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci	if (!soft->split_flag) {	/* not split */
16662306a36Sopenharmony_ci		arc_printk(D_RX, dev, "incoming is not split (splitflag=%d)\n",
16762306a36Sopenharmony_ci			   soft->split_flag);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		if (in->skb) {	/* already assembling one! */
17062306a36Sopenharmony_ci			arc_printk(D_EXTRA, dev, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
17162306a36Sopenharmony_ci				   in->sequence, soft->split_flag,
17262306a36Sopenharmony_ci				   soft->sequence);
17362306a36Sopenharmony_ci			lp->rfc1201.aborted_seq = soft->sequence;
17462306a36Sopenharmony_ci			dev_kfree_skb_irq(in->skb);
17562306a36Sopenharmony_ci			dev->stats.rx_errors++;
17662306a36Sopenharmony_ci			dev->stats.rx_missed_errors++;
17762306a36Sopenharmony_ci			in->skb = NULL;
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci		in->sequence = soft->sequence;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
18262306a36Sopenharmony_ci		if (!skb) {
18362306a36Sopenharmony_ci			dev->stats.rx_dropped++;
18462306a36Sopenharmony_ci			return;
18562306a36Sopenharmony_ci		}
18662306a36Sopenharmony_ci		skb_put(skb, length + ARC_HDR_SIZE);
18762306a36Sopenharmony_ci		skb->dev = dev;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		pkt = (struct archdr *)skb->data;
19062306a36Sopenharmony_ci		soft = &pkt->soft.rfc1201;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		/* up to sizeof(pkt->soft) has already
19362306a36Sopenharmony_ci		 * been copied from the card
19462306a36Sopenharmony_ci		 */
19562306a36Sopenharmony_ci		memcpy(pkt, pkthdr, sizeof(struct archdr));
19662306a36Sopenharmony_ci		if (length > sizeof(pkt->soft))
19762306a36Sopenharmony_ci			lp->hw.copy_from_card(dev, bufnum,
19862306a36Sopenharmony_ci					      ofs + sizeof(pkt->soft),
19962306a36Sopenharmony_ci					      pkt->soft.raw + sizeof(pkt->soft),
20062306a36Sopenharmony_ci					      length - sizeof(pkt->soft));
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		/* ARP packets have problems when sent from some DOS systems:
20362306a36Sopenharmony_ci		 * the source address is always 0!
20462306a36Sopenharmony_ci		 * So we take the hardware source addr (which is impossible
20562306a36Sopenharmony_ci		 * to fumble) and insert it ourselves.
20662306a36Sopenharmony_ci		 */
20762306a36Sopenharmony_ci		if (soft->proto == ARC_P_ARP) {
20862306a36Sopenharmony_ci			struct arphdr *arp = (struct arphdr *)soft->payload;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci			/* make sure addresses are the right length */
21162306a36Sopenharmony_ci			if (arp->ar_hln == 1 && arp->ar_pln == 4) {
21262306a36Sopenharmony_ci				uint8_t *cptr = (uint8_t *)arp + sizeof(struct arphdr);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci				if (!*cptr) {	/* is saddr = 00? */
21562306a36Sopenharmony_ci					arc_printk(D_EXTRA, dev,
21662306a36Sopenharmony_ci						   "ARP source address was 00h, set to %02Xh\n",
21762306a36Sopenharmony_ci						   saddr);
21862306a36Sopenharmony_ci					dev->stats.rx_crc_errors++;
21962306a36Sopenharmony_ci					*cptr = saddr;
22062306a36Sopenharmony_ci				} else {
22162306a36Sopenharmony_ci					arc_printk(D_DURING, dev, "ARP source address (%Xh) is fine.\n",
22262306a36Sopenharmony_ci						   *cptr);
22362306a36Sopenharmony_ci				}
22462306a36Sopenharmony_ci			} else {
22562306a36Sopenharmony_ci				arc_printk(D_NORMAL, dev, "funny-shaped ARP packet. (%Xh, %Xh)\n",
22662306a36Sopenharmony_ci					   arp->ar_hln, arp->ar_pln);
22762306a36Sopenharmony_ci				dev->stats.rx_errors++;
22862306a36Sopenharmony_ci				dev->stats.rx_crc_errors++;
22962306a36Sopenharmony_ci			}
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci		if (BUGLVL(D_SKB))
23262306a36Sopenharmony_ci			arcnet_dump_skb(dev, skb, "rx");
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		skb->protocol = type_trans(skb, dev);
23562306a36Sopenharmony_ci		netif_rx(skb);
23662306a36Sopenharmony_ci	} else {		/* split packet */
23762306a36Sopenharmony_ci		/* NOTE: MSDOS ARP packet correction should only need to
23862306a36Sopenharmony_ci		 * apply to unsplit packets, since ARP packets are so short.
23962306a36Sopenharmony_ci		 *
24062306a36Sopenharmony_ci		 * My interpretation of the RFC1201 document is that if a
24162306a36Sopenharmony_ci		 * packet is received out of order, the entire assembly
24262306a36Sopenharmony_ci		 * process should be aborted.
24362306a36Sopenharmony_ci		 *
24462306a36Sopenharmony_ci		 * The RFC also mentions "it is possible for successfully
24562306a36Sopenharmony_ci		 * received packets to be retransmitted." As of 0.40 all
24662306a36Sopenharmony_ci		 * previously received packets are allowed, not just the
24762306a36Sopenharmony_ci		 * most recent one.
24862306a36Sopenharmony_ci		 *
24962306a36Sopenharmony_ci		 * We allow multiple assembly processes, one for each
25062306a36Sopenharmony_ci		 * ARCnet card possible on the network.
25162306a36Sopenharmony_ci		 * Seems rather like a waste of memory, but there's no
25262306a36Sopenharmony_ci		 * other way to be reliable.
25362306a36Sopenharmony_ci		 */
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		arc_printk(D_RX, dev, "packet is split (splitflag=%d, seq=%d)\n",
25662306a36Sopenharmony_ci			   soft->split_flag, in->sequence);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		if (in->skb && in->sequence != soft->sequence) {
25962306a36Sopenharmony_ci			arc_printk(D_EXTRA, dev, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
26062306a36Sopenharmony_ci				   saddr, in->sequence, soft->sequence,
26162306a36Sopenharmony_ci				   soft->split_flag);
26262306a36Sopenharmony_ci			dev_kfree_skb_irq(in->skb);
26362306a36Sopenharmony_ci			in->skb = NULL;
26462306a36Sopenharmony_ci			dev->stats.rx_errors++;
26562306a36Sopenharmony_ci			dev->stats.rx_missed_errors++;
26662306a36Sopenharmony_ci			in->lastpacket = in->numpackets = 0;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci		if (soft->split_flag & 1) {	/* first packet in split */
26962306a36Sopenharmony_ci			arc_printk(D_RX, dev, "brand new splitpacket (splitflag=%d)\n",
27062306a36Sopenharmony_ci				   soft->split_flag);
27162306a36Sopenharmony_ci			if (in->skb) {	/* already assembling one! */
27262306a36Sopenharmony_ci				arc_printk(D_EXTRA, dev, "aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
27362306a36Sopenharmony_ci					   in->sequence, soft->split_flag,
27462306a36Sopenharmony_ci					   soft->sequence);
27562306a36Sopenharmony_ci				dev->stats.rx_errors++;
27662306a36Sopenharmony_ci				dev->stats.rx_missed_errors++;
27762306a36Sopenharmony_ci				dev_kfree_skb_irq(in->skb);
27862306a36Sopenharmony_ci			}
27962306a36Sopenharmony_ci			in->sequence = soft->sequence;
28062306a36Sopenharmony_ci			in->numpackets = ((unsigned)soft->split_flag >> 1) + 2;
28162306a36Sopenharmony_ci			in->lastpacket = 1;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci			if (in->numpackets > 16) {
28462306a36Sopenharmony_ci				arc_printk(D_EXTRA, dev, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
28562306a36Sopenharmony_ci					   soft->split_flag);
28662306a36Sopenharmony_ci				lp->rfc1201.aborted_seq = soft->sequence;
28762306a36Sopenharmony_ci				dev->stats.rx_errors++;
28862306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
28962306a36Sopenharmony_ci				return;
29062306a36Sopenharmony_ci			}
29162306a36Sopenharmony_ci			in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE,
29262306a36Sopenharmony_ci						  GFP_ATOMIC);
29362306a36Sopenharmony_ci			if (!skb) {
29462306a36Sopenharmony_ci				arc_printk(D_NORMAL, dev, "(split) memory squeeze, dropping packet.\n");
29562306a36Sopenharmony_ci				lp->rfc1201.aborted_seq = soft->sequence;
29662306a36Sopenharmony_ci				dev->stats.rx_dropped++;
29762306a36Sopenharmony_ci				return;
29862306a36Sopenharmony_ci			}
29962306a36Sopenharmony_ci			skb->dev = dev;
30062306a36Sopenharmony_ci			pkt = (struct archdr *)skb->data;
30162306a36Sopenharmony_ci			soft = &pkt->soft.rfc1201;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci			memcpy(pkt, pkthdr, ARC_HDR_SIZE + RFC1201_HDR_SIZE);
30462306a36Sopenharmony_ci			skb_put(skb, ARC_HDR_SIZE + RFC1201_HDR_SIZE);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci			soft->split_flag = 0;	/* end result won't be split */
30762306a36Sopenharmony_ci		} else {	/* not first packet */
30862306a36Sopenharmony_ci			int packetnum = ((unsigned)soft->split_flag >> 1) + 1;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci			/* if we're not assembling, there's no point trying to
31162306a36Sopenharmony_ci			 * continue.
31262306a36Sopenharmony_ci			 */
31362306a36Sopenharmony_ci			if (!in->skb) {
31462306a36Sopenharmony_ci				if (lp->rfc1201.aborted_seq != soft->sequence) {
31562306a36Sopenharmony_ci					arc_printk(D_EXTRA, dev, "can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n",
31662306a36Sopenharmony_ci						   soft->split_flag,
31762306a36Sopenharmony_ci						   soft->sequence,
31862306a36Sopenharmony_ci						   lp->rfc1201.aborted_seq);
31962306a36Sopenharmony_ci					dev->stats.rx_errors++;
32062306a36Sopenharmony_ci					dev->stats.rx_missed_errors++;
32162306a36Sopenharmony_ci				}
32262306a36Sopenharmony_ci				return;
32362306a36Sopenharmony_ci			}
32462306a36Sopenharmony_ci			in->lastpacket++;
32562306a36Sopenharmony_ci			/* if not the right flag */
32662306a36Sopenharmony_ci			if (packetnum != in->lastpacket) {
32762306a36Sopenharmony_ci				/* harmless duplicate? ignore. */
32862306a36Sopenharmony_ci				if (packetnum <= in->lastpacket - 1) {
32962306a36Sopenharmony_ci					arc_printk(D_EXTRA, dev, "duplicate splitpacket ignored! (splitflag=%d)\n",
33062306a36Sopenharmony_ci						   soft->split_flag);
33162306a36Sopenharmony_ci					dev->stats.rx_errors++;
33262306a36Sopenharmony_ci					dev->stats.rx_frame_errors++;
33362306a36Sopenharmony_ci					return;
33462306a36Sopenharmony_ci				}
33562306a36Sopenharmony_ci				/* "bad" duplicate, kill reassembly */
33662306a36Sopenharmony_ci				arc_printk(D_EXTRA, dev, "out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
33762306a36Sopenharmony_ci					   in->sequence, soft->split_flag,
33862306a36Sopenharmony_ci					   soft->sequence);
33962306a36Sopenharmony_ci				lp->rfc1201.aborted_seq = soft->sequence;
34062306a36Sopenharmony_ci				dev_kfree_skb_irq(in->skb);
34162306a36Sopenharmony_ci				in->skb = NULL;
34262306a36Sopenharmony_ci				dev->stats.rx_errors++;
34362306a36Sopenharmony_ci				dev->stats.rx_missed_errors++;
34462306a36Sopenharmony_ci				in->lastpacket = in->numpackets = 0;
34562306a36Sopenharmony_ci				return;
34662306a36Sopenharmony_ci			}
34762306a36Sopenharmony_ci			pkt = (struct archdr *)in->skb->data;
34862306a36Sopenharmony_ci			soft = &pkt->soft.rfc1201;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		skb = in->skb;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		lp->hw.copy_from_card(dev, bufnum, ofs + RFC1201_HDR_SIZE,
35462306a36Sopenharmony_ci				      skb->data + skb->len,
35562306a36Sopenharmony_ci				      length - RFC1201_HDR_SIZE);
35662306a36Sopenharmony_ci		skb_put(skb, length - RFC1201_HDR_SIZE);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		/* are we done? */
35962306a36Sopenharmony_ci		if (in->lastpacket == in->numpackets) {
36062306a36Sopenharmony_ci			in->skb = NULL;
36162306a36Sopenharmony_ci			in->lastpacket = in->numpackets = 0;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci			arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (unsplit)\n",
36462306a36Sopenharmony_ci				   skb->len, pkt->hard.source);
36562306a36Sopenharmony_ci			arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (split)\n",
36662306a36Sopenharmony_ci				   skb->len, pkt->hard.source);
36762306a36Sopenharmony_ci			if (BUGLVL(D_SKB))
36862306a36Sopenharmony_ci				arcnet_dump_skb(dev, skb, "rx");
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci			skb->protocol = type_trans(skb, dev);
37162306a36Sopenharmony_ci			netif_rx(skb);
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/* Create the ARCnet hard/soft headers for RFC1201. */
37762306a36Sopenharmony_cistatic int build_header(struct sk_buff *skb, struct net_device *dev,
37862306a36Sopenharmony_ci			unsigned short type, uint8_t daddr)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	struct arcnet_local *lp = netdev_priv(dev);
38162306a36Sopenharmony_ci	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
38262306a36Sopenharmony_ci	struct archdr *pkt = skb_push(skb, hdr_size);
38362306a36Sopenharmony_ci	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* set the protocol ID according to RFC1201 */
38662306a36Sopenharmony_ci	switch (type) {
38762306a36Sopenharmony_ci	case ETH_P_IP:
38862306a36Sopenharmony_ci		soft->proto = ARC_P_IP;
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci	case ETH_P_IPV6:
39162306a36Sopenharmony_ci		soft->proto = ARC_P_IPV6;
39262306a36Sopenharmony_ci		break;
39362306a36Sopenharmony_ci	case ETH_P_ARP:
39462306a36Sopenharmony_ci		soft->proto = ARC_P_ARP;
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci	case ETH_P_RARP:
39762306a36Sopenharmony_ci		soft->proto = ARC_P_RARP;
39862306a36Sopenharmony_ci		break;
39962306a36Sopenharmony_ci	case ETH_P_IPX:
40062306a36Sopenharmony_ci	case ETH_P_802_3:
40162306a36Sopenharmony_ci	case ETH_P_802_2:
40262306a36Sopenharmony_ci		soft->proto = ARC_P_IPX;
40362306a36Sopenharmony_ci		break;
40462306a36Sopenharmony_ci	case ETH_P_ATALK:
40562306a36Sopenharmony_ci		soft->proto = ARC_P_ATALK;
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci	default:
40862306a36Sopenharmony_ci		arc_printk(D_NORMAL, dev, "RFC1201: I don't understand protocol %d (%Xh)\n",
40962306a36Sopenharmony_ci			   type, type);
41062306a36Sopenharmony_ci		dev->stats.tx_errors++;
41162306a36Sopenharmony_ci		dev->stats.tx_aborted_errors++;
41262306a36Sopenharmony_ci		return 0;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* Set the source hardware address.
41662306a36Sopenharmony_ci	 *
41762306a36Sopenharmony_ci	 * This is pretty pointless for most purposes, but it can help in
41862306a36Sopenharmony_ci	 * debugging.  ARCnet does not allow us to change the source address
41962306a36Sopenharmony_ci	 * in the actual packet sent.
42062306a36Sopenharmony_ci	 */
42162306a36Sopenharmony_ci	pkt->hard.source = *dev->dev_addr;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	soft->sequence = htons(lp->rfc1201.sequence++);
42462306a36Sopenharmony_ci	soft->split_flag = 0;	/* split packets are done elsewhere */
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* see linux/net/ethernet/eth.c to see where I got the following */
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
42962306a36Sopenharmony_ci		/* FIXME: fill in the last byte of the dest ipaddr here
43062306a36Sopenharmony_ci		 * to better comply with RFC1051 in "noarp" mode.
43162306a36Sopenharmony_ci		 * For now, always broadcasting will probably at least get
43262306a36Sopenharmony_ci		 * packets sent out :)
43362306a36Sopenharmony_ci		 */
43462306a36Sopenharmony_ci		pkt->hard.dest = 0;
43562306a36Sopenharmony_ci		return hdr_size;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci	/* otherwise, drop in the dest address */
43862306a36Sopenharmony_ci	pkt->hard.dest = daddr;
43962306a36Sopenharmony_ci	return hdr_size;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic void load_pkt(struct net_device *dev, struct arc_hardware *hard,
44362306a36Sopenharmony_ci		     struct arc_rfc1201 *soft, int softlen, int bufnum)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct arcnet_local *lp = netdev_priv(dev);
44662306a36Sopenharmony_ci	int ofs;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	/* assume length <= XMTU: someone should have handled that by now. */
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (softlen > MinTU) {
45162306a36Sopenharmony_ci		hard->offset[0] = 0;
45262306a36Sopenharmony_ci		hard->offset[1] = ofs = 512 - softlen;
45362306a36Sopenharmony_ci	} else if (softlen > MTU) {	/* exception packet - add an extra header */
45462306a36Sopenharmony_ci		struct arc_rfc1201 excsoft;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		excsoft.proto = soft->proto;
45762306a36Sopenharmony_ci		excsoft.split_flag = 0xff;
45862306a36Sopenharmony_ci		excsoft.sequence = htons(0xffff);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		hard->offset[0] = 0;
46162306a36Sopenharmony_ci		ofs = 512 - softlen;
46262306a36Sopenharmony_ci		hard->offset[1] = ofs - RFC1201_HDR_SIZE;
46362306a36Sopenharmony_ci		lp->hw.copy_to_card(dev, bufnum, ofs - RFC1201_HDR_SIZE,
46462306a36Sopenharmony_ci				    &excsoft, RFC1201_HDR_SIZE);
46562306a36Sopenharmony_ci	} else {
46662306a36Sopenharmony_ci		hard->offset[0] = ofs = 256 - softlen;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
47062306a36Sopenharmony_ci	lp->hw.copy_to_card(dev, bufnum, ofs, soft, softlen);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	lp->lastload_dest = hard->dest;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
47662306a36Sopenharmony_ci		      int bufnum)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct arcnet_local *lp = netdev_priv(dev);
47962306a36Sopenharmony_ci	const int maxsegsize = XMTU - RFC1201_HDR_SIZE;
48062306a36Sopenharmony_ci	struct Outgoing *out;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
48362306a36Sopenharmony_ci		   lp->next_tx, lp->cur_tx, bufnum);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* hard header is not included in packet length */
48662306a36Sopenharmony_ci	length -= ARC_HDR_SIZE;
48762306a36Sopenharmony_ci	pkt->soft.rfc1201.split_flag = 0;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* need to do a split packet? */
49062306a36Sopenharmony_ci	if (length > XMTU) {
49162306a36Sopenharmony_ci		out = &lp->outgoing;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		out->length = length - RFC1201_HDR_SIZE;
49462306a36Sopenharmony_ci		out->dataleft = lp->outgoing.length;
49562306a36Sopenharmony_ci		out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize;
49662306a36Sopenharmony_ci		out->segnum = 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		arc_printk(D_DURING, dev, "rfc1201 prep_tx: ready for %d-segment split (%d bytes, seq=%d)\n",
49962306a36Sopenharmony_ci			   out->numsegs, out->length,
50062306a36Sopenharmony_ci			   pkt->soft.rfc1201.sequence);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		return 0;	/* not done */
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci	/* just load the packet into the buffers and send it off */
50562306a36Sopenharmony_ci	load_pkt(dev, &pkt->hard, &pkt->soft.rfc1201, length, bufnum);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	return 1;		/* done */
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int continue_tx(struct net_device *dev, int bufnum)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct arcnet_local *lp = netdev_priv(dev);
51362306a36Sopenharmony_ci	struct Outgoing *out = &lp->outgoing;
51462306a36Sopenharmony_ci	struct arc_hardware *hard = &out->pkt->hard;
51562306a36Sopenharmony_ci	struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft;
51662306a36Sopenharmony_ci	int maxsegsize = XMTU - RFC1201_HDR_SIZE;
51762306a36Sopenharmony_ci	int seglen;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	arc_printk(D_DURING, dev,
52062306a36Sopenharmony_ci		   "rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n",
52162306a36Sopenharmony_ci		   out->segnum, out->numsegs, soft->sequence);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* the "new" soft header comes right before the data chunk */
52462306a36Sopenharmony_ci	newsoft = (struct arc_rfc1201 *)
52562306a36Sopenharmony_ci	    (out->pkt->soft.raw + out->length - out->dataleft);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (!out->segnum)	/* first packet; newsoft == soft */
52862306a36Sopenharmony_ci		newsoft->split_flag = ((out->numsegs - 2) << 1) | 1;
52962306a36Sopenharmony_ci	else {
53062306a36Sopenharmony_ci		newsoft->split_flag = out->segnum << 1;
53162306a36Sopenharmony_ci		newsoft->proto = soft->proto;
53262306a36Sopenharmony_ci		newsoft->sequence = soft->sequence;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	seglen = maxsegsize;
53662306a36Sopenharmony_ci	if (seglen > out->dataleft)
53762306a36Sopenharmony_ci		seglen = out->dataleft;
53862306a36Sopenharmony_ci	out->dataleft -= seglen;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	load_pkt(dev, hard, newsoft, seglen + RFC1201_HDR_SIZE, bufnum);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	out->segnum++;
54362306a36Sopenharmony_ci	if (out->segnum >= out->numsegs)
54462306a36Sopenharmony_ci		return 1;
54562306a36Sopenharmony_ci	else
54662306a36Sopenharmony_ci		return 0;
54762306a36Sopenharmony_ci}
548