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 | |
| 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>
| -rw-r--r-- | drivers/s390/net/qeth.h | 5 | ||||
| -rw-r--r-- | drivers/s390/net/qeth_main.c | 136 |
2 files changed, 114 insertions, 27 deletions
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 501b87e6875a..d13c105f74e6 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include "qeth_mpc.h" | 25 | #include "qeth_mpc.h" |
| 26 | 26 | ||
| 27 | #define VERSION_QETH_H "$Revision: 1.136 $" | 27 | #define VERSION_QETH_H "$Revision: 1.137 $" |
| 28 | 28 | ||
| 29 | #ifdef CONFIG_QETH_IPV6 | 29 | #ifdef CONFIG_QETH_IPV6 |
| 30 | #define QETH_VERSION_IPV6 ":IPv6" | 30 | #define QETH_VERSION_IPV6 ":IPv6" |
| @@ -288,7 +288,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) | |||
| 288 | #define QETH_TX_TIMEOUT 100 * HZ | 288 | #define QETH_TX_TIMEOUT 100 * HZ |
| 289 | #define QETH_HEADER_SIZE 32 | 289 | #define QETH_HEADER_SIZE 32 |
| 290 | #define MAX_PORTNO 15 | 290 | #define MAX_PORTNO 15 |
| 291 | #define QETH_FAKE_LL_LEN ETH_HLEN | 291 | #define QETH_FAKE_LL_LEN_ETH ETH_HLEN |
| 292 | #define QETH_FAKE_LL_LEN_TR (sizeof(struct trh_hdr)-TR_MAXRIFLEN+sizeof(struct trllc)) | ||
| 292 | #define QETH_FAKE_LL_V6_ADDR_POS 24 | 293 | #define QETH_FAKE_LL_V6_ADDR_POS 24 |
| 293 | 294 | ||
| 294 | /*IPv6 address autoconfiguration stuff*/ | 295 | /*IPv6 address autoconfiguration stuff*/ |
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); |
