0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/phy.h>
0013 #include <net/selftests.h>
0014 #include <net/tcp.h>
0015 #include <net/udp.h>
0016
0017 struct net_packet_attrs {
0018 const unsigned char *src;
0019 const unsigned char *dst;
0020 u32 ip_src;
0021 u32 ip_dst;
0022 bool tcp;
0023 u16 sport;
0024 u16 dport;
0025 int timeout;
0026 int size;
0027 int max_size;
0028 u8 id;
0029 u16 queue_mapping;
0030 };
0031
0032 struct net_test_priv {
0033 struct net_packet_attrs *packet;
0034 struct packet_type pt;
0035 struct completion comp;
0036 int double_vlan;
0037 int vlan_id;
0038 int ok;
0039 };
0040
0041 struct netsfhdr {
0042 __be32 version;
0043 __be64 magic;
0044 u8 id;
0045 } __packed;
0046
0047 static u8 net_test_next_id;
0048
0049 #define NET_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
0050 sizeof(struct netsfhdr))
0051 #define NET_TEST_PKT_MAGIC 0xdeadcafecafedeadULL
0052 #define NET_LB_TIMEOUT msecs_to_jiffies(200)
0053
0054 static struct sk_buff *net_test_get_skb(struct net_device *ndev,
0055 struct net_packet_attrs *attr)
0056 {
0057 struct sk_buff *skb = NULL;
0058 struct udphdr *uhdr = NULL;
0059 struct tcphdr *thdr = NULL;
0060 struct netsfhdr *shdr;
0061 struct ethhdr *ehdr;
0062 struct iphdr *ihdr;
0063 int iplen, size;
0064
0065 size = attr->size + NET_TEST_PKT_SIZE;
0066
0067 if (attr->tcp)
0068 size += sizeof(struct tcphdr);
0069 else
0070 size += sizeof(struct udphdr);
0071
0072 if (attr->max_size && attr->max_size > size)
0073 size = attr->max_size;
0074
0075 skb = netdev_alloc_skb(ndev, size);
0076 if (!skb)
0077 return NULL;
0078
0079 prefetchw(skb->data);
0080
0081 ehdr = skb_push(skb, ETH_HLEN);
0082 skb_reset_mac_header(skb);
0083
0084 skb_set_network_header(skb, skb->len);
0085 ihdr = skb_put(skb, sizeof(*ihdr));
0086
0087 skb_set_transport_header(skb, skb->len);
0088 if (attr->tcp)
0089 thdr = skb_put(skb, sizeof(*thdr));
0090 else
0091 uhdr = skb_put(skb, sizeof(*uhdr));
0092
0093 eth_zero_addr(ehdr->h_dest);
0094
0095 if (attr->src)
0096 ether_addr_copy(ehdr->h_source, attr->src);
0097 if (attr->dst)
0098 ether_addr_copy(ehdr->h_dest, attr->dst);
0099
0100 ehdr->h_proto = htons(ETH_P_IP);
0101
0102 if (attr->tcp) {
0103 thdr->source = htons(attr->sport);
0104 thdr->dest = htons(attr->dport);
0105 thdr->doff = sizeof(struct tcphdr) / 4;
0106 thdr->check = 0;
0107 } else {
0108 uhdr->source = htons(attr->sport);
0109 uhdr->dest = htons(attr->dport);
0110 uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size);
0111 if (attr->max_size)
0112 uhdr->len = htons(attr->max_size -
0113 (sizeof(*ihdr) + sizeof(*ehdr)));
0114 uhdr->check = 0;
0115 }
0116
0117 ihdr->ihl = 5;
0118 ihdr->ttl = 32;
0119 ihdr->version = 4;
0120 if (attr->tcp)
0121 ihdr->protocol = IPPROTO_TCP;
0122 else
0123 ihdr->protocol = IPPROTO_UDP;
0124 iplen = sizeof(*ihdr) + sizeof(*shdr) + attr->size;
0125 if (attr->tcp)
0126 iplen += sizeof(*thdr);
0127 else
0128 iplen += sizeof(*uhdr);
0129
0130 if (attr->max_size)
0131 iplen = attr->max_size - sizeof(*ehdr);
0132
0133 ihdr->tot_len = htons(iplen);
0134 ihdr->frag_off = 0;
0135 ihdr->saddr = htonl(attr->ip_src);
0136 ihdr->daddr = htonl(attr->ip_dst);
0137 ihdr->tos = 0;
0138 ihdr->id = 0;
0139 ip_send_check(ihdr);
0140
0141 shdr = skb_put(skb, sizeof(*shdr));
0142 shdr->version = 0;
0143 shdr->magic = cpu_to_be64(NET_TEST_PKT_MAGIC);
0144 attr->id = net_test_next_id;
0145 shdr->id = net_test_next_id++;
0146
0147 if (attr->size)
0148 skb_put(skb, attr->size);
0149 if (attr->max_size && attr->max_size > skb->len)
0150 skb_put(skb, attr->max_size - skb->len);
0151
0152 skb->csum = 0;
0153 skb->ip_summed = CHECKSUM_PARTIAL;
0154 if (attr->tcp) {
0155 thdr->check = ~tcp_v4_check(skb->len, ihdr->saddr,
0156 ihdr->daddr, 0);
0157 skb->csum_start = skb_transport_header(skb) - skb->head;
0158 skb->csum_offset = offsetof(struct tcphdr, check);
0159 } else {
0160 udp4_hwcsum(skb, ihdr->saddr, ihdr->daddr);
0161 }
0162
0163 skb->protocol = htons(ETH_P_IP);
0164 skb->pkt_type = PACKET_HOST;
0165 skb->dev = ndev;
0166
0167 return skb;
0168 }
0169
0170 static int net_test_loopback_validate(struct sk_buff *skb,
0171 struct net_device *ndev,
0172 struct packet_type *pt,
0173 struct net_device *orig_ndev)
0174 {
0175 struct net_test_priv *tpriv = pt->af_packet_priv;
0176 const unsigned char *src = tpriv->packet->src;
0177 const unsigned char *dst = tpriv->packet->dst;
0178 struct netsfhdr *shdr;
0179 struct ethhdr *ehdr;
0180 struct udphdr *uhdr;
0181 struct tcphdr *thdr;
0182 struct iphdr *ihdr;
0183
0184 skb = skb_unshare(skb, GFP_ATOMIC);
0185 if (!skb)
0186 goto out;
0187
0188 if (skb_linearize(skb))
0189 goto out;
0190 if (skb_headlen(skb) < (NET_TEST_PKT_SIZE - ETH_HLEN))
0191 goto out;
0192
0193 ehdr = (struct ethhdr *)skb_mac_header(skb);
0194 if (dst) {
0195 if (!ether_addr_equal_unaligned(ehdr->h_dest, dst))
0196 goto out;
0197 }
0198
0199 if (src) {
0200 if (!ether_addr_equal_unaligned(ehdr->h_source, src))
0201 goto out;
0202 }
0203
0204 ihdr = ip_hdr(skb);
0205 if (tpriv->double_vlan)
0206 ihdr = (struct iphdr *)(skb_network_header(skb) + 4);
0207
0208 if (tpriv->packet->tcp) {
0209 if (ihdr->protocol != IPPROTO_TCP)
0210 goto out;
0211
0212 thdr = (struct tcphdr *)((u8 *)ihdr + 4 * ihdr->ihl);
0213 if (thdr->dest != htons(tpriv->packet->dport))
0214 goto out;
0215
0216 shdr = (struct netsfhdr *)((u8 *)thdr + sizeof(*thdr));
0217 } else {
0218 if (ihdr->protocol != IPPROTO_UDP)
0219 goto out;
0220
0221 uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl);
0222 if (uhdr->dest != htons(tpriv->packet->dport))
0223 goto out;
0224
0225 shdr = (struct netsfhdr *)((u8 *)uhdr + sizeof(*uhdr));
0226 }
0227
0228 if (shdr->magic != cpu_to_be64(NET_TEST_PKT_MAGIC))
0229 goto out;
0230 if (tpriv->packet->id != shdr->id)
0231 goto out;
0232
0233 tpriv->ok = true;
0234 complete(&tpriv->comp);
0235 out:
0236 kfree_skb(skb);
0237 return 0;
0238 }
0239
0240 static int __net_test_loopback(struct net_device *ndev,
0241 struct net_packet_attrs *attr)
0242 {
0243 struct net_test_priv *tpriv;
0244 struct sk_buff *skb = NULL;
0245 int ret = 0;
0246
0247 tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
0248 if (!tpriv)
0249 return -ENOMEM;
0250
0251 tpriv->ok = false;
0252 init_completion(&tpriv->comp);
0253
0254 tpriv->pt.type = htons(ETH_P_IP);
0255 tpriv->pt.func = net_test_loopback_validate;
0256 tpriv->pt.dev = ndev;
0257 tpriv->pt.af_packet_priv = tpriv;
0258 tpriv->packet = attr;
0259 dev_add_pack(&tpriv->pt);
0260
0261 skb = net_test_get_skb(ndev, attr);
0262 if (!skb) {
0263 ret = -ENOMEM;
0264 goto cleanup;
0265 }
0266
0267 ret = dev_direct_xmit(skb, attr->queue_mapping);
0268 if (ret < 0) {
0269 goto cleanup;
0270 } else if (ret > 0) {
0271 ret = -ENETUNREACH;
0272 goto cleanup;
0273 }
0274
0275 if (!attr->timeout)
0276 attr->timeout = NET_LB_TIMEOUT;
0277
0278 wait_for_completion_timeout(&tpriv->comp, attr->timeout);
0279 ret = tpriv->ok ? 0 : -ETIMEDOUT;
0280
0281 cleanup:
0282 dev_remove_pack(&tpriv->pt);
0283 kfree(tpriv);
0284 return ret;
0285 }
0286
0287 static int net_test_netif_carrier(struct net_device *ndev)
0288 {
0289 return netif_carrier_ok(ndev) ? 0 : -ENOLINK;
0290 }
0291
0292 static int net_test_phy_phydev(struct net_device *ndev)
0293 {
0294 return ndev->phydev ? 0 : -EOPNOTSUPP;
0295 }
0296
0297 static int net_test_phy_loopback_enable(struct net_device *ndev)
0298 {
0299 if (!ndev->phydev)
0300 return -EOPNOTSUPP;
0301
0302 return phy_loopback(ndev->phydev, true);
0303 }
0304
0305 static int net_test_phy_loopback_disable(struct net_device *ndev)
0306 {
0307 if (!ndev->phydev)
0308 return -EOPNOTSUPP;
0309
0310 return phy_loopback(ndev->phydev, false);
0311 }
0312
0313 static int net_test_phy_loopback_udp(struct net_device *ndev)
0314 {
0315 struct net_packet_attrs attr = { };
0316
0317 attr.dst = ndev->dev_addr;
0318 return __net_test_loopback(ndev, &attr);
0319 }
0320
0321 static int net_test_phy_loopback_udp_mtu(struct net_device *ndev)
0322 {
0323 struct net_packet_attrs attr = { };
0324
0325 attr.dst = ndev->dev_addr;
0326 attr.max_size = ndev->mtu;
0327 return __net_test_loopback(ndev, &attr);
0328 }
0329
0330 static int net_test_phy_loopback_tcp(struct net_device *ndev)
0331 {
0332 struct net_packet_attrs attr = { };
0333
0334 attr.dst = ndev->dev_addr;
0335 attr.tcp = true;
0336 return __net_test_loopback(ndev, &attr);
0337 }
0338
0339 static const struct net_test {
0340 char name[ETH_GSTRING_LEN];
0341 int (*fn)(struct net_device *ndev);
0342 } net_selftests[] = {
0343 {
0344 .name = "Carrier ",
0345 .fn = net_test_netif_carrier,
0346 }, {
0347 .name = "PHY dev is present ",
0348 .fn = net_test_phy_phydev,
0349 }, {
0350
0351 .name = "PHY internal loopback, enable ",
0352 .fn = net_test_phy_loopback_enable,
0353 }, {
0354 .name = "PHY internal loopback, UDP ",
0355 .fn = net_test_phy_loopback_udp,
0356 }, {
0357 .name = "PHY internal loopback, MTU ",
0358 .fn = net_test_phy_loopback_udp_mtu,
0359 }, {
0360 .name = "PHY internal loopback, TCP ",
0361 .fn = net_test_phy_loopback_tcp,
0362 }, {
0363
0364 .name = "PHY internal loopback, disable",
0365 .fn = net_test_phy_loopback_disable,
0366 },
0367 };
0368
0369 void net_selftest(struct net_device *ndev, struct ethtool_test *etest, u64 *buf)
0370 {
0371 int count = net_selftest_get_count();
0372 int i;
0373
0374 memset(buf, 0, sizeof(*buf) * count);
0375 net_test_next_id = 0;
0376
0377 if (etest->flags != ETH_TEST_FL_OFFLINE) {
0378 netdev_err(ndev, "Only offline tests are supported\n");
0379 etest->flags |= ETH_TEST_FL_FAILED;
0380 return;
0381 }
0382
0383
0384 for (i = 0; i < count; i++) {
0385 buf[i] = net_selftests[i].fn(ndev);
0386 if (buf[i] && (buf[i] != -EOPNOTSUPP))
0387 etest->flags |= ETH_TEST_FL_FAILED;
0388 }
0389 }
0390 EXPORT_SYMBOL_GPL(net_selftest);
0391
0392 int net_selftest_get_count(void)
0393 {
0394 return ARRAY_SIZE(net_selftests);
0395 }
0396 EXPORT_SYMBOL_GPL(net_selftest_get_count);
0397
0398 void net_selftest_get_strings(u8 *data)
0399 {
0400 u8 *p = data;
0401 int i;
0402
0403 for (i = 0; i < net_selftest_get_count(); i++) {
0404 snprintf(p, ETH_GSTRING_LEN, "%2d. %s", i + 1,
0405 net_selftests[i].name);
0406 p += ETH_GSTRING_LEN;
0407 }
0408 }
0409 EXPORT_SYMBOL_GPL(net_selftest_get_strings);
0410
0411 MODULE_LICENSE("GPL v2");
0412 MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");