aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-01-14 17:24:25 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-14 17:24:25 -0500
commita49da8811e71c5355b52c65ee32976741d5834cd (patch)
tree66260c1adbda75fb290ca7085337045c91706aef /drivers/net
parentb86f81cca9442ce6cfbe76d10fb8d2c61122ae12 (diff)
parentb5cf66cd114ca24757ccf7c1f3e4d8ed86fe868c (diff)
Merge branch 'skb_checksum_help'
Paul Durrant says: ==================== make skb_checksum_setup generally available Both xen-netfront and xen-netback need to be able to set up the partial checksum offset of an skb and may also need to recalculate the pseudo- header checksum in the process. This functionality is currently private and duplicated between the two drivers. Patch #1 of this series moves the implementation into the core network code as there is nothing xen-specific about it and it is potentially useful to any network driver. Patch #2 removes the private implementation from netback. Patch #3 removes the private implementation from netfront. v2: - Put skb_checksum_setup in skbuff.c rather than dev.c - remove inline ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/xen-netback/netback.c260
-rw-r--r--drivers/net/xen-netfront.c48
2 files changed, 6 insertions, 302 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 27385639b6e5..6b62c3eb8e18 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -39,7 +39,6 @@
39#include <linux/udp.h> 39#include <linux/udp.h>
40 40
41#include <net/tcp.h> 41#include <net/tcp.h>
42#include <net/ip6_checksum.h>
43 42
44#include <xen/xen.h> 43#include <xen/xen.h>
45#include <xen/events.h> 44#include <xen/events.h>
@@ -1051,257 +1050,9 @@ static int xenvif_set_skb_gso(struct xenvif *vif,
1051 return 0; 1050 return 0;
1052} 1051}
1053 1052
1054static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len,
1055 unsigned int max)
1056{
1057 if (skb_headlen(skb) >= len)
1058 return 0;
1059
1060 /* If we need to pullup then pullup to the max, so we
1061 * won't need to do it again.
1062 */
1063 if (max > skb->len)
1064 max = skb->len;
1065
1066 if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL)
1067 return -ENOMEM;
1068
1069 if (skb_headlen(skb) < len)
1070 return -EPROTO;
1071
1072 return 0;
1073}
1074
1075/* This value should be large enough to cover a tagged ethernet header plus
1076 * maximally sized IP and TCP or UDP headers.
1077 */
1078#define MAX_IP_HDR_LEN 128
1079
1080static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
1081 int recalculate_partial_csum)
1082{
1083 unsigned int off;
1084 bool fragment;
1085 int err;
1086
1087 fragment = false;
1088
1089 err = maybe_pull_tail(skb,
1090 sizeof(struct iphdr),
1091 MAX_IP_HDR_LEN);
1092 if (err < 0)
1093 goto out;
1094
1095 if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF))
1096 fragment = true;
1097
1098 off = ip_hdrlen(skb);
1099
1100 err = -EPROTO;
1101
1102 if (fragment)
1103 goto out;
1104
1105 switch (ip_hdr(skb)->protocol) {
1106 case IPPROTO_TCP:
1107 err = maybe_pull_tail(skb,
1108 off + sizeof(struct tcphdr),
1109 MAX_IP_HDR_LEN);
1110 if (err < 0)
1111 goto out;
1112
1113 if (!skb_partial_csum_set(skb, off,
1114 offsetof(struct tcphdr, check))) {
1115 err = -EPROTO;
1116 goto out;
1117 }
1118
1119 if (recalculate_partial_csum)
1120 tcp_hdr(skb)->check =
1121 ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1122 ip_hdr(skb)->daddr,
1123 skb->len - off,
1124 IPPROTO_TCP, 0);
1125 break;
1126 case IPPROTO_UDP:
1127 err = maybe_pull_tail(skb,
1128 off + sizeof(struct udphdr),
1129 MAX_IP_HDR_LEN);
1130 if (err < 0)
1131 goto out;
1132
1133 if (!skb_partial_csum_set(skb, off,
1134 offsetof(struct udphdr, check))) {
1135 err = -EPROTO;
1136 goto out;
1137 }
1138
1139 if (recalculate_partial_csum)
1140 udp_hdr(skb)->check =
1141 ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1142 ip_hdr(skb)->daddr,
1143 skb->len - off,
1144 IPPROTO_UDP, 0);
1145 break;
1146 default:
1147 goto out;
1148 }
1149
1150 err = 0;
1151
1152out:
1153 return err;
1154}
1155
1156/* This value should be large enough to cover a tagged ethernet header plus
1157 * an IPv6 header, all options, and a maximal TCP or UDP header.
1158 */
1159#define MAX_IPV6_HDR_LEN 256
1160
1161#define OPT_HDR(type, skb, off) \
1162 (type *)(skb_network_header(skb) + (off))
1163
1164static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
1165 int recalculate_partial_csum)
1166{
1167 int err;
1168 u8 nexthdr;
1169 unsigned int off;
1170 unsigned int len;
1171 bool fragment;
1172 bool done;
1173
1174 fragment = false;
1175 done = false;
1176
1177 off = sizeof(struct ipv6hdr);
1178
1179 err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN);
1180 if (err < 0)
1181 goto out;
1182
1183 nexthdr = ipv6_hdr(skb)->nexthdr;
1184
1185 len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
1186 while (off <= len && !done) {
1187 switch (nexthdr) {
1188 case IPPROTO_DSTOPTS:
1189 case IPPROTO_HOPOPTS:
1190 case IPPROTO_ROUTING: {
1191 struct ipv6_opt_hdr *hp;
1192
1193 err = maybe_pull_tail(skb,
1194 off +
1195 sizeof(struct ipv6_opt_hdr),
1196 MAX_IPV6_HDR_LEN);
1197 if (err < 0)
1198 goto out;
1199
1200 hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
1201 nexthdr = hp->nexthdr;
1202 off += ipv6_optlen(hp);
1203 break;
1204 }
1205 case IPPROTO_AH: {
1206 struct ip_auth_hdr *hp;
1207
1208 err = maybe_pull_tail(skb,
1209 off +
1210 sizeof(struct ip_auth_hdr),
1211 MAX_IPV6_HDR_LEN);
1212 if (err < 0)
1213 goto out;
1214
1215 hp = OPT_HDR(struct ip_auth_hdr, skb, off);
1216 nexthdr = hp->nexthdr;
1217 off += ipv6_authlen(hp);
1218 break;
1219 }
1220 case IPPROTO_FRAGMENT: {
1221 struct frag_hdr *hp;
1222
1223 err = maybe_pull_tail(skb,
1224 off +
1225 sizeof(struct frag_hdr),
1226 MAX_IPV6_HDR_LEN);
1227 if (err < 0)
1228 goto out;
1229
1230 hp = OPT_HDR(struct frag_hdr, skb, off);
1231
1232 if (hp->frag_off & htons(IP6_OFFSET | IP6_MF))
1233 fragment = true;
1234
1235 nexthdr = hp->nexthdr;
1236 off += sizeof(struct frag_hdr);
1237 break;
1238 }
1239 default:
1240 done = true;
1241 break;
1242 }
1243 }
1244
1245 err = -EPROTO;
1246
1247 if (!done || fragment)
1248 goto out;
1249
1250 switch (nexthdr) {
1251 case IPPROTO_TCP:
1252 err = maybe_pull_tail(skb,
1253 off + sizeof(struct tcphdr),
1254 MAX_IPV6_HDR_LEN);
1255 if (err < 0)
1256 goto out;
1257
1258 if (!skb_partial_csum_set(skb, off,
1259 offsetof(struct tcphdr, check))) {
1260 err = -EPROTO;
1261 goto out;
1262 }
1263
1264 if (recalculate_partial_csum)
1265 tcp_hdr(skb)->check =
1266 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1267 &ipv6_hdr(skb)->daddr,
1268 skb->len - off,
1269 IPPROTO_TCP, 0);
1270 break;
1271 case IPPROTO_UDP:
1272 err = maybe_pull_tail(skb,
1273 off + sizeof(struct udphdr),
1274 MAX_IPV6_HDR_LEN);
1275 if (err < 0)
1276 goto out;
1277
1278 if (!skb_partial_csum_set(skb, off,
1279 offsetof(struct udphdr, check))) {
1280 err = -EPROTO;
1281 goto out;
1282 }
1283
1284 if (recalculate_partial_csum)
1285 udp_hdr(skb)->check =
1286 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1287 &ipv6_hdr(skb)->daddr,
1288 skb->len - off,
1289 IPPROTO_UDP, 0);
1290 break;
1291 default:
1292 goto out;
1293 }
1294
1295 err = 0;
1296
1297out:
1298 return err;
1299}
1300
1301static int checksum_setup(struct xenvif *vif, struct sk_buff *skb) 1053static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
1302{ 1054{
1303 int err = -EPROTO; 1055 bool recalculate_partial_csum = false;
1304 int recalculate_partial_csum = 0;
1305 1056
1306 /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy 1057 /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
1307 * peers can fail to set NETRXF_csum_blank when sending a GSO 1058 * peers can fail to set NETRXF_csum_blank when sending a GSO
@@ -1311,19 +1062,14 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
1311 if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) { 1062 if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
1312 vif->rx_gso_checksum_fixup++; 1063 vif->rx_gso_checksum_fixup++;
1313 skb->ip_summed = CHECKSUM_PARTIAL; 1064 skb->ip_summed = CHECKSUM_PARTIAL;
1314 recalculate_partial_csum = 1; 1065 recalculate_partial_csum = true;
1315 } 1066 }
1316 1067
1317 /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ 1068 /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
1318 if (skb->ip_summed != CHECKSUM_PARTIAL) 1069 if (skb->ip_summed != CHECKSUM_PARTIAL)
1319 return 0; 1070 return 0;
1320 1071
1321 if (skb->protocol == htons(ETH_P_IP)) 1072 return skb_checksum_setup(skb, recalculate_partial_csum);
1322 err = checksum_setup_ip(vif, skb, recalculate_partial_csum);
1323 else if (skb->protocol == htons(ETH_P_IPV6))
1324 err = checksum_setup_ipv6(vif, skb, recalculate_partial_csum);
1325
1326 return err;
1327} 1073}
1328 1074
1329static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) 1075static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index e59acb1daa23..c41537b577a4 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -859,9 +859,7 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
859 859
860static int checksum_setup(struct net_device *dev, struct sk_buff *skb) 860static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
861{ 861{
862 struct iphdr *iph; 862 bool recalculate_partial_csum = false;
863 int err = -EPROTO;
864 int recalculate_partial_csum = 0;
865 863
866 /* 864 /*
867 * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy 865 * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
@@ -873,54 +871,14 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
873 struct netfront_info *np = netdev_priv(dev); 871 struct netfront_info *np = netdev_priv(dev);
874 np->rx_gso_checksum_fixup++; 872 np->rx_gso_checksum_fixup++;
875 skb->ip_summed = CHECKSUM_PARTIAL; 873 skb->ip_summed = CHECKSUM_PARTIAL;
876 recalculate_partial_csum = 1; 874 recalculate_partial_csum = true;
877 } 875 }
878 876
879 /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ 877 /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
880 if (skb->ip_summed != CHECKSUM_PARTIAL) 878 if (skb->ip_summed != CHECKSUM_PARTIAL)
881 return 0; 879 return 0;
882 880
883 if (skb->protocol != htons(ETH_P_IP)) 881 return skb_checksum_setup(skb, recalculate_partial_csum);
884 goto out;
885
886 iph = (void *)skb->data;
887
888 switch (iph->protocol) {
889 case IPPROTO_TCP:
890 if (!skb_partial_csum_set(skb, 4 * iph->ihl,
891 offsetof(struct tcphdr, check)))
892 goto out;
893
894 if (recalculate_partial_csum) {
895 struct tcphdr *tcph = tcp_hdr(skb);
896 tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
897 skb->len - iph->ihl*4,
898 IPPROTO_TCP, 0);
899 }
900 break;
901 case IPPROTO_UDP:
902 if (!skb_partial_csum_set(skb, 4 * iph->ihl,
903 offsetof(struct udphdr, check)))
904 goto out;
905
906 if (recalculate_partial_csum) {
907 struct udphdr *udph = udp_hdr(skb);
908 udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
909 skb->len - iph->ihl*4,
910 IPPROTO_UDP, 0);
911 }
912 break;
913 default:
914 if (net_ratelimit())
915 pr_err("Attempting to checksum a non-TCP/UDP packet, dropping a protocol %d packet\n",
916 iph->protocol);
917 goto out;
918 }
919
920 err = 0;
921
922out:
923 return err;
924} 882}
925 883
926static int handle_incoming_queue(struct net_device *dev, 884static int handle_incoming_queue(struct net_device *dev,