0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
0030
0031 #include <linux/module.h>
0032 #include <linux/gfp.h>
0033 #include <linux/init.h>
0034 #include <linux/if_arp.h>
0035 #include <net/arp.h>
0036 #include <linux/netdevice.h>
0037 #include <linux/skbuff.h>
0038
0039 #include "arcdevice.h"
0040
0041
0042 static void rx(struct net_device *dev, int bufnum,
0043 struct archdr *pkthdr, int length)
0044 {
0045 struct arcnet_local *lp = netdev_priv(dev);
0046 struct sk_buff *skb;
0047 struct archdr *pkt;
0048 char *pktbuf, *pkthdrbuf;
0049 int ofs;
0050
0051 arc_printk(D_DURING, dev, "it's a raw(cap) packet (length=%d)\n",
0052 length);
0053
0054 if (length >= MinTU)
0055 ofs = 512 - length;
0056 else
0057 ofs = 256 - length;
0058
0059 skb = alloc_skb(length + ARC_HDR_SIZE + sizeof(int), GFP_ATOMIC);
0060 if (!skb) {
0061 dev->stats.rx_dropped++;
0062 return;
0063 }
0064 skb_put(skb, length + ARC_HDR_SIZE + sizeof(int));
0065 skb->dev = dev;
0066 skb_reset_mac_header(skb);
0067 pkt = (struct archdr *)skb_mac_header(skb);
0068 skb_pull(skb, ARC_HDR_SIZE);
0069
0070
0071
0072
0073
0074
0075 pktbuf = (char *)pkt;
0076 pkthdrbuf = (char *)pkthdr;
0077 memcpy(pktbuf, pkthdrbuf, ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto));
0078 memcpy(pktbuf + ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto) + sizeof(int),
0079 pkthdrbuf + ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto),
0080 sizeof(struct archdr) - ARC_HDR_SIZE - sizeof(pkt->soft.cap.proto));
0081
0082 if (length > sizeof(pkt->soft))
0083 lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
0084 pkt->soft.raw + sizeof(pkt->soft)
0085 + sizeof(int),
0086 length - sizeof(pkt->soft));
0087
0088 if (BUGLVL(D_SKB))
0089 arcnet_dump_skb(dev, skb, "rx");
0090
0091 skb->protocol = cpu_to_be16(ETH_P_ARCNET);
0092 netif_rx(skb);
0093 }
0094
0095
0096
0097
0098 static int build_header(struct sk_buff *skb,
0099 struct net_device *dev,
0100 unsigned short type,
0101 uint8_t daddr)
0102 {
0103 int hdr_size = ARC_HDR_SIZE;
0104 struct archdr *pkt = skb_push(skb, hdr_size);
0105
0106 arc_printk(D_PROTO, dev, "Preparing header for cap packet %x.\n",
0107 *((int *)&pkt->soft.cap.cookie[0]));
0108
0109
0110
0111
0112
0113
0114
0115 pkt->hard.source = *dev->dev_addr;
0116
0117
0118
0119 if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
0120
0121
0122
0123 pkt->hard.dest = 0;
0124 return hdr_size;
0125 }
0126
0127 pkt->hard.dest = daddr;
0128
0129 return hdr_size;
0130 }
0131
0132 static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
0133 int bufnum)
0134 {
0135 struct arcnet_local *lp = netdev_priv(dev);
0136 struct arc_hardware *hard = &pkt->hard;
0137 int ofs;
0138
0139
0140 length -= ARC_HDR_SIZE;
0141
0142 length -= sizeof(int);
0143
0144 arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
0145 lp->next_tx, lp->cur_tx, bufnum);
0146
0147 arc_printk(D_PROTO, dev, "Sending for cap packet %x.\n",
0148 *((int *)&pkt->soft.cap.cookie[0]));
0149
0150 if (length > XMTU) {
0151
0152 arc_printk(D_NORMAL, dev, "Bug! prepare_tx with size %d (> %d)\n",
0153 length, XMTU);
0154 length = XMTU;
0155 }
0156 if (length > MinTU) {
0157 hard->offset[0] = 0;
0158 hard->offset[1] = ofs = 512 - length;
0159 } else if (length > MTU) {
0160 hard->offset[0] = 0;
0161 hard->offset[1] = ofs = 512 - length - 3;
0162 } else {
0163 hard->offset[0] = ofs = 256 - length;
0164 }
0165
0166 arc_printk(D_DURING, dev, "prepare_tx: length=%d ofs=%d\n",
0167 length, ofs);
0168
0169
0170 lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
0171 lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft.cap.proto,
0172 sizeof(pkt->soft.cap.proto));
0173
0174
0175
0176
0177 lp->hw.copy_to_card(dev, bufnum, ofs + 1,
0178 ((unsigned char *)&pkt->soft.cap.mes), length - 1);
0179
0180 lp->lastload_dest = hard->dest;
0181
0182 return 1;
0183 }
0184
0185 static int ack_tx(struct net_device *dev, int acked)
0186 {
0187 struct arcnet_local *lp = netdev_priv(dev);
0188 struct sk_buff *ackskb;
0189 struct archdr *ackpkt;
0190 int length = sizeof(struct arc_cap);
0191
0192 arc_printk(D_DURING, dev, "capmode: ack_tx: protocol: %x: result: %d\n",
0193 lp->outgoing.skb->protocol, acked);
0194
0195 if (BUGLVL(D_SKB))
0196 arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
0197
0198
0199 ackskb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
0200 if (!ackskb)
0201 goto free_outskb;
0202
0203 skb_put(ackskb, length + ARC_HDR_SIZE);
0204 ackskb->dev = dev;
0205
0206 skb_reset_mac_header(ackskb);
0207 ackpkt = (struct archdr *)skb_mac_header(ackskb);
0208
0209
0210 skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
0211 ARC_HDR_SIZE + sizeof(struct arc_cap));
0212 ackpkt->soft.cap.proto = 0;
0213 ackpkt->soft.cap.mes.ack = acked;
0214
0215 arc_printk(D_PROTO, dev, "Acknowledge for cap packet %x.\n",
0216 *((int *)&ackpkt->soft.cap.cookie[0]));
0217
0218 ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
0219
0220 if (BUGLVL(D_SKB))
0221 arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
0222 netif_rx(ackskb);
0223
0224 free_outskb:
0225 dev_kfree_skb_irq(lp->outgoing.skb);
0226 lp->outgoing.proto = NULL;
0227
0228
0229 return 0;
0230 }
0231
0232 static struct ArcProto capmode_proto = {
0233 .suffix = 'r',
0234 .mtu = XMTU,
0235 .rx = rx,
0236 .build_header = build_header,
0237 .prepare_tx = prepare_tx,
0238 .ack_tx = ack_tx
0239 };
0240
0241 static int __init capmode_module_init(void)
0242 {
0243 int count;
0244
0245 pr_info("cap mode (`c') encapsulation support loaded\n");
0246
0247 for (count = 1; count <= 8; count++)
0248 if (arc_proto_map[count] == arc_proto_default)
0249 arc_proto_map[count] = &capmode_proto;
0250
0251
0252 if (arc_bcast_proto == arc_proto_default)
0253 arc_bcast_proto = &capmode_proto;
0254
0255 arc_proto_default = &capmode_proto;
0256 arc_raw_proto = &capmode_proto;
0257
0258 return 0;
0259 }
0260
0261 static void __exit capmode_module_exit(void)
0262 {
0263 arcnet_unregister_proto(&capmode_proto);
0264 }
0265 module_init(capmode_module_init);
0266 module_exit(capmode_module_exit);
0267
0268 MODULE_LICENSE("GPL");