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