brintos

brintos / linux-shallow public Read only

0
0
Text · 15.8 KiB · 0edf35d Raw
549 lines · c
1/*2 * Linux ARCnet driver - RFC1201 (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/gfp.h>30#include <linux/module.h>31#include <linux/init.h>32#include <linux/if_arp.h>33#include <linux/netdevice.h>34#include <linux/skbuff.h>35 36#include "arcdevice.h"37 38MODULE_DESCRIPTION("ARCNet packet format (RFC 1201) module");39MODULE_LICENSE("GPL");40 41static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);42static void rx(struct net_device *dev, int bufnum,43	       struct archdr *pkthdr, int length);44static int build_header(struct sk_buff *skb, struct net_device *dev,45			unsigned short type, uint8_t daddr);46static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,47		      int bufnum);48static int continue_tx(struct net_device *dev, int bufnum);49 50static struct ArcProto rfc1201_proto = {51	.suffix		= 'a',52	.mtu		= 1500,	/* could be more, but some receivers can't handle it... */53	.is_ip          = 1,    /* This is for sending IP and ARP packages */54	.rx		= rx,55	.build_header	= build_header,56	.prepare_tx	= prepare_tx,57	.continue_tx	= continue_tx,58	.ack_tx         = NULL59};60 61static int __init arcnet_rfc1201_init(void)62{63	pr_info("%s\n", "RFC1201 \"standard\" (`a') encapsulation support loaded");64 65	arc_proto_map[ARC_P_IP]66	    = arc_proto_map[ARC_P_IPV6]67	    = arc_proto_map[ARC_P_ARP]68	    = arc_proto_map[ARC_P_RARP]69	    = arc_proto_map[ARC_P_IPX]70	    = arc_proto_map[ARC_P_NOVELL_EC]71	    = &rfc1201_proto;72 73	/* if someone else already owns the broadcast, we won't take it */74	if (arc_bcast_proto == arc_proto_default)75		arc_bcast_proto = &rfc1201_proto;76 77	return 0;78}79 80static void __exit arcnet_rfc1201_exit(void)81{82	arcnet_unregister_proto(&rfc1201_proto);83}84 85module_init(arcnet_rfc1201_init);86module_exit(arcnet_rfc1201_exit);87 88/* Determine a packet's protocol ID.89 *90 * With ARCnet we have to convert everything to Ethernet-style stuff.91 */92static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)93{94	struct archdr *pkt = (struct archdr *)skb->data;95	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;96	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;97 98	/* Pull off the arcnet header. */99	skb_reset_mac_header(skb);100	skb_pull(skb, hdr_size);101 102	if (pkt->hard.dest == 0) {103		skb->pkt_type = PACKET_BROADCAST;104	} else if (dev->flags & IFF_PROMISC) {105		/* if we're not sending to ourselves :) */106		if (pkt->hard.dest != dev->dev_addr[0])107			skb->pkt_type = PACKET_OTHERHOST;108	}109	/* now return the protocol number */110	switch (soft->proto) {111	case ARC_P_IP:112		return htons(ETH_P_IP);113	case ARC_P_IPV6:114		return htons(ETH_P_IPV6);115	case ARC_P_ARP:116		return htons(ETH_P_ARP);117	case ARC_P_RARP:118		return htons(ETH_P_RARP);119 120	case ARC_P_IPX:121	case ARC_P_NOVELL_EC:122		return htons(ETH_P_802_3);123	default:124		dev->stats.rx_errors++;125		dev->stats.rx_crc_errors++;126		return 0;127	}128 129	return htons(ETH_P_IP);130}131 132/* packet receiver */133static void rx(struct net_device *dev, int bufnum,134	       struct archdr *pkthdr, int length)135{136	struct arcnet_local *lp = netdev_priv(dev);137	struct sk_buff *skb;138	struct archdr *pkt = pkthdr;139	struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201;140	int saddr = pkt->hard.source, ofs;141	struct Incoming *in = &lp->rfc1201.incoming[saddr];142 143	arc_printk(D_DURING, dev, "it's an RFC1201 packet (length=%d)\n",144		   length);145 146	if (length >= MinTU)147		ofs = 512 - length;148	else149		ofs = 256 - length;150 151	if (soft->split_flag == 0xFF) {		/* Exception Packet */152		if (length >= 4 + RFC1201_HDR_SIZE) {153			arc_printk(D_DURING, dev, "compensating for exception packet\n");154		} else {155			arc_printk(D_EXTRA, dev, "short RFC1201 exception packet from %02Xh",156				   saddr);157			return;158		}159 160		/* skip over 4-byte junkola */161		length -= 4;162		ofs += 4;163		lp->hw.copy_from_card(dev, bufnum, 512 - length,164				      soft, sizeof(pkt->soft));165	}166	if (!soft->split_flag) {	/* not split */167		arc_printk(D_RX, dev, "incoming is not split (splitflag=%d)\n",168			   soft->split_flag);169 170		if (in->skb) {	/* already assembling one! */171			arc_printk(D_EXTRA, dev, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",172				   in->sequence, soft->split_flag,173				   soft->sequence);174			lp->rfc1201.aborted_seq = soft->sequence;175			dev_kfree_skb_irq(in->skb);176			dev->stats.rx_errors++;177			dev->stats.rx_missed_errors++;178			in->skb = NULL;179		}180		in->sequence = soft->sequence;181 182		skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);183		if (!skb) {184			dev->stats.rx_dropped++;185			return;186		}187		skb_put(skb, length + ARC_HDR_SIZE);188		skb->dev = dev;189 190		pkt = (struct archdr *)skb->data;191		soft = &pkt->soft.rfc1201;192 193		/* up to sizeof(pkt->soft) has already194		 * been copied from the card195		 */196		memcpy(pkt, pkthdr, sizeof(struct archdr));197		if (length > sizeof(pkt->soft))198			lp->hw.copy_from_card(dev, bufnum,199					      ofs + sizeof(pkt->soft),200					      pkt->soft.raw + sizeof(pkt->soft),201					      length - sizeof(pkt->soft));202 203		/* ARP packets have problems when sent from some DOS systems:204		 * the source address is always 0!205		 * So we take the hardware source addr (which is impossible206		 * to fumble) and insert it ourselves.207		 */208		if (soft->proto == ARC_P_ARP) {209			struct arphdr *arp = (struct arphdr *)soft->payload;210 211			/* make sure addresses are the right length */212			if (arp->ar_hln == 1 && arp->ar_pln == 4) {213				uint8_t *cptr = (uint8_t *)arp + sizeof(struct arphdr);214 215				if (!*cptr) {	/* is saddr = 00? */216					arc_printk(D_EXTRA, dev,217						   "ARP source address was 00h, set to %02Xh\n",218						   saddr);219					dev->stats.rx_crc_errors++;220					*cptr = saddr;221				} else {222					arc_printk(D_DURING, dev, "ARP source address (%Xh) is fine.\n",223						   *cptr);224				}225			} else {226				arc_printk(D_NORMAL, dev, "funny-shaped ARP packet. (%Xh, %Xh)\n",227					   arp->ar_hln, arp->ar_pln);228				dev->stats.rx_errors++;229				dev->stats.rx_crc_errors++;230			}231		}232		if (BUGLVL(D_SKB))233			arcnet_dump_skb(dev, skb, "rx");234 235		skb->protocol = type_trans(skb, dev);236		netif_rx(skb);237	} else {		/* split packet */238		/* NOTE: MSDOS ARP packet correction should only need to239		 * apply to unsplit packets, since ARP packets are so short.240		 *241		 * My interpretation of the RFC1201 document is that if a242		 * packet is received out of order, the entire assembly243		 * process should be aborted.244		 *245		 * The RFC also mentions "it is possible for successfully246		 * received packets to be retransmitted." As of 0.40 all247		 * previously received packets are allowed, not just the248		 * most recent one.249		 *250		 * We allow multiple assembly processes, one for each251		 * ARCnet card possible on the network.252		 * Seems rather like a waste of memory, but there's no253		 * other way to be reliable.254		 */255 256		arc_printk(D_RX, dev, "packet is split (splitflag=%d, seq=%d)\n",257			   soft->split_flag, in->sequence);258 259		if (in->skb && in->sequence != soft->sequence) {260			arc_printk(D_EXTRA, dev, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",261				   saddr, in->sequence, soft->sequence,262				   soft->split_flag);263			dev_kfree_skb_irq(in->skb);264			in->skb = NULL;265			dev->stats.rx_errors++;266			dev->stats.rx_missed_errors++;267			in->lastpacket = in->numpackets = 0;268		}269		if (soft->split_flag & 1) {	/* first packet in split */270			arc_printk(D_RX, dev, "brand new splitpacket (splitflag=%d)\n",271				   soft->split_flag);272			if (in->skb) {	/* already assembling one! */273				arc_printk(D_EXTRA, dev, "aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",274					   in->sequence, soft->split_flag,275					   soft->sequence);276				dev->stats.rx_errors++;277				dev->stats.rx_missed_errors++;278				dev_kfree_skb_irq(in->skb);279			}280			in->sequence = soft->sequence;281			in->numpackets = ((unsigned)soft->split_flag >> 1) + 2;282			in->lastpacket = 1;283 284			if (in->numpackets > 16) {285				arc_printk(D_EXTRA, dev, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",286					   soft->split_flag);287				lp->rfc1201.aborted_seq = soft->sequence;288				dev->stats.rx_errors++;289				dev->stats.rx_length_errors++;290				return;291			}292			in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE,293						  GFP_ATOMIC);294			if (!skb) {295				arc_printk(D_NORMAL, dev, "(split) memory squeeze, dropping packet.\n");296				lp->rfc1201.aborted_seq = soft->sequence;297				dev->stats.rx_dropped++;298				return;299			}300			skb->dev = dev;301			pkt = (struct archdr *)skb->data;302			soft = &pkt->soft.rfc1201;303 304			memcpy(pkt, pkthdr, ARC_HDR_SIZE + RFC1201_HDR_SIZE);305			skb_put(skb, ARC_HDR_SIZE + RFC1201_HDR_SIZE);306 307			soft->split_flag = 0;	/* end result won't be split */308		} else {	/* not first packet */309			int packetnum = ((unsigned)soft->split_flag >> 1) + 1;310 311			/* if we're not assembling, there's no point trying to312			 * continue.313			 */314			if (!in->skb) {315				if (lp->rfc1201.aborted_seq != soft->sequence) {316					arc_printk(D_EXTRA, dev, "can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n",317						   soft->split_flag,318						   soft->sequence,319						   lp->rfc1201.aborted_seq);320					dev->stats.rx_errors++;321					dev->stats.rx_missed_errors++;322				}323				return;324			}325			in->lastpacket++;326			/* if not the right flag */327			if (packetnum != in->lastpacket) {328				/* harmless duplicate? ignore. */329				if (packetnum <= in->lastpacket - 1) {330					arc_printk(D_EXTRA, dev, "duplicate splitpacket ignored! (splitflag=%d)\n",331						   soft->split_flag);332					dev->stats.rx_errors++;333					dev->stats.rx_frame_errors++;334					return;335				}336				/* "bad" duplicate, kill reassembly */337				arc_printk(D_EXTRA, dev, "out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",338					   in->sequence, soft->split_flag,339					   soft->sequence);340				lp->rfc1201.aborted_seq = soft->sequence;341				dev_kfree_skb_irq(in->skb);342				in->skb = NULL;343				dev->stats.rx_errors++;344				dev->stats.rx_missed_errors++;345				in->lastpacket = in->numpackets = 0;346				return;347			}348			pkt = (struct archdr *)in->skb->data;349			soft = &pkt->soft.rfc1201;350		}351 352		skb = in->skb;353 354		lp->hw.copy_from_card(dev, bufnum, ofs + RFC1201_HDR_SIZE,355				      skb->data + skb->len,356				      length - RFC1201_HDR_SIZE);357		skb_put(skb, length - RFC1201_HDR_SIZE);358 359		/* are we done? */360		if (in->lastpacket == in->numpackets) {361			in->skb = NULL;362			in->lastpacket = in->numpackets = 0;363 364			arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (unsplit)\n",365				   skb->len, pkt->hard.source);366			arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (split)\n",367				   skb->len, pkt->hard.source);368			if (BUGLVL(D_SKB))369				arcnet_dump_skb(dev, skb, "rx");370 371			skb->protocol = type_trans(skb, dev);372			netif_rx(skb);373		}374	}375}376 377/* Create the ARCnet hard/soft headers for RFC1201. */378static int build_header(struct sk_buff *skb, struct net_device *dev,379			unsigned short type, uint8_t daddr)380{381	struct arcnet_local *lp = netdev_priv(dev);382	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;383	struct archdr *pkt = skb_push(skb, hdr_size);384	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;385 386	/* set the protocol ID according to RFC1201 */387	switch (type) {388	case ETH_P_IP:389		soft->proto = ARC_P_IP;390		break;391	case ETH_P_IPV6:392		soft->proto = ARC_P_IPV6;393		break;394	case ETH_P_ARP:395		soft->proto = ARC_P_ARP;396		break;397	case ETH_P_RARP:398		soft->proto = ARC_P_RARP;399		break;400	case ETH_P_IPX:401	case ETH_P_802_3:402	case ETH_P_802_2:403		soft->proto = ARC_P_IPX;404		break;405	case ETH_P_ATALK:406		soft->proto = ARC_P_ATALK;407		break;408	default:409		arc_printk(D_NORMAL, dev, "RFC1201: I don't understand protocol %d (%Xh)\n",410			   type, type);411		dev->stats.tx_errors++;412		dev->stats.tx_aborted_errors++;413		return 0;414	}415 416	/* Set the source hardware address.417	 *418	 * This is pretty pointless for most purposes, but it can help in419	 * debugging.  ARCnet does not allow us to change the source address420	 * in the actual packet sent.421	 */422	pkt->hard.source = *dev->dev_addr;423 424	soft->sequence = htons(lp->rfc1201.sequence++);425	soft->split_flag = 0;	/* split packets are done elsewhere */426 427	/* see linux/net/ethernet/eth.c to see where I got the following */428 429	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {430		/* FIXME: fill in the last byte of the dest ipaddr here431		 * to better comply with RFC1051 in "noarp" mode.432		 * For now, always broadcasting will probably at least get433		 * packets sent out :)434		 */435		pkt->hard.dest = 0;436		return hdr_size;437	}438	/* otherwise, drop in the dest address */439	pkt->hard.dest = daddr;440	return hdr_size;441}442 443static void load_pkt(struct net_device *dev, struct arc_hardware *hard,444		     struct arc_rfc1201 *soft, int softlen, int bufnum)445{446	struct arcnet_local *lp = netdev_priv(dev);447	int ofs;448 449	/* assume length <= XMTU: someone should have handled that by now. */450 451	if (softlen > MinTU) {452		hard->offset[0] = 0;453		hard->offset[1] = ofs = 512 - softlen;454	} else if (softlen > MTU) {	/* exception packet - add an extra header */455		struct arc_rfc1201 excsoft;456 457		excsoft.proto = soft->proto;458		excsoft.split_flag = 0xff;459		excsoft.sequence = htons(0xffff);460 461		hard->offset[0] = 0;462		ofs = 512 - softlen;463		hard->offset[1] = ofs - RFC1201_HDR_SIZE;464		lp->hw.copy_to_card(dev, bufnum, ofs - RFC1201_HDR_SIZE,465				    &excsoft, RFC1201_HDR_SIZE);466	} else {467		hard->offset[0] = ofs = 256 - softlen;468	}469 470	lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);471	lp->hw.copy_to_card(dev, bufnum, ofs, soft, softlen);472 473	lp->lastload_dest = hard->dest;474}475 476static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,477		      int bufnum)478{479	struct arcnet_local *lp = netdev_priv(dev);480	const int maxsegsize = XMTU - RFC1201_HDR_SIZE;481	struct Outgoing *out;482 483	arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",484		   lp->next_tx, lp->cur_tx, bufnum);485 486	/* hard header is not included in packet length */487	length -= ARC_HDR_SIZE;488	pkt->soft.rfc1201.split_flag = 0;489 490	/* need to do a split packet? */491	if (length > XMTU) {492		out = &lp->outgoing;493 494		out->length = length - RFC1201_HDR_SIZE;495		out->dataleft = lp->outgoing.length;496		out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize;497		out->segnum = 0;498 499		arc_printk(D_DURING, dev, "rfc1201 prep_tx: ready for %d-segment split (%d bytes, seq=%d)\n",500			   out->numsegs, out->length,501			   pkt->soft.rfc1201.sequence);502 503		return 0;	/* not done */504	}505	/* just load the packet into the buffers and send it off */506	load_pkt(dev, &pkt->hard, &pkt->soft.rfc1201, length, bufnum);507 508	return 1;		/* done */509}510 511static int continue_tx(struct net_device *dev, int bufnum)512{513	struct arcnet_local *lp = netdev_priv(dev);514	struct Outgoing *out = &lp->outgoing;515	struct arc_hardware *hard = &out->pkt->hard;516	struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft;517	int maxsegsize = XMTU - RFC1201_HDR_SIZE;518	int seglen;519 520	arc_printk(D_DURING, dev,521		   "rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n",522		   out->segnum, out->numsegs, soft->sequence);523 524	/* the "new" soft header comes right before the data chunk */525	newsoft = (struct arc_rfc1201 *)526	    (out->pkt->soft.raw + out->length - out->dataleft);527 528	if (!out->segnum)	/* first packet; newsoft == soft */529		newsoft->split_flag = ((out->numsegs - 2) << 1) | 1;530	else {531		newsoft->split_flag = out->segnum << 1;532		newsoft->proto = soft->proto;533		newsoft->sequence = soft->sequence;534	}535 536	seglen = maxsegsize;537	if (seglen > out->dataleft)538		seglen = out->dataleft;539	out->dataleft -= seglen;540 541	load_pkt(dev, hard, newsoft, seglen + RFC1201_HDR_SIZE, bufnum);542 543	out->segnum++;544	if (out->segnum >= out->numsegs)545		return 1;546	else547		return 0;548}549