1*cf84ac9aSAndroid Build Coastguard Worker #include "tests.h"
2*cf84ac9aSAndroid Build Coastguard Worker #include <stdio.h>
3*cf84ac9aSAndroid Build Coastguard Worker #include <stddef.h>
4*cf84ac9aSAndroid Build Coastguard Worker #include <sys/socket.h>
5*cf84ac9aSAndroid Build Coastguard Worker #include <linux/if_packet.h>
6*cf84ac9aSAndroid Build Coastguard Worker #include "print_fields.h"
7*cf84ac9aSAndroid Build Coastguard Worker
8*cf84ac9aSAndroid Build Coastguard Worker static const char *errstr;
9*cf84ac9aSAndroid Build Coastguard Worker
10*cf84ac9aSAndroid Build Coastguard Worker struct tp_stats {
11*cf84ac9aSAndroid Build Coastguard Worker unsigned int tp_packets, tp_drops, tp_freeze_q_cnt;
12*cf84ac9aSAndroid Build Coastguard Worker };
13*cf84ac9aSAndroid Build Coastguard Worker
14*cf84ac9aSAndroid Build Coastguard Worker static long
get_tpacket_stats(void * optval,socklen_t * len)15*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(void *optval, socklen_t *len)
16*cf84ac9aSAndroid Build Coastguard Worker {
17*cf84ac9aSAndroid Build Coastguard Worker struct tp_stats *tpstats = optval;
18*cf84ac9aSAndroid Build Coastguard Worker socklen_t optlen = *len;
19*cf84ac9aSAndroid Build Coastguard Worker long rc = getsockopt(-1, SOL_PACKET, PACKET_STATISTICS, tpstats, len);
20*cf84ac9aSAndroid Build Coastguard Worker errstr = sprintrc(rc);
21*cf84ac9aSAndroid Build Coastguard Worker #ifdef INJECT_RETVAL
22*cf84ac9aSAndroid Build Coastguard Worker if (rc != INJECT_RETVAL)
23*cf84ac9aSAndroid Build Coastguard Worker error_msg_and_fail("Got a return value of %ld != %d",
24*cf84ac9aSAndroid Build Coastguard Worker rc, INJECT_RETVAL);
25*cf84ac9aSAndroid Build Coastguard Worker
26*cf84ac9aSAndroid Build Coastguard Worker static char inj_errstr[4096];
27*cf84ac9aSAndroid Build Coastguard Worker
28*cf84ac9aSAndroid Build Coastguard Worker snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
29*cf84ac9aSAndroid Build Coastguard Worker errstr = inj_errstr;
30*cf84ac9aSAndroid Build Coastguard Worker #endif
31*cf84ac9aSAndroid Build Coastguard Worker printf("getsockopt(-1, SOL_PACKET, PACKET_STATISTICS");
32*cf84ac9aSAndroid Build Coastguard Worker if (rc < 0 || optlen <= 0) {
33*cf84ac9aSAndroid Build Coastguard Worker printf(", %p", tpstats);
34*cf84ac9aSAndroid Build Coastguard Worker } else if (optlen < sizeof(tpstats->tp_packets)) {
35*cf84ac9aSAndroid Build Coastguard Worker printf(", {tp_packets=");
36*cf84ac9aSAndroid Build Coastguard Worker print_quoted_hex(tpstats, optlen);
37*cf84ac9aSAndroid Build Coastguard Worker printf("}");
38*cf84ac9aSAndroid Build Coastguard Worker } else {
39*cf84ac9aSAndroid Build Coastguard Worker PRINT_FIELD_U(", {", *tpstats, tp_packets);
40*cf84ac9aSAndroid Build Coastguard Worker
41*cf84ac9aSAndroid Build Coastguard Worker if (optlen > offsetof(struct tp_stats, tp_drops)) {
42*cf84ac9aSAndroid Build Coastguard Worker optlen -= offsetof(struct tp_stats, tp_drops);
43*cf84ac9aSAndroid Build Coastguard Worker if (optlen < sizeof(tpstats->tp_drops)) {
44*cf84ac9aSAndroid Build Coastguard Worker printf(", tp_drops=");
45*cf84ac9aSAndroid Build Coastguard Worker print_quoted_hex(tpstats, optlen);
46*cf84ac9aSAndroid Build Coastguard Worker } else {
47*cf84ac9aSAndroid Build Coastguard Worker PRINT_FIELD_U(", ", *tpstats, tp_drops);
48*cf84ac9aSAndroid Build Coastguard Worker
49*cf84ac9aSAndroid Build Coastguard Worker if (optlen > offsetof(struct tp_stats, tp_freeze_q_cnt) -
50*cf84ac9aSAndroid Build Coastguard Worker offsetof(struct tp_stats, tp_drops)) {
51*cf84ac9aSAndroid Build Coastguard Worker optlen -= offsetof(struct tp_stats, tp_freeze_q_cnt) -
52*cf84ac9aSAndroid Build Coastguard Worker offsetof(struct tp_stats, tp_drops);
53*cf84ac9aSAndroid Build Coastguard Worker if (optlen < sizeof(tpstats->tp_freeze_q_cnt)) {
54*cf84ac9aSAndroid Build Coastguard Worker printf(", tp_freeze_q_cnt=");
55*cf84ac9aSAndroid Build Coastguard Worker print_quoted_hex(tpstats, optlen);
56*cf84ac9aSAndroid Build Coastguard Worker } else {
57*cf84ac9aSAndroid Build Coastguard Worker PRINT_FIELD_U(", ", *tpstats, tp_freeze_q_cnt);
58*cf84ac9aSAndroid Build Coastguard Worker }
59*cf84ac9aSAndroid Build Coastguard Worker }
60*cf84ac9aSAndroid Build Coastguard Worker }
61*cf84ac9aSAndroid Build Coastguard Worker }
62*cf84ac9aSAndroid Build Coastguard Worker printf("}");
63*cf84ac9aSAndroid Build Coastguard Worker }
64*cf84ac9aSAndroid Build Coastguard Worker printf(", [%d]) = %s\n", *len, errstr);
65*cf84ac9aSAndroid Build Coastguard Worker
66*cf84ac9aSAndroid Build Coastguard Worker return rc;
67*cf84ac9aSAndroid Build Coastguard Worker }
68*cf84ac9aSAndroid Build Coastguard Worker
69*cf84ac9aSAndroid Build Coastguard Worker int
main(void)70*cf84ac9aSAndroid Build Coastguard Worker main(void)
71*cf84ac9aSAndroid Build Coastguard Worker {
72*cf84ac9aSAndroid Build Coastguard Worker TAIL_ALLOC_OBJECT_CONST_PTR(struct tp_stats, tp_stats);
73*cf84ac9aSAndroid Build Coastguard Worker TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
74*cf84ac9aSAndroid Build Coastguard Worker
75*cf84ac9aSAndroid Build Coastguard Worker /* offset of (truncated) struct tp_stats.tp_packets */
76*cf84ac9aSAndroid Build Coastguard Worker const unsigned int offset_tp_packets = offsetofend(struct tp_stats, tp_packets);
77*cf84ac9aSAndroid Build Coastguard Worker const unsigned int tp_packets_truncated = offset_tp_packets - 1;
78*cf84ac9aSAndroid Build Coastguard Worker /* offset of (truncated) struct tp_stats.tp_drops */
79*cf84ac9aSAndroid Build Coastguard Worker const unsigned int offset_tp_drops = offsetofend(struct tp_stats, tp_drops);
80*cf84ac9aSAndroid Build Coastguard Worker const unsigned int tp_drops_truncated = offset_tp_drops - 1;
81*cf84ac9aSAndroid Build Coastguard Worker /* offset of (truncated) struct tp_stats.tp_freeze_q_cnt */
82*cf84ac9aSAndroid Build Coastguard Worker const unsigned int offset_tp_freeze_q_cnt = offsetofend(struct tp_stats, tp_freeze_q_cnt);
83*cf84ac9aSAndroid Build Coastguard Worker const unsigned int tp_freeze_q_cnt_truncated = offset_tp_freeze_q_cnt - 1;
84*cf84ac9aSAndroid Build Coastguard Worker
85*cf84ac9aSAndroid Build Coastguard Worker *len = sizeof(*tp_stats);
86*cf84ac9aSAndroid Build Coastguard Worker
87*cf84ac9aSAndroid Build Coastguard Worker /* classic getsockopt */
88*cf84ac9aSAndroid Build Coastguard Worker unsigned int optlen = *len;
89*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
90*cf84ac9aSAndroid Build Coastguard Worker
91*cf84ac9aSAndroid Build Coastguard Worker /* getsockopt with zero optlen */
92*cf84ac9aSAndroid Build Coastguard Worker optlen = 0;
93*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
94*cf84ac9aSAndroid Build Coastguard Worker
95*cf84ac9aSAndroid Build Coastguard Worker /*
96*cf84ac9aSAndroid Build Coastguard Worker * getsockopt with optlen less than offsetofend(struct tp_stats.tp_packets):
97*cf84ac9aSAndroid Build Coastguard Worker * the part of struct tp_stats.tp_packets is printed in hex.
98*cf84ac9aSAndroid Build Coastguard Worker */
99*cf84ac9aSAndroid Build Coastguard Worker optlen = tp_packets_truncated;
100*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
101*cf84ac9aSAndroid Build Coastguard Worker
102*cf84ac9aSAndroid Build Coastguard Worker /*
103*cf84ac9aSAndroid Build Coastguard Worker * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_packets):
104*cf84ac9aSAndroid Build Coastguard Worker * struct tp_stats.tp_drops and struct tp_stats.offset_tp_freeze_q_cnt
105*cf84ac9aSAndroid Build Coastguard Worker * are not printed.
106*cf84ac9aSAndroid Build Coastguard Worker */
107*cf84ac9aSAndroid Build Coastguard Worker optlen = offset_tp_packets;
108*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
109*cf84ac9aSAndroid Build Coastguard Worker
110*cf84ac9aSAndroid Build Coastguard Worker /*
111*cf84ac9aSAndroid Build Coastguard Worker * getsockopt with optlen greater than offsetofend(struct tp_stats.tp_packets)
112*cf84ac9aSAndroid Build Coastguard Worker * but less than offsetofend(struct tp_stats, tp_drops):
113*cf84ac9aSAndroid Build Coastguard Worker * the part of struct tp_stats.tp_drops is printed in hex.
114*cf84ac9aSAndroid Build Coastguard Worker */
115*cf84ac9aSAndroid Build Coastguard Worker optlen = tp_drops_truncated;
116*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
117*cf84ac9aSAndroid Build Coastguard Worker
118*cf84ac9aSAndroid Build Coastguard Worker /*
119*cf84ac9aSAndroid Build Coastguard Worker * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_drops):
120*cf84ac9aSAndroid Build Coastguard Worker * struct tp_stats.tp_freeze_q_cnt is not printed.
121*cf84ac9aSAndroid Build Coastguard Worker */
122*cf84ac9aSAndroid Build Coastguard Worker optlen = offset_tp_drops;
123*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
124*cf84ac9aSAndroid Build Coastguard Worker
125*cf84ac9aSAndroid Build Coastguard Worker /*
126*cf84ac9aSAndroid Build Coastguard Worker * getsockopt with optlen greater than offsetofend(struct tp_stats.tp_drops)
127*cf84ac9aSAndroid Build Coastguard Worker * but less than offsetofend(struct tp_stats, tp_freeze_q_cnt):
128*cf84ac9aSAndroid Build Coastguard Worker * the part of struct tp_stats.tp_freeze_q_cnt is printed in hex.
129*cf84ac9aSAndroid Build Coastguard Worker */
130*cf84ac9aSAndroid Build Coastguard Worker optlen = tp_freeze_q_cnt_truncated;
131*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
132*cf84ac9aSAndroid Build Coastguard Worker
133*cf84ac9aSAndroid Build Coastguard Worker /*
134*cf84ac9aSAndroid Build Coastguard Worker * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_freeze_q_cnt):
135*cf84ac9aSAndroid Build Coastguard Worker */
136*cf84ac9aSAndroid Build Coastguard Worker optlen = offset_tp_freeze_q_cnt;
137*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
138*cf84ac9aSAndroid Build Coastguard Worker
139*cf84ac9aSAndroid Build Coastguard Worker /*
140*cf84ac9aSAndroid Build Coastguard Worker * getsockopt with optlen greater than sizeof(struct tp_stats)
141*cf84ac9aSAndroid Build Coastguard Worker */
142*cf84ac9aSAndroid Build Coastguard Worker optlen = offset_tp_freeze_q_cnt + 1;
143*cf84ac9aSAndroid Build Coastguard Worker get_tpacket_stats(tp_stats, &optlen);
144*cf84ac9aSAndroid Build Coastguard Worker
145*cf84ac9aSAndroid Build Coastguard Worker puts("+++ exited with 0 +++");
146*cf84ac9aSAndroid Build Coastguard Worker return 0;
147*cf84ac9aSAndroid Build Coastguard Worker }
148