[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: Frank 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: Jeff Garzik <jgarzik@pobox.com>

authored by Frank Pavlic and committed by Jeff Garzik 66cc5d5a 0d613a27

+61 -75
+45 -63
drivers/s390/net/qeth.h
··· 1076 1076 } 1077 1077 1078 1078 static inline int 1079 - qeth_isdigit(char * buf) 1080 - { 1081 - while (*buf) { 1082 - if (!isdigit(*buf++)) 1083 - return 0; 1084 - } 1085 - return 1; 1086 - } 1087 - 1088 - static inline int 1089 1079 qeth_isxdigit(char * buf) 1090 1080 { 1091 1081 while (*buf) { ··· 1094 1104 static inline int 1095 1105 qeth_string_to_ipaddr4(const char *buf, __u8 *addr) 1096 1106 { 1097 - const char *start, *end; 1098 - char abuf[4]; 1099 - char *tmp; 1100 - int len; 1101 - int i; 1107 + int count = 0, rc = 0; 1108 + int in[4]; 1102 1109 1103 - start = buf; 1104 - for (i = 0; i < 4; i++) { 1105 - if (i == 3) { 1106 - end = strchr(start,0xa); 1107 - if (end) 1108 - len = end - start; 1109 - else 1110 - len = strlen(start); 1111 - } 1112 - else { 1113 - end = strchr(start, '.'); 1114 - len = end - start; 1115 - } 1116 - if ((len <= 0) || (len > 3)) 1110 + rc = sscanf(buf, "%d.%d.%d.%d%n", 1111 + &in[0], &in[1], &in[2], &in[3], &count); 1112 + if (rc != 4 || count) 1113 + return -EINVAL; 1114 + for (count = 0; count < 4; count++) { 1115 + if (in[count] > 255) 1117 1116 return -EINVAL; 1118 - memset(abuf, 0, 4); 1119 - strncpy(abuf, start, len); 1120 - if (!qeth_isdigit(abuf)) 1121 - return -EINVAL; 1122 - addr[i] = simple_strtoul(abuf, &tmp, 10); 1123 - start = end + 1; 1117 + addr[count] = in[count]; 1124 1118 } 1125 1119 return 0; 1126 1120 } ··· 1123 1149 static inline int 1124 1150 qeth_string_to_ipaddr6(const char *buf, __u8 *addr) 1125 1151 { 1126 - const char *start, *end; 1127 - u16 *tmp_addr; 1128 - char abuf[5]; 1129 - char *tmp; 1130 - int len; 1131 - int i; 1152 + char *end, *start; 1153 + __u16 *in; 1154 + char num[5]; 1155 + int num2, cnt, out, found, save_cnt; 1156 + unsigned short in_tmp[8] = {0, }; 1132 1157 1133 - tmp_addr = (u16 *)addr; 1134 - start = buf; 1135 - for (i = 0; i < 8; i++) { 1136 - if (i == 7) { 1137 - end = strchr(start,0xa); 1138 - if (end) 1139 - len = end - start; 1140 - else 1141 - len = strlen(start); 1158 + cnt = out = found = save_cnt = num2 = 0; 1159 + end = start = (char *) buf; 1160 + in = (__u16 *) addr; 1161 + memset(in, 0, 16); 1162 + while (end) { 1163 + end = strchr(end,':'); 1164 + if (end == NULL) { 1165 + end = (char *)buf + (strlen(buf)); 1166 + out = 1; 1167 + } 1168 + if ((end - start)) { 1169 + memset(num, 0, 5); 1170 + memcpy(num, start, end - start); 1171 + if (!qeth_isxdigit(num)) 1172 + return -EINVAL; 1173 + sscanf(start, "%x", &num2); 1174 + if (found) 1175 + in_tmp[save_cnt++] = num2; 1176 + else 1177 + in[cnt++] = num2; 1178 + if (out) 1179 + break; 1180 + } else { 1181 + if (found) 1182 + return -EINVAL; 1183 + found = 1; 1142 1184 } 1143 - else { 1144 - end = strchr(start, ':'); 1145 - len = end - start; 1146 - } 1147 - if ((len <= 0) || (len > 4)) 1148 - return -EINVAL; 1149 - memset(abuf, 0, 5); 1150 - strncpy(abuf, start, len); 1151 - if (!qeth_isxdigit(abuf)) 1152 - return -EINVAL; 1153 - tmp_addr[i] = simple_strtoul(abuf, &tmp, 16); 1154 - start = end + 1; 1155 - } 1185 + start = ++end; 1186 + } 1187 + cnt = 7; 1188 + while (save_cnt) 1189 + in[cnt--] = in_tmp[--save_cnt]; 1156 1190 return 0; 1157 1191 } 1158 1192
+9 -2
drivers/s390/net/qeth_eddp.c
··· 59 59 for (i = 0; i < ctx->num_pages; ++i) 60 60 free_page((unsigned long)ctx->pages[i]); 61 61 kfree(ctx->pages); 62 - if (ctx->elements != NULL) 63 - kfree(ctx->elements); 62 + kfree(ctx->elements); 64 63 kfree(ctx); 65 64 } 66 65 ··· 412 413 413 414 QETH_DBF_TEXT(trace, 5, "eddpftcp"); 414 415 eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl; 416 + if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { 417 + eddp->skb_offset += sizeof(struct ethhdr); 418 + #ifdef CONFIG_QETH_VLAN 419 + if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) 420 + eddp->skb_offset += VLAN_HLEN; 421 + #endif /* CONFIG_QETH_VLAN */ 422 + } 415 423 tcph = eddp->skb->h.th; 416 424 while (eddp->skb_offset < eddp->skb->len) { 417 425 data_len = min((int)skb_shinfo(eddp->skb)->tso_size, ··· 489 483 return -ENOMEM; 490 484 } 491 485 if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { 486 + skb->mac.raw = (skb->data) + sizeof(struct qeth_hdr); 492 487 memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN); 493 488 #ifdef CONFIG_QETH_VLAN 494 489 if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
+7 -10
drivers/s390/net/qeth_main.c
··· 516 516 QETH_DBF_TEXT(setup, 3, "setoffl"); 517 517 QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); 518 518 519 - netif_carrier_off(card->dev); 519 + if (card->dev && netif_carrier_ok(card->dev)) 520 + netif_carrier_off(card->dev); 520 521 recover_flag = card->state; 521 522 if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){ 522 523 PRINT_WARN("Stopping card %s interrupted by user!\n", ··· 1680 1679 spin_unlock_irqrestore(&reply->card->lock, flags); 1681 1680 } 1682 1681 1682 + 1683 1683 static struct qeth_ipa_cmd * 1684 1684 qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) 1685 1685 { ··· 1701 1699 QETH_CARD_IFNAME(card), 1702 1700 card->info.chpid); 1703 1701 card->lan_online = 0; 1704 - netif_carrier_off(card->dev); 1702 + if (card->dev && netif_carrier_ok(card->dev)) 1703 + netif_carrier_off(card->dev); 1705 1704 return NULL; 1706 1705 case IPA_CMD_STARTLAN: 1707 1706 PRINT_INFO("Link reestablished on %s " ··· 5565 5562 if (card->info.type == QETH_CARD_TYPE_OSN) 5566 5563 return ; 5567 5564 5568 - QETH_DBF_TEXT(trace,3,"setmulti"); 5565 + QETH_DBF_TEXT(trace, 3, "setmulti"); 5569 5566 qeth_delete_mc_addresses(card); 5570 5567 if (card->options.layer2) { 5571 5568 qeth_layer2_add_multicast(card); ··· 5582 5579 return; 5583 5580 if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0) 5584 5581 schedule_work(&card->kernel_thread_starter); 5585 - 5586 5582 } 5587 5583 5588 5584 static int ··· 7454 7452 card->lan_online = 1; 7455 7453 if (card->info.type==QETH_CARD_TYPE_OSN) 7456 7454 goto out; 7455 + qeth_set_large_send(card, card->options.large_send); 7457 7456 if (card->options.layer2) { 7458 7457 card->dev->features |= 7459 7458 NETIF_F_HW_VLAN_FILTER | ··· 7471 7468 #endif 7472 7469 goto out; 7473 7470 } 7474 - if ((card->options.large_send == QETH_LARGE_SEND_EDDP) || 7475 - (card->options.large_send == QETH_LARGE_SEND_TSO)) 7476 - card->dev->features |= NETIF_F_TSO | NETIF_F_SG; 7477 - else 7478 - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); 7479 - 7480 7471 if ((rc = qeth_setadapter_parms(card))) 7481 7472 QETH_DBF_TEXT_(setup, 2, "2err%d", rc); 7482 7473 if ((rc = qeth_start_ipassists(card)))