Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+47 −65
Original line number Diff line number Diff line
@@ -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
qeth_isxdigit(char * buf)
{
@@ -1104,33 +1094,17 @@ qeth_ipaddr4_to_string(const __u8 *addr, char *buf)
static inline int
qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
{
	const char *start, *end;
	char abuf[4];
	char *tmp;
	int len;
	int i;

	start = buf;
	for (i = 0; i < 4; i++) {
		if (i == 3) {
			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))
	int count = 0, rc = 0;
	int in[4];

	rc = sscanf(buf, "%d.%d.%d.%d%n", 
		    &in[0], &in[1], &in[2], &in[3], &count);
	if (rc != 4  || count) 
		return -EINVAL;
		memset(abuf, 0, 4);
		strncpy(abuf, start, len);
		if (!qeth_isdigit(abuf))
	for (count = 0; count < 4; count++) {
		if (in[count] > 255)
			return -EINVAL;
		addr[i] = simple_strtoul(abuf, &tmp, 10);
		start = end + 1;
		addr[count] = in[count];
	}
	return 0;
}
@@ -1149,36 +1123,44 @@ qeth_ipaddr6_to_string(const __u8 *addr, char *buf)
static inline int
qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
{
	const char *start, *end;
	u16 *tmp_addr;
	char abuf[5];
	char *tmp;
	int len;
	int i;

	tmp_addr = (u16 *)addr;
	start = buf;
	for (i = 0; i < 8; i++) {
		if (i == 7) {
			end = strchr(start,0xa);
			if (end)
				len = end - start;
			else
				len = strlen(start);
		}
		else {
			end = strchr(start, ':');
			len = end - start;
	char *end, *start;
	__u16 *in;
        char num[5];
        int num2, cnt, out, found, save_cnt;
        unsigned short in_tmp[8] = {0, };

	cnt = out = found = save_cnt = num2 = 0;
        end = start = (char *) buf;
	in = (__u16 *) addr;	
	memset(in, 0, 16);
        while (end) {
                end = strchr(end,':');
                if (end == NULL) {
                        end = (char *)buf + (strlen(buf));
                        out = 1;
                }
		if ((len <= 0) || (len > 4))
                if ((end - start)) { 
                        memset(num, 0, 5);
                        memcpy(num, start, end - start);
			if (!qeth_isxdigit(num))
				return -EINVAL;
		memset(abuf, 0, 5);
		strncpy(abuf, start, len);
		if (!qeth_isxdigit(abuf))
                        sscanf(start, "%x", &num2);
                        if (found)
                                in_tmp[save_cnt++] = num2;
                        else
                                in[cnt++] = num2;
                        if (out)
                                break;
                } else {
			if (found)
				return -EINVAL;
		tmp_addr[i] = simple_strtoul(abuf, &tmp, 16);
		start = end + 1;
                        found = 1;
		}
		start = ++end;
        }
        cnt = 7;
	while (save_cnt)
                in[cnt--] = in_tmp[--save_cnt];
	return 0;
}

+9 −2
Original line number Diff line number Diff line
@@ -59,7 +59,6 @@ qeth_eddp_free_context(struct qeth_eddp_context *ctx)
	for (i = 0; i < ctx->num_pages; ++i)
		free_page((unsigned long)ctx->pages[i]);
	kfree(ctx->pages);
	if (ctx->elements != NULL)
	kfree(ctx->elements);
	kfree(ctx);
}
@@ -413,6 +412,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
	
	QETH_DBF_TEXT(trace, 5, "eddpftcp");
	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;
	while (eddp->skb_offset < eddp->skb->len) {
		data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
@@ -483,6 +489,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
		return -ENOMEM;
	}
	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);
#ifdef CONFIG_QETH_VLAN
		if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
+7 −10
Original line number Diff line number Diff line
@@ -516,6 +516,7 @@ __qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
	QETH_DBF_TEXT(setup, 3, "setoffl");
	QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
	
	if (card->dev && netif_carrier_ok(card->dev))
		netif_carrier_off(card->dev);
	recover_flag = card->state;
	if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
@@ -1679,6 +1680,7 @@ qeth_cmd_timeout(unsigned long data)
	spin_unlock_irqrestore(&reply->card->lock, flags);
}


static struct qeth_ipa_cmd *
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
{
@@ -1699,6 +1701,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
					   QETH_CARD_IFNAME(card),
					   card->info.chpid);
				card->lan_online = 0;
				if (card->dev && netif_carrier_ok(card->dev))
					netif_carrier_off(card->dev);
				return NULL;
			case IPA_CMD_STARTLAN:
@@ -5579,7 +5582,6 @@ qeth_set_multicast_list(struct net_device *dev)
		return;
	if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
		schedule_work(&card->kernel_thread_starter);

}

static int
@@ -7452,6 +7454,7 @@ qeth_softsetup_card(struct qeth_card *card)
		card->lan_online = 1;
	if (card->info.type==QETH_CARD_TYPE_OSN)
		goto out;
	qeth_set_large_send(card, card->options.large_send);
	if (card->options.layer2) {
		card->dev->features |=
			NETIF_F_HW_VLAN_FILTER |
@@ -7468,12 +7471,6 @@ qeth_softsetup_card(struct qeth_card *card)
#endif
		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)))
		QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
	if ((rc = qeth_start_ipassists(card)))