Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
0d60fd5
Documentation
LICENSES
arch
block
certs
crypto
drivers
fs
include
init
io_uring
ipc
kernel
lib
mm
net
6lowpan
802
8021q
9p
appletalk
atm
ax25
batman-adv
bluetooth
bpf
bridge
caif
can
ceph
core
Makefile
bpf_sk_storage.c
datagram.c
dev.c
dev.h
dev_addr_lists.c
dev_addr_lists_test.c
dev_api.c
dev_ioctl.c
devmem.c
devmem.h
drop_monitor.c
dst.c
dst_cache.c
failover.c
fib_notifier.c
fib_rules.c
filter.c
flow_dissector.c
flow_offload.c
gen_estimator.c
gen_stats.c
gro.c
gro_cells.c
gso.c
hotdata.c
hwbm.c
ieee8021q_helpers.c
link_watch.c
lwt_bpf.c
lwtunnel.c
mp_dmabuf_devmem.h
neighbour.c
net-procfs.c
net-sysfs.c
net-sysfs.h
net-traces.c
net_namespace.c
net_test.c
netclassid_cgroup.c
netdev-genl-gen.c
netdev-genl-gen.h
netdev-genl.c
netdev_rx_queue.c
netevent.c
netmem_priv.h
netpoll.c
netprio_cgroup.c
of_net.c
page_pool.c
page_pool_priv.h
page_pool_user.c
pktgen.c
ptp_classifier.c
request_sock.c
rtnetlink.c
rtnl_net_debug.c
scm.c
secure_seq.c
selftests.c
skb_fault_injection.c
skbuff.c
skmsg.c
sock.c
sock_destructor.h
sock_diag.c
sock_map.c
sock_reuseport.c
stream.c
sysctl_net_core.c
timestamping.c
tso.c
utils.c
xdp.c
dcb
dccp
devlink
dns_resolver
dsa
ethernet
ethtool
handshake
hsr
ieee802154
ife
ipv4
ipv6
iucv
kcm
key
l2tp
l3mdev
lapb
llc
mac80211
mac802154
mctp
mpls
mptcp
ncsi
netfilter
netlabel
netlink
netrom
nfc
nsh
openvswitch
packet
phonet
psample
qrtr
rds
rfkill
rose
rxrpc
sched
sctp
shaper
smc
strparser
sunrpc
switchdev
tipc
tls
unix
vmw_vsock
wireless
x25
xdp
xfrm
Kconfig
Kconfig.debug
Makefile
compat.c
devres.c
socket.c
sysctl_net.c
rust
samples
scripts
security
sound
tools
usr
virt
.clang-format
.clippy.toml
.cocciconfig
.editorconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
.rustfmt.toml
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
net
/
core
/
selftests.c
Blame
Blame
Latest commit
History
History
410 lines (339 loc) · 9.04 KB
Breadcrumbs
linux
/
net
/
core
/
selftests.c
Top
File metadata and controls
Code
Blame
410 lines (339 loc) · 9.04 KB
Raw
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 Synopsys, Inc. and/or its affiliates. * stmmac Selftests Support * * Author: Jose Abreu <joabreu@synopsys.com> * * Ported from stmmac by: * Copyright (C) 2021 Oleksij Rempel <o.rempel@pengutronix.de> */ #include <linux/phy.h> #include <net/selftests.h> #include <net/tcp.h> #include <net/udp.h> struct net_packet_attrs { const unsigned char *src; const unsigned char *dst; u32 ip_src; u32 ip_dst; bool tcp; u16 sport; u16 dport; int timeout; int size; int max_size; u8 id; u16 queue_mapping; }; struct net_test_priv { struct net_packet_attrs *packet; struct packet_type pt; struct completion comp; int double_vlan; int vlan_id; int ok; }; struct netsfhdr { __be32 version; __be64 magic; u8 id; } __packed; static u8 net_test_next_id; #define NET_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \ sizeof(struct netsfhdr)) #define NET_TEST_PKT_MAGIC 0xdeadcafecafedeadULL #define NET_LB_TIMEOUT msecs_to_jiffies(200) static struct sk_buff *net_test_get_skb(struct net_device *ndev, struct net_packet_attrs *attr) { struct sk_buff *skb = NULL; struct udphdr *uhdr = NULL; struct tcphdr *thdr = NULL; struct netsfhdr *shdr; struct ethhdr *ehdr; struct iphdr *ihdr; int iplen, size; size = attr->size + NET_TEST_PKT_SIZE; if (attr->tcp) size += sizeof(struct tcphdr); else size += sizeof(struct udphdr); if (attr->max_size && attr->max_size > size) size = attr->max_size; skb = netdev_alloc_skb(ndev, size); if (!skb) return NULL; prefetchw(skb->data); ehdr = skb_push(skb, ETH_HLEN); skb_reset_mac_header(skb); skb_set_network_header(skb, skb->len); ihdr = skb_put(skb, sizeof(*ihdr)); skb_set_transport_header(skb, skb->len); if (attr->tcp) thdr = skb_put(skb, sizeof(*thdr)); else uhdr = skb_put(skb, sizeof(*uhdr)); eth_zero_addr(ehdr->h_dest); if (attr->src) ether_addr_copy(ehdr->h_source, attr->src); if (attr->dst) ether_addr_copy(ehdr->h_dest, attr->dst); ehdr->h_proto = htons(ETH_P_IP); if (attr->tcp) { thdr->source = htons(attr->sport); thdr->dest = htons(attr->dport); thdr->doff = sizeof(struct tcphdr) / 4; thdr->check = 0; } else { uhdr->source = htons(attr->sport); uhdr->dest = htons(attr->dport); uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size); if (attr->max_size) uhdr->len = htons(attr->max_size - (sizeof(*ihdr) + sizeof(*ehdr))); uhdr->check = 0; } ihdr->ihl = 5; ihdr->ttl = 32; ihdr->version = 4; if (attr->tcp) ihdr->protocol = IPPROTO_TCP; else ihdr->protocol = IPPROTO_UDP; iplen = sizeof(*ihdr) + sizeof(*shdr) + attr->size; if (attr->tcp) iplen += sizeof(*thdr); else iplen += sizeof(*uhdr); if (attr->max_size) iplen = attr->max_size - sizeof(*ehdr); ihdr->tot_len = htons(iplen); ihdr->frag_off = 0; ihdr->saddr = htonl(attr->ip_src); ihdr->daddr = htonl(attr->ip_dst); ihdr->tos = 0; ihdr->id = 0; ip_send_check(ihdr); shdr = skb_put(skb, sizeof(*shdr)); shdr->version = 0; shdr->magic = cpu_to_be64(NET_TEST_PKT_MAGIC); attr->id = net_test_next_id; shdr->id = net_test_next_id++; if (attr->size) skb_put(skb, attr->size); if (attr->max_size && attr->max_size > skb->len) skb_put(skb, attr->max_size - skb->len); skb->csum = 0; skb->ip_summed = CHECKSUM_PARTIAL; if (attr->tcp) { thdr->check = ~tcp_v4_check(skb->len, ihdr->saddr, ihdr->daddr, 0); skb->csum_start = skb_transport_header(skb) - skb->head; skb->csum_offset = offsetof(struct tcphdr, check); } else { udp4_hwcsum(skb, ihdr->saddr, ihdr->daddr); } skb->protocol = htons(ETH_P_IP); skb->pkt_type = PACKET_HOST; skb->dev = ndev; return skb; } static int net_test_loopback_validate(struct sk_buff *skb, struct net_device *ndev, struct packet_type *pt, struct net_device *orig_ndev) { struct net_test_priv *tpriv = pt->af_packet_priv; const unsigned char *src = tpriv->packet->src; const unsigned char *dst = tpriv->packet->dst; struct netsfhdr *shdr; struct ethhdr *ehdr; struct udphdr *uhdr; struct tcphdr *thdr; struct iphdr *ihdr; skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) goto out; if (skb_linearize(skb)) goto out; if (skb_headlen(skb) < (NET_TEST_PKT_SIZE - ETH_HLEN)) goto out; ehdr = (struct ethhdr *)skb_mac_header(skb); if (dst) { if (!ether_addr_equal_unaligned(ehdr->h_dest, dst)) goto out; } if (src) { if (!ether_addr_equal_unaligned(ehdr->h_source, src)) goto out; } ihdr = ip_hdr(skb); if (tpriv->double_vlan) ihdr = (struct iphdr *)(skb_network_header(skb) + 4); if (tpriv->packet->tcp) { if (ihdr->protocol != IPPROTO_TCP) goto out; thdr = (struct tcphdr *)((u8 *)ihdr + 4 * ihdr->ihl); if (thdr->dest != htons(tpriv->packet->dport)) goto out; shdr = (struct netsfhdr *)((u8 *)thdr + sizeof(*thdr)); } else { if (ihdr->protocol != IPPROTO_UDP) goto out; uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl); if (uhdr->dest != htons(tpriv->packet->dport)) goto out; shdr = (struct netsfhdr *)((u8 *)uhdr + sizeof(*uhdr)); } if (shdr->magic != cpu_to_be64(NET_TEST_PKT_MAGIC)) goto out; if (tpriv->packet->id != shdr->id) goto out; tpriv->ok = true; complete(&tpriv->comp); out: kfree_skb(skb); return 0; } static int __net_test_loopback(struct net_device *ndev, struct net_packet_attrs *attr) { struct net_test_priv *tpriv; struct sk_buff *skb = NULL; int ret = 0; tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); if (!tpriv) return -ENOMEM; tpriv->ok = false; init_completion(&tpriv->comp); tpriv->pt.type = htons(ETH_P_IP); tpriv->pt.func = net_test_loopback_validate; tpriv->pt.dev = ndev; tpriv->pt.af_packet_priv = tpriv; tpriv->packet = attr; dev_add_pack(&tpriv->pt); skb = net_test_get_skb(ndev, attr); if (!skb) { ret = -ENOMEM; goto cleanup; } ret = dev_direct_xmit(skb, attr->queue_mapping); if (ret < 0) { goto cleanup; } else if (ret > 0) { ret = -ENETUNREACH; goto cleanup; } if (!attr->timeout) attr->timeout = NET_LB_TIMEOUT; wait_for_completion_timeout(&tpriv->comp, attr->timeout); ret = tpriv->ok ? 0 : -ETIMEDOUT; cleanup: dev_remove_pack(&tpriv->pt); kfree(tpriv); return ret; } static int net_test_netif_carrier(struct net_device *ndev) { return netif_carrier_ok(ndev) ? 0 : -ENOLINK; } static int net_test_phy_phydev(struct net_device *ndev) { return ndev->phydev ? 0 : -EOPNOTSUPP; } static int net_test_phy_loopback_enable(struct net_device *ndev) { if (!ndev->phydev) return -EOPNOTSUPP; return phy_loopback(ndev->phydev, true, 0); } static int net_test_phy_loopback_disable(struct net_device *ndev) { if (!ndev->phydev) return -EOPNOTSUPP; return phy_loopback(ndev->phydev, false, 0); } static int net_test_phy_loopback_udp(struct net_device *ndev) { struct net_packet_attrs attr = { }; attr.dst = ndev->dev_addr; return __net_test_loopback(ndev, &attr); } static int net_test_phy_loopback_udp_mtu(struct net_device *ndev) { struct net_packet_attrs attr = { }; attr.dst = ndev->dev_addr; attr.max_size = ndev->mtu; return __net_test_loopback(ndev, &attr); } static int net_test_phy_loopback_tcp(struct net_device *ndev) { struct net_packet_attrs attr = { }; attr.dst = ndev->dev_addr; attr.tcp = true; return __net_test_loopback(ndev, &attr); } static const struct net_test { char name[ETH_GSTRING_LEN]; int (*fn)(struct net_device *ndev); } net_selftests[] = { { .name = "Carrier ", .fn = net_test_netif_carrier, }, { .name = "PHY dev is present ", .fn = net_test_phy_phydev, }, { /* This test should be done before all PHY loopback test */ .name = "PHY internal loopback, enable ", .fn = net_test_phy_loopback_enable, }, { .name = "PHY internal loopback, UDP ", .fn = net_test_phy_loopback_udp, }, { .name = "PHY internal loopback, MTU ", .fn = net_test_phy_loopback_udp_mtu, }, { .name = "PHY internal loopback, TCP ", .fn = net_test_phy_loopback_tcp, }, { /* This test should be done after all PHY loopback test */ .name = "PHY internal loopback, disable", .fn = net_test_phy_loopback_disable, }, }; void net_selftest(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) { int count = net_selftest_get_count(); int i; memset(buf, 0, sizeof(*buf) * count); net_test_next_id = 0; if (etest->flags != ETH_TEST_FL_OFFLINE) { netdev_err(ndev, "Only offline tests are supported\n"); etest->flags |= ETH_TEST_FL_FAILED; return; } for (i = 0; i < count; i++) { buf[i] = net_selftests[i].fn(ndev); if (buf[i] && (buf[i] != -EOPNOTSUPP)) etest->flags |= ETH_TEST_FL_FAILED; } } EXPORT_SYMBOL_GPL(net_selftest); int net_selftest_get_count(void) { return ARRAY_SIZE(net_selftests); } EXPORT_SYMBOL_GPL(net_selftest_get_count); void net_selftest_get_strings(u8 *data) { int i; for (i = 0; i < net_selftest_get_count(); i++) ethtool_sprintf(&data, "%2d. %s", i + 1, net_selftests[i].name); } EXPORT_SYMBOL_GPL(net_selftest_get_strings); MODULE_DESCRIPTION("Common library for generic PHY ethtool selftests"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
You can’t perform that action at this time.