Commit 66cc5d5a authored by Frank Pavlic's avatar Frank Pavlic Committed by Jeff Garzik

[PATCH] s390: some qeth driver fixes

[patch 2/2] s390: some qeth driver fixes

From: Frank Pavlic <fpavlic@de.ibm.com>
	- fixed kernel panic when using EDDP support in Layer 2 mode
	- NULL pointer exception in qeth_set_offline fixed.
	- setting EDDP in Layer 2 mode did not set NETIF_F_(SG/TSO)
	  flags when device became online.
	- use sscanf for parsing and converting IPv4 addresses
	  from string to __u8 values.
	- qeth_string_to_ipaddr6 fixed. in case of double colon
	  the converted IPv6 address out from the string was not correct
	  in previous implementation.
Signed-off-by: default avatarFrank Pavlic <fpavlic@de.ibm.com>

diffstat:
 qeth.h      |  112 +++++++++++++++++++++++++-----------------------------------
 qeth_eddp.c |   11 ++++-
 qeth_main.c |   17 +++------
 3 files changed, 63 insertions(+), 77 deletions(-)
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 0d613a27
...@@ -1075,16 +1075,6 @@ qeth_get_qdio_q_format(struct qeth_card *card) ...@@ -1075,16 +1075,6 @@ qeth_get_qdio_q_format(struct qeth_card *card)
} }
} }
static inline int
qeth_isdigit(char * buf)
{
while (*buf) {
if (!isdigit(*buf++))
return 0;
}
return 1;
}
static inline int static inline int
qeth_isxdigit(char * buf) qeth_isxdigit(char * buf)
{ {
...@@ -1104,33 +1094,17 @@ qeth_ipaddr4_to_string(const __u8 *addr, char *buf) ...@@ -1104,33 +1094,17 @@ qeth_ipaddr4_to_string(const __u8 *addr, char *buf)
static inline int static inline int
qeth_string_to_ipaddr4(const char *buf, __u8 *addr) qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
{ {
const char *start, *end; int count = 0, rc = 0;
char abuf[4]; int in[4];
char *tmp;
int len; rc = sscanf(buf, "%d.%d.%d.%d%n",
int i; &in[0], &in[1], &in[2], &in[3], &count);
if (rc != 4 || count)
start = buf; return -EINVAL;
for (i = 0; i < 4; i++) { for (count = 0; count < 4; count++) {
if (i == 3) { if (in[count] > 255)
end = strchr(start,0xa);
if (end)
len = end - start;
else
len = strlen(start);
}
else {
end = strchr(start, '.');
len = end - start;
}
if ((len <= 0) || (len > 3))
return -EINVAL;
memset(abuf, 0, 4);
strncpy(abuf, start, len);
if (!qeth_isdigit(abuf))
return -EINVAL; return -EINVAL;
addr[i] = simple_strtoul(abuf, &tmp, 10); addr[count] = in[count];
start = end + 1;
} }
return 0; return 0;
} }
...@@ -1149,36 +1123,44 @@ qeth_ipaddr6_to_string(const __u8 *addr, char *buf) ...@@ -1149,36 +1123,44 @@ qeth_ipaddr6_to_string(const __u8 *addr, char *buf)
static inline int static inline int
qeth_string_to_ipaddr6(const char *buf, __u8 *addr) qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
{ {
const char *start, *end; char *end, *start;
u16 *tmp_addr; __u16 *in;
char abuf[5]; char num[5];
char *tmp; int num2, cnt, out, found, save_cnt;
int len; unsigned short in_tmp[8] = {0, };
int i;
cnt = out = found = save_cnt = num2 = 0;
tmp_addr = (u16 *)addr; end = start = (char *) buf;
start = buf; in = (__u16 *) addr;
for (i = 0; i < 8; i++) { memset(in, 0, 16);
if (i == 7) { while (end) {
end = strchr(start,0xa); end = strchr(end,':');
if (end) if (end == NULL) {
len = end - start; end = (char *)buf + (strlen(buf));
else out = 1;
len = strlen(start); }
} if ((end - start)) {
else { memset(num, 0, 5);
end = strchr(start, ':'); memcpy(num, start, end - start);
len = end - start; if (!qeth_isxdigit(num))
return -EINVAL;
sscanf(start, "%x", &num2);
if (found)
in_tmp[save_cnt++] = num2;
else
in[cnt++] = num2;
if (out)
break;
} else {
if (found)
return -EINVAL;
found = 1;
} }
if ((len <= 0) || (len > 4)) start = ++end;
return -EINVAL; }
memset(abuf, 0, 5); cnt = 7;
strncpy(abuf, start, len); while (save_cnt)
if (!qeth_isxdigit(abuf)) in[cnt--] = in_tmp[--save_cnt];
return -EINVAL;
tmp_addr[i] = simple_strtoul(abuf, &tmp, 16);
start = end + 1;
}
return 0; return 0;
} }
......
...@@ -59,8 +59,7 @@ qeth_eddp_free_context(struct qeth_eddp_context *ctx) ...@@ -59,8 +59,7 @@ qeth_eddp_free_context(struct qeth_eddp_context *ctx)
for (i = 0; i < ctx->num_pages; ++i) for (i = 0; i < ctx->num_pages; ++i)
free_page((unsigned long)ctx->pages[i]); free_page((unsigned long)ctx->pages[i]);
kfree(ctx->pages); kfree(ctx->pages);
if (ctx->elements != NULL) kfree(ctx->elements);
kfree(ctx->elements);
kfree(ctx); kfree(ctx);
} }
...@@ -413,6 +412,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, ...@@ -413,6 +412,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
QETH_DBF_TEXT(trace, 5, "eddpftcp"); QETH_DBF_TEXT(trace, 5, "eddpftcp");
eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl; eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
eddp->skb_offset += sizeof(struct ethhdr);
#ifdef CONFIG_QETH_VLAN
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
eddp->skb_offset += VLAN_HLEN;
#endif /* CONFIG_QETH_VLAN */
}
tcph = eddp->skb->h.th; tcph = eddp->skb->h.th;
while (eddp->skb_offset < eddp->skb->len) { while (eddp->skb_offset < eddp->skb->len) {
data_len = min((int)skb_shinfo(eddp->skb)->tso_size, data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
...@@ -483,6 +489,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, ...@@ -483,6 +489,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
return -ENOMEM; return -ENOMEM;
} }
if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
skb->mac.raw = (skb->data) + sizeof(struct qeth_hdr);
memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN); memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN);
#ifdef CONFIG_QETH_VLAN #ifdef CONFIG_QETH_VLAN
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) { if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
......
...@@ -516,7 +516,8 @@ __qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode) ...@@ -516,7 +516,8 @@ __qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
QETH_DBF_TEXT(setup, 3, "setoffl"); QETH_DBF_TEXT(setup, 3, "setoffl");
QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
netif_carrier_off(card->dev); if (card->dev && netif_carrier_ok(card->dev))
netif_carrier_off(card->dev);
recover_flag = card->state; recover_flag = card->state;
if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){ if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
PRINT_WARN("Stopping card %s interrupted by user!\n", PRINT_WARN("Stopping card %s interrupted by user!\n",
...@@ -1679,6 +1680,7 @@ qeth_cmd_timeout(unsigned long data) ...@@ -1679,6 +1680,7 @@ qeth_cmd_timeout(unsigned long data)
spin_unlock_irqrestore(&reply->card->lock, flags); spin_unlock_irqrestore(&reply->card->lock, flags);
} }
static struct qeth_ipa_cmd * static struct qeth_ipa_cmd *
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
{ {
...@@ -1699,7 +1701,8 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) ...@@ -1699,7 +1701,8 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
QETH_CARD_IFNAME(card), QETH_CARD_IFNAME(card),
card->info.chpid); card->info.chpid);
card->lan_online = 0; card->lan_online = 0;
netif_carrier_off(card->dev); if (card->dev && netif_carrier_ok(card->dev))
netif_carrier_off(card->dev);
return NULL; return NULL;
case IPA_CMD_STARTLAN: case IPA_CMD_STARTLAN:
PRINT_INFO("Link reestablished on %s " PRINT_INFO("Link reestablished on %s "
...@@ -5562,7 +5565,7 @@ qeth_set_multicast_list(struct net_device *dev) ...@@ -5562,7 +5565,7 @@ qeth_set_multicast_list(struct net_device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN) if (card->info.type == QETH_CARD_TYPE_OSN)
return ; return ;
QETH_DBF_TEXT(trace,3,"setmulti"); QETH_DBF_TEXT(trace, 3, "setmulti");
qeth_delete_mc_addresses(card); qeth_delete_mc_addresses(card);
if (card->options.layer2) { if (card->options.layer2) {
qeth_layer2_add_multicast(card); qeth_layer2_add_multicast(card);
...@@ -5579,7 +5582,6 @@ qeth_set_multicast_list(struct net_device *dev) ...@@ -5579,7 +5582,6 @@ qeth_set_multicast_list(struct net_device *dev)
return; return;
if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0) if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
schedule_work(&card->kernel_thread_starter); schedule_work(&card->kernel_thread_starter);
} }
static int static int
...@@ -7452,6 +7454,7 @@ qeth_softsetup_card(struct qeth_card *card) ...@@ -7452,6 +7454,7 @@ qeth_softsetup_card(struct qeth_card *card)
card->lan_online = 1; card->lan_online = 1;
if (card->info.type==QETH_CARD_TYPE_OSN) if (card->info.type==QETH_CARD_TYPE_OSN)
goto out; goto out;
qeth_set_large_send(card, card->options.large_send);
if (card->options.layer2) { if (card->options.layer2) {
card->dev->features |= card->dev->features |=
NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_VLAN_FILTER |
...@@ -7468,12 +7471,6 @@ qeth_softsetup_card(struct qeth_card *card) ...@@ -7468,12 +7471,6 @@ qeth_softsetup_card(struct qeth_card *card)
#endif #endif
goto out; goto out;
} }
if ((card->options.large_send == QETH_LARGE_SEND_EDDP) ||
(card->options.large_send == QETH_LARGE_SEND_TSO))
card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
else
card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
if ((rc = qeth_setadapter_parms(card))) if ((rc = qeth_setadapter_parms(card)))
QETH_DBF_TEXT_(setup, 2, "2err%d", rc); QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
if ((rc = qeth_start_ipassists(card))) if ((rc = qeth_start_ipassists(card)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment