[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 } 1077 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 qeth_isxdigit(char * buf) 1090 { 1091 while (*buf) { ··· 1094 static inline int 1095 qeth_string_to_ipaddr4(const char *buf, __u8 *addr) 1096 { 1097 - const char *start, *end; 1098 - char abuf[4]; 1099 - char *tmp; 1100 - int len; 1101 - int i; 1102 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)) 1117 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; 1124 } 1125 return 0; 1126 } ··· 1123 static inline int 1124 qeth_string_to_ipaddr6(const char *buf, __u8 *addr) 1125 { 1126 - const char *start, *end; 1127 - u16 *tmp_addr; 1128 - char abuf[5]; 1129 - char *tmp; 1130 - int len; 1131 - int i; 1132 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); 1142 } 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 - } 1156 return 0; 1157 } 1158
··· 1076 } 1077 1078 static inline int 1079 qeth_isxdigit(char * buf) 1080 { 1081 while (*buf) { ··· 1104 static inline int 1105 qeth_string_to_ipaddr4(const char *buf, __u8 *addr) 1106 { 1107 + int count = 0, rc = 0; 1108 + int in[4]; 1109 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) 1116 return -EINVAL; 1117 + addr[count] = in[count]; 1118 } 1119 return 0; 1120 } ··· 1149 static inline int 1150 qeth_string_to_ipaddr6(const char *buf, __u8 *addr) 1151 { 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, }; 1157 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; 1184 } 1185 + start = ++end; 1186 + } 1187 + cnt = 7; 1188 + while (save_cnt) 1189 + in[cnt--] = in_tmp[--save_cnt]; 1190 return 0; 1191 } 1192
+9 -2
drivers/s390/net/qeth_eddp.c
··· 59 for (i = 0; i < ctx->num_pages; ++i) 60 free_page((unsigned long)ctx->pages[i]); 61 kfree(ctx->pages); 62 - if (ctx->elements != NULL) 63 - kfree(ctx->elements); 64 kfree(ctx); 65 } 66 ··· 412 413 QETH_DBF_TEXT(trace, 5, "eddpftcp"); 414 eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl; 415 tcph = eddp->skb->h.th; 416 while (eddp->skb_offset < eddp->skb->len) { 417 data_len = min((int)skb_shinfo(eddp->skb)->tso_size, ··· 489 return -ENOMEM; 490 } 491 if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { 492 memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN); 493 #ifdef CONFIG_QETH_VLAN 494 if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
··· 59 for (i = 0; i < ctx->num_pages; ++i) 60 free_page((unsigned long)ctx->pages[i]); 61 kfree(ctx->pages); 62 + kfree(ctx->elements); 63 kfree(ctx); 64 } 65 ··· 413 414 QETH_DBF_TEXT(trace, 5, "eddpftcp"); 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 + } 423 tcph = eddp->skb->h.th; 424 while (eddp->skb_offset < eddp->skb->len) { 425 data_len = min((int)skb_shinfo(eddp->skb)->tso_size, ··· 483 return -ENOMEM; 484 } 485 if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { 486 + skb->mac.raw = (skb->data) + sizeof(struct qeth_hdr); 487 memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN); 488 #ifdef CONFIG_QETH_VLAN 489 if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
+7 -10
drivers/s390/net/qeth_main.c
··· 516 QETH_DBF_TEXT(setup, 3, "setoffl"); 517 QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); 518 519 - netif_carrier_off(card->dev); 520 recover_flag = card->state; 521 if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){ 522 PRINT_WARN("Stopping card %s interrupted by user!\n", ··· 1680 spin_unlock_irqrestore(&reply->card->lock, flags); 1681 } 1682 1683 static struct qeth_ipa_cmd * 1684 qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) 1685 { ··· 1701 QETH_CARD_IFNAME(card), 1702 card->info.chpid); 1703 card->lan_online = 0; 1704 - netif_carrier_off(card->dev); 1705 return NULL; 1706 case IPA_CMD_STARTLAN: 1707 PRINT_INFO("Link reestablished on %s " ··· 5565 if (card->info.type == QETH_CARD_TYPE_OSN) 5566 return ; 5567 5568 - QETH_DBF_TEXT(trace,3,"setmulti"); 5569 qeth_delete_mc_addresses(card); 5570 if (card->options.layer2) { 5571 qeth_layer2_add_multicast(card); ··· 5582 return; 5583 if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0) 5584 schedule_work(&card->kernel_thread_starter); 5585 - 5586 } 5587 5588 static int ··· 7454 card->lan_online = 1; 7455 if (card->info.type==QETH_CARD_TYPE_OSN) 7456 goto out; 7457 if (card->options.layer2) { 7458 card->dev->features |= 7459 NETIF_F_HW_VLAN_FILTER | ··· 7471 #endif 7472 goto out; 7473 } 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 if ((rc = qeth_setadapter_parms(card))) 7481 QETH_DBF_TEXT_(setup, 2, "2err%d", rc); 7482 if ((rc = qeth_start_ipassists(card)))
··· 516 QETH_DBF_TEXT(setup, 3, "setoffl"); 517 QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); 518 519 + if (card->dev && netif_carrier_ok(card->dev)) 520 + netif_carrier_off(card->dev); 521 recover_flag = card->state; 522 if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){ 523 PRINT_WARN("Stopping card %s interrupted by user!\n", ··· 1679 spin_unlock_irqrestore(&reply->card->lock, flags); 1680 } 1681 1682 + 1683 static struct qeth_ipa_cmd * 1684 qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) 1685 { ··· 1699 QETH_CARD_IFNAME(card), 1700 card->info.chpid); 1701 card->lan_online = 0; 1702 + if (card->dev && netif_carrier_ok(card->dev)) 1703 + netif_carrier_off(card->dev); 1704 return NULL; 1705 case IPA_CMD_STARTLAN: 1706 PRINT_INFO("Link reestablished on %s " ··· 5562 if (card->info.type == QETH_CARD_TYPE_OSN) 5563 return ; 5564 5565 + QETH_DBF_TEXT(trace, 3, "setmulti"); 5566 qeth_delete_mc_addresses(card); 5567 if (card->options.layer2) { 5568 qeth_layer2_add_multicast(card); ··· 5579 return; 5580 if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0) 5581 schedule_work(&card->kernel_thread_starter); 5582 } 5583 5584 static int ··· 7452 card->lan_online = 1; 7453 if (card->info.type==QETH_CARD_TYPE_OSN) 7454 goto out; 7455 + qeth_set_large_send(card, card->options.large_send); 7456 if (card->options.layer2) { 7457 card->dev->features |= 7458 NETIF_F_HW_VLAN_FILTER | ··· 7468 #endif 7469 goto out; 7470 } 7471 if ((rc = qeth_setadapter_parms(card))) 7472 QETH_DBF_TEXT_(setup, 2, "2err%d", rc); 7473 if ((rc = qeth_start_ipassists(card)))