aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/xen-netback
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-12-09 20:20:14 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-09 20:20:14 -0500
commit34f9f437104b86f6ddfa2770e2cd852846385dc3 (patch)
tree6c78386b3db9dd47fd2b79efb4dcf8c1472de99e /drivers/net/xen-netback
parent95dc19299f741c986227ec33e23cbf9b3321f812 (diff)
parent66e56cd46b93ef407c60adcac62cf33b06119d50 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Merge 'net' into 'net-next' to get the AF_PACKET bug fix that Daniel's direct transmit changes depend upon. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netback')
-rw-r--r--drivers/net/xen-netback/netback.c236
1 files changed, 137 insertions, 99 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 64f0e0d18b81..acf13920e6d1 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1149,49 +1149,72 @@ static int xenvif_set_skb_gso(struct xenvif *vif,
1149 return 0; 1149 return 0;
1150} 1150}
1151 1151
1152static inline void maybe_pull_tail(struct sk_buff *skb, unsigned int len) 1152static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len,
1153 unsigned int max)
1153{ 1154{
1154 if (skb_is_nonlinear(skb) && skb_headlen(skb) < len) { 1155 if (skb_headlen(skb) >= len)
1155 /* If we need to pullup then pullup to the max, so we 1156 return 0;
1156 * won't need to do it again. 1157
1157 */ 1158 /* If we need to pullup then pullup to the max, so we
1158 int target = min_t(int, skb->len, MAX_TCP_HEADER); 1159 * won't need to do it again.
1159 __pskb_pull_tail(skb, target - skb_headlen(skb)); 1160 */
1160 } 1161 if (max > skb->len)
1162 max = skb->len;
1163
1164 if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL)
1165 return -ENOMEM;
1166
1167 if (skb_headlen(skb) < len)
1168 return -EPROTO;
1169
1170 return 0;
1161} 1171}
1162 1172
1173/* This value should be large enough to cover a tagged ethernet header plus
1174 * maximally sized IP and TCP or UDP headers.
1175 */
1176#define MAX_IP_HDR_LEN 128
1177
1163static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb, 1178static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
1164 int recalculate_partial_csum) 1179 int recalculate_partial_csum)
1165{ 1180{
1166 struct iphdr *iph = (void *)skb->data;
1167 unsigned int header_size;
1168 unsigned int off; 1181 unsigned int off;
1169 int err = -EPROTO; 1182 bool fragment;
1183 int err;
1184
1185 fragment = false;
1186
1187 err = maybe_pull_tail(skb,
1188 sizeof(struct iphdr),
1189 MAX_IP_HDR_LEN);
1190 if (err < 0)
1191 goto out;
1170 1192
1171 off = sizeof(struct iphdr); 1193 if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF))
1194 fragment = true;
1172 1195
1173 header_size = skb->network_header + off + MAX_IPOPTLEN; 1196 off = ip_hdrlen(skb);
1174 maybe_pull_tail(skb, header_size);
1175 1197
1176 off = iph->ihl * 4; 1198 err = -EPROTO;
1177 1199
1178 switch (iph->protocol) { 1200 switch (ip_hdr(skb)->protocol) {
1179 case IPPROTO_TCP: 1201 case IPPROTO_TCP:
1180 if (!skb_partial_csum_set(skb, off, 1202 if (!skb_partial_csum_set(skb, off,
1181 offsetof(struct tcphdr, check))) 1203 offsetof(struct tcphdr, check)))
1182 goto out; 1204 goto out;
1183 1205
1184 if (recalculate_partial_csum) { 1206 if (recalculate_partial_csum) {
1185 struct tcphdr *tcph = tcp_hdr(skb); 1207 err = maybe_pull_tail(skb,
1186 1208 off + sizeof(struct tcphdr),
1187 header_size = skb->network_header + 1209 MAX_IP_HDR_LEN);
1188 off + 1210 if (err < 0)
1189 sizeof(struct tcphdr); 1211 goto out;
1190 maybe_pull_tail(skb, header_size); 1212
1191 1213 tcp_hdr(skb)->check =
1192 tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, 1214 ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1193 skb->len - off, 1215 ip_hdr(skb)->daddr,
1194 IPPROTO_TCP, 0); 1216 skb->len - off,
1217 IPPROTO_TCP, 0);
1195 } 1218 }
1196 break; 1219 break;
1197 case IPPROTO_UDP: 1220 case IPPROTO_UDP:
@@ -1200,24 +1223,20 @@ static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
1200 goto out; 1223 goto out;
1201 1224
1202 if (recalculate_partial_csum) { 1225 if (recalculate_partial_csum) {
1203 struct udphdr *udph = udp_hdr(skb); 1226 err = maybe_pull_tail(skb,
1204 1227 off + sizeof(struct udphdr),
1205 header_size = skb->network_header + 1228 MAX_IP_HDR_LEN);
1206 off + 1229 if (err < 0)
1207 sizeof(struct udphdr); 1230 goto out;
1208 maybe_pull_tail(skb, header_size); 1231
1209 1232 udp_hdr(skb)->check =
1210 udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, 1233 ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1211 skb->len - off, 1234 ip_hdr(skb)->daddr,
1212 IPPROTO_UDP, 0); 1235 skb->len - off,
1236 IPPROTO_UDP, 0);
1213 } 1237 }
1214 break; 1238 break;
1215 default: 1239 default:
1216 if (net_ratelimit())
1217 netdev_err(vif->dev,
1218 "Attempting to checksum a non-TCP/UDP packet, "
1219 "dropping a protocol %d packet\n",
1220 iph->protocol);
1221 goto out; 1240 goto out;
1222 } 1241 }
1223 1242
@@ -1227,75 +1246,99 @@ out:
1227 return err; 1246 return err;
1228} 1247}
1229 1248
1249/* This value should be large enough to cover a tagged ethernet header plus
1250 * an IPv6 header, all options, and a maximal TCP or UDP header.
1251 */
1252#define MAX_IPV6_HDR_LEN 256
1253
1254#define OPT_HDR(type, skb, off) \
1255 (type *)(skb_network_header(skb) + (off))
1256
1230static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, 1257static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
1231 int recalculate_partial_csum) 1258 int recalculate_partial_csum)
1232{ 1259{
1233 int err = -EPROTO; 1260 int err;
1234 struct ipv6hdr *ipv6h = (void *)skb->data;
1235 u8 nexthdr; 1261 u8 nexthdr;
1236 unsigned int header_size;
1237 unsigned int off; 1262 unsigned int off;
1263 unsigned int len;
1238 bool fragment; 1264 bool fragment;
1239 bool done; 1265 bool done;
1240 1266
1267 fragment = false;
1241 done = false; 1268 done = false;
1242 1269
1243 off = sizeof(struct ipv6hdr); 1270 off = sizeof(struct ipv6hdr);
1244 1271
1245 header_size = skb->network_header + off; 1272 err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN);
1246 maybe_pull_tail(skb, header_size); 1273 if (err < 0)
1274 goto out;
1247 1275
1248 nexthdr = ipv6h->nexthdr; 1276 nexthdr = ipv6_hdr(skb)->nexthdr;
1249 1277
1250 while ((off <= sizeof(struct ipv6hdr) + ntohs(ipv6h->payload_len)) && 1278 len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
1251 !done) { 1279 while (off <= len && !done) {
1252 switch (nexthdr) { 1280 switch (nexthdr) {
1253 case IPPROTO_DSTOPTS: 1281 case IPPROTO_DSTOPTS:
1254 case IPPROTO_HOPOPTS: 1282 case IPPROTO_HOPOPTS:
1255 case IPPROTO_ROUTING: { 1283 case IPPROTO_ROUTING: {
1256 struct ipv6_opt_hdr *hp = (void *)(skb->data + off); 1284 struct ipv6_opt_hdr *hp;
1257 1285
1258 header_size = skb->network_header + 1286 err = maybe_pull_tail(skb,
1259 off + 1287 off +
1260 sizeof(struct ipv6_opt_hdr); 1288 sizeof(struct ipv6_opt_hdr),
1261 maybe_pull_tail(skb, header_size); 1289 MAX_IPV6_HDR_LEN);
1290 if (err < 0)
1291 goto out;
1262 1292
1293 hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
1263 nexthdr = hp->nexthdr; 1294 nexthdr = hp->nexthdr;
1264 off += ipv6_optlen(hp); 1295 off += ipv6_optlen(hp);
1265 break; 1296 break;
1266 } 1297 }
1267 case IPPROTO_AH: { 1298 case IPPROTO_AH: {
1268 struct ip_auth_hdr *hp = (void *)(skb->data + off); 1299 struct ip_auth_hdr *hp;
1300
1301 err = maybe_pull_tail(skb,
1302 off +
1303 sizeof(struct ip_auth_hdr),
1304 MAX_IPV6_HDR_LEN);
1305 if (err < 0)
1306 goto out;
1307
1308 hp = OPT_HDR(struct ip_auth_hdr, skb, off);
1309 nexthdr = hp->nexthdr;
1310 off += ipv6_authlen(hp);
1311 break;
1312 }
1313 case IPPROTO_FRAGMENT: {
1314 struct frag_hdr *hp;
1269 1315
1270 header_size = skb->network_header + 1316 err = maybe_pull_tail(skb,
1271 off + 1317 off +
1272 sizeof(struct ip_auth_hdr); 1318 sizeof(struct frag_hdr),
1273 maybe_pull_tail(skb, header_size); 1319 MAX_IPV6_HDR_LEN);
1320 if (err < 0)
1321 goto out;
1322
1323 hp = OPT_HDR(struct frag_hdr, skb, off);
1324
1325 if (hp->frag_off & htons(IP6_OFFSET | IP6_MF))
1326 fragment = true;
1274 1327
1275 nexthdr = hp->nexthdr; 1328 nexthdr = hp->nexthdr;
1276 off += (hp->hdrlen+2)<<2; 1329 off += sizeof(struct frag_hdr);
1277 break; 1330 break;
1278 } 1331 }
1279 case IPPROTO_FRAGMENT:
1280 fragment = true;
1281 /* fall through */
1282 default: 1332 default:
1283 done = true; 1333 done = true;
1284 break; 1334 break;
1285 } 1335 }
1286 } 1336 }
1287 1337
1288 if (!done) { 1338 err = -EPROTO;
1289 if (net_ratelimit())
1290 netdev_err(vif->dev, "Failed to parse packet header\n");
1291 goto out;
1292 }
1293 1339
1294 if (fragment) { 1340 if (!done || fragment)
1295 if (net_ratelimit())
1296 netdev_err(vif->dev, "Packet is a fragment!\n");
1297 goto out; 1341 goto out;
1298 }
1299 1342
1300 switch (nexthdr) { 1343 switch (nexthdr) {
1301 case IPPROTO_TCP: 1344 case IPPROTO_TCP:
@@ -1304,17 +1347,17 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
1304 goto out; 1347 goto out;
1305 1348
1306 if (recalculate_partial_csum) { 1349 if (recalculate_partial_csum) {
1307 struct tcphdr *tcph = tcp_hdr(skb); 1350 err = maybe_pull_tail(skb,
1308 1351 off + sizeof(struct tcphdr),
1309 header_size = skb->network_header + 1352 MAX_IPV6_HDR_LEN);
1310 off + 1353 if (err < 0)
1311 sizeof(struct tcphdr); 1354 goto out;
1312 maybe_pull_tail(skb, header_size); 1355
1313 1356 tcp_hdr(skb)->check =
1314 tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, 1357 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1315 &ipv6h->daddr, 1358 &ipv6_hdr(skb)->daddr,
1316 skb->len - off, 1359 skb->len - off,
1317 IPPROTO_TCP, 0); 1360 IPPROTO_TCP, 0);
1318 } 1361 }
1319 break; 1362 break;
1320 case IPPROTO_UDP: 1363 case IPPROTO_UDP:
@@ -1323,25 +1366,20 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
1323 goto out; 1366 goto out;
1324 1367
1325 if (recalculate_partial_csum) { 1368 if (recalculate_partial_csum) {
1326 struct udphdr *udph = udp_hdr(skb); 1369 err = maybe_pull_tail(skb,
1327 1370 off + sizeof(struct udphdr),
1328 header_size = skb->network_header + 1371 MAX_IPV6_HDR_LEN);
1329 off + 1372 if (err < 0)
1330 sizeof(struct udphdr); 1373 goto out;
1331 maybe_pull_tail(skb, header_size); 1374
1332 1375 udp_hdr(skb)->check =
1333 udph->check = ~csum_ipv6_magic(&ipv6h->saddr, 1376 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1334 &ipv6h->daddr, 1377 &ipv6_hdr(skb)->daddr,
1335 skb->len - off, 1378 skb->len - off,
1336 IPPROTO_UDP, 0); 1379 IPPROTO_UDP, 0);
1337 } 1380 }
1338 break; 1381 break;
1339 default: 1382 default:
1340 if (net_ratelimit())
1341 netdev_err(vif->dev,
1342 "Attempting to checksum a non-TCP/UDP packet, "
1343 "dropping a protocol %d packet\n",
1344 nexthdr);
1345 goto out; 1383 goto out;
1346 } 1384 }
1347 1385