aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_main.c
diff options
context:
space:
mode:
authorFrank Pavlic <pavlic@de.ibm.com>2005-05-12 14:38:11 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-05-15 18:06:17 -0400
commite23dd9cdd676323c95fab47dc55123ba18f7e1ff (patch)
tree6592c2330319316fff28c520cf9e3beb539528f6 /drivers/s390/net/qeth_main.c
parentd801145d910cc4a0fb418dda1dee227cec993cbd (diff)
[PATCH] s390: fakell for high speed token ring
[patch 8/10] s390: fakell for high speed token ring. From: Michael Holzheu <holzheu@de.ibm.com> Implement fake-link-layer for high speed token ring. Without it token ring packages get leading ethernet headers, which confuses dhcp. Signed-off-by: Frank Pavlic <pavlic@de.ibm.com>
Diffstat (limited to 'drivers/s390/net/qeth_main.c')
-rw-r--r--drivers/s390/net/qeth_main.c136
1 files changed, 111 insertions, 25 deletions
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 17e8d16fa06c..2afe515f928d 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * linux/drivers/s390/net/qeth_main.c ($Revision: 1.207 $) 3 * linux/drivers/s390/net/qeth_main.c ($Revision: 1.209 $)
4 * 4 *
5 * Linux on zSeries OSA Express and HiperSockets support 5 * Linux on zSeries OSA Express and HiperSockets support
6 * 6 *
@@ -12,7 +12,7 @@
12 * Frank Pavlic (pavlic@de.ibm.com) and 12 * Frank Pavlic (pavlic@de.ibm.com) and
13 * Thomas Spatzier <tspat@de.ibm.com> 13 * Thomas Spatzier <tspat@de.ibm.com>
14 * 14 *
15 * $Revision: 1.207 $ $Date: 2005/04/01 21:40:40 $ 15 * $Revision: 1.209 $ $Date: 2005/04/18 11:58:48 $
16 * 16 *
17 * This program is free software; you can redistribute it and/or modify 17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by 18 * it under the terms of the GNU General Public License as published by
@@ -80,7 +80,7 @@ qeth_eyecatcher(void)
80#include "qeth_eddp.h" 80#include "qeth_eddp.h"
81#include "qeth_tso.h" 81#include "qeth_tso.h"
82 82
83#define VERSION_QETH_C "$Revision: 1.207 $" 83#define VERSION_QETH_C "$Revision: 1.209 $"
84static const char *version = "qeth S/390 OSA-Express driver"; 84static const char *version = "qeth S/390 OSA-Express driver";
85 85
86/** 86/**
@@ -2152,9 +2152,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
2152 if (!skb_len) 2152 if (!skb_len)
2153 return NULL; 2153 return NULL;
2154 if (card->options.fake_ll){ 2154 if (card->options.fake_ll){
2155 if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN))) 2155 if(card->dev->type == ARPHRD_IEEE802_TR){
2156 goto no_mem; 2156 if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR)))
2157 skb_pull(skb, QETH_FAKE_LL_LEN); 2157 goto no_mem;
2158 skb_reserve(skb,QETH_FAKE_LL_LEN_TR);
2159 } else {
2160 if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH)))
2161 goto no_mem;
2162 skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
2163 }
2158 } else if (!(skb = qeth_get_skb(skb_len))) 2164 } else if (!(skb = qeth_get_skb(skb_len)))
2159 goto no_mem; 2165 goto no_mem;
2160 data_ptr = element->addr + offset; 2166 data_ptr = element->addr + offset;
@@ -2229,14 +2235,68 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
2229} 2235}
2230 2236
2231static inline void 2237static inline void
2232qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, 2238qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
2239 struct qeth_hdr *hdr)
2240{
2241 struct trh_hdr *fake_hdr;
2242 struct trllc *fake_llc;
2243 struct iphdr *ip_hdr;
2244
2245 QETH_DBF_TEXT(trace,5,"skbfktr");
2246 skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR;
2247 /* this is a fake ethernet header */
2248 fake_hdr = (struct trh_hdr *) skb->mac.raw;
2249
2250 /* the destination MAC address */
2251 switch (skb->pkt_type){
2252 case PACKET_MULTICAST:
2253 switch (skb->protocol){
2254#ifdef CONFIG_QETH_IPV6
2255 case __constant_htons(ETH_P_IPV6):
2256 ndisc_mc_map((struct in6_addr *)
2257 skb->data + QETH_FAKE_LL_V6_ADDR_POS,
2258 fake_hdr->daddr, card->dev, 0);
2259 break;
2260#endif /* CONFIG_QETH_IPV6 */
2261 case __constant_htons(ETH_P_IP):
2262 ip_hdr = (struct iphdr *)skb->data;
2263 ip_tr_mc_map(ip_hdr->daddr, fake_hdr->daddr);
2264 break;
2265 default:
2266 memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
2267 }
2268 break;
2269 case PACKET_BROADCAST:
2270 memset(fake_hdr->daddr, 0xff, TR_ALEN);
2271 break;
2272 default:
2273 memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
2274 }
2275 /* the source MAC address */
2276 if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
2277 memcpy(fake_hdr->saddr, &hdr->hdr.l3.dest_addr[2], TR_ALEN);
2278 else
2279 memset(fake_hdr->saddr, 0, TR_ALEN);
2280 fake_hdr->rcf=0;
2281 fake_llc = (struct trllc*)&(fake_hdr->rcf);
2282 fake_llc->dsap = EXTENDED_SAP;
2283 fake_llc->ssap = EXTENDED_SAP;
2284 fake_llc->llc = UI_CMD;
2285 fake_llc->protid[0] = 0;
2286 fake_llc->protid[1] = 0;
2287 fake_llc->protid[2] = 0;
2288 fake_llc->ethertype = ETH_P_IP;
2289}
2290
2291static inline void
2292qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
2233 struct qeth_hdr *hdr) 2293 struct qeth_hdr *hdr)
2234{ 2294{
2235 struct ethhdr *fake_hdr; 2295 struct ethhdr *fake_hdr;
2236 struct iphdr *ip_hdr; 2296 struct iphdr *ip_hdr;
2237 2297
2238 QETH_DBF_TEXT(trace,5,"skbfake"); 2298 QETH_DBF_TEXT(trace,5,"skbfketh");
2239 skb->mac.raw = skb->data - QETH_FAKE_LL_LEN; 2299 skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH;
2240 /* this is a fake ethernet header */ 2300 /* this is a fake ethernet header */
2241 fake_hdr = (struct ethhdr *) skb->mac.raw; 2301 fake_hdr = (struct ethhdr *) skb->mac.raw;
2242 2302
@@ -2253,10 +2313,7 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
2253#endif /* CONFIG_QETH_IPV6 */ 2313#endif /* CONFIG_QETH_IPV6 */
2254 case __constant_htons(ETH_P_IP): 2314 case __constant_htons(ETH_P_IP):
2255 ip_hdr = (struct iphdr *)skb->data; 2315 ip_hdr = (struct iphdr *)skb->data;
2256 if (card->dev->type == ARPHRD_IEEE802_TR) 2316 ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
2257 ip_tr_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
2258 else
2259 ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
2260 break; 2317 break;
2261 default: 2318 default:
2262 memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN); 2319 memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN);
@@ -2278,6 +2335,16 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
2278} 2335}
2279 2336
2280static inline void 2337static inline void
2338qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
2339 struct qeth_hdr *hdr)
2340{
2341 if (card->dev->type == ARPHRD_IEEE802_TR)
2342 qeth_rebuild_skb_fake_ll_tr(card, skb, hdr);
2343 else
2344 qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
2345}
2346
2347static inline void
2281qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, 2348qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
2282 struct qeth_hdr *hdr) 2349 struct qeth_hdr *hdr)
2283{ 2350{
@@ -3440,16 +3507,25 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
3440 unsigned short type, void *daddr, void *saddr, 3507 unsigned short type, void *daddr, void *saddr,
3441 unsigned len) 3508 unsigned len)
3442{ 3509{
3443 struct ethhdr *hdr; 3510 if(dev->type == ARPHRD_IEEE802_TR){
3511 struct trh_hdr *hdr;
3512 hdr = (struct trh_hdr *)skb_push(skb, QETH_FAKE_LL_LEN_TR);
3513 memcpy(hdr->saddr, dev->dev_addr, TR_ALEN);
3514 memcpy(hdr->daddr, "FAKELL", TR_ALEN);
3515 return QETH_FAKE_LL_LEN_TR;
3516
3517 } else {
3518 struct ethhdr *hdr;
3519 hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN_ETH);
3520 memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
3521 memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
3522 if (type != ETH_P_802_3)
3523 hdr->h_proto = htons(type);
3524 else
3525 hdr->h_proto = htons(len);
3526 return QETH_FAKE_LL_LEN_ETH;
3444 3527
3445 hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN); 3528 }
3446 memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
3447 memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
3448 if (type != ETH_P_802_3)
3449 hdr->h_proto = htons(type);
3450 else
3451 hdr->h_proto = htons(len);
3452 return QETH_FAKE_LL_LEN;
3453} 3529}
3454 3530
3455static inline int 3531static inline int
@@ -3882,9 +3958,15 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
3882 memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16); 3958 memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16);
3883 } 3959 }
3884 } else { /* passthrough */ 3960 } else { /* passthrough */
3885 if (!memcmp(skb->data + sizeof(struct qeth_hdr), 3961 if((skb->dev->type == ARPHRD_IEEE802_TR) &&
3962 !memcmp(skb->data + sizeof(struct qeth_hdr) + 2,
3963 skb->dev->broadcast, 6)) {
3964 hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
3965 QETH_HDR_PASSTHRU;
3966 } else if (!memcmp(skb->data + sizeof(struct qeth_hdr),
3886 skb->dev->broadcast, 6)) { /* broadcast? */ 3967 skb->dev->broadcast, 6)) { /* broadcast? */
3887 hdr->hdr.l3.flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU; 3968 hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
3969 QETH_HDR_PASSTHRU;
3888 } else { 3970 } else {
3889 hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ? 3971 hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ?
3890 QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU : 3972 QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
@@ -4164,7 +4246,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
4164 dev_kfree_skb_irq(skb); 4246 dev_kfree_skb_irq(skb);
4165 return 0; 4247 return 0;
4166 } 4248 }
4167 skb_pull(skb, QETH_FAKE_LL_LEN); 4249 if(card->dev->type == ARPHRD_IEEE802_TR){
4250 skb_pull(skb, QETH_FAKE_LL_LEN_TR);
4251 } else {
4252 skb_pull(skb, QETH_FAKE_LL_LEN_ETH);
4253 }
4168 } 4254 }
4169 } 4255 }
4170 cast_type = qeth_get_cast_type(card, skb); 4256 cast_type = qeth_get_cast_type(card, skb);