diff options
author | Frank Pavlic <pavlic@de.ibm.com> | 2005-05-12 14:38:11 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-05-15 18:06:17 -0400 |
commit | e23dd9cdd676323c95fab47dc55123ba18f7e1ff (patch) | |
tree | 6592c2330319316fff28c520cf9e3beb539528f6 /drivers/s390/net/qeth_main.c | |
parent | d801145d910cc4a0fb418dda1dee227cec993cbd (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.c | 136 |
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 $" |
84 | static const char *version = "qeth S/390 OSA-Express driver"; | 84 | static 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 | ||
2231 | static inline void | 2237 | static inline void |
2232 | qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, | 2238 | qeth_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 | |||
2291 | static inline void | ||
2292 | qeth_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 | ||
2280 | static inline void | 2337 | static inline void |
2338 | qeth_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 | |||
2347 | static inline void | ||
2281 | qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, | 2348 | qeth_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 | ||
3455 | static inline int | 3531 | static 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); |