#include "tests.h" #include <stdio.h> #include <stddef.h> #include <sys/socket.h> #include <linux/if_packet.h> #include "print_fields.h" static const char *errstr; struct tp_stats { unsigned int tp_packets, tp_drops, tp_freeze_q_cnt; }; static long get_tpacket_stats(void *optval, socklen_t *len) { struct tp_stats *tpstats = optval; socklen_t optlen = *len; long rc = getsockopt(-1, SOL_PACKET, PACKET_STATISTICS, tpstats, len); errstr = sprintrc(rc); #ifdef INJECT_RETVAL if (rc != INJECT_RETVAL) error_msg_and_fail("Got a return value of %ld != %d", rc, INJECT_RETVAL); static char inj_errstr[4096]; snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr); errstr = inj_errstr; #endif printf("getsockopt(-1, SOL_PACKET, PACKET_STATISTICS"); if (rc < 0 || optlen <= 0) { printf(", %p", tpstats); } else if (optlen < sizeof(tpstats->tp_packets)) { printf(", {tp_packets="); print_quoted_hex(tpstats, optlen); printf("}"); } else { PRINT_FIELD_U(", {", *tpstats, tp_packets); if (optlen > offsetof(struct tp_stats, tp_drops)) { optlen -= offsetof(struct tp_stats, tp_drops); if (optlen < sizeof(tpstats->tp_drops)) { printf(", tp_drops="); print_quoted_hex(tpstats, optlen); } else { PRINT_FIELD_U(", ", *tpstats, tp_drops); if (optlen > offsetof(struct tp_stats, tp_freeze_q_cnt) - offsetof(struct tp_stats, tp_drops)) { optlen -= offsetof(struct tp_stats, tp_freeze_q_cnt) - offsetof(struct tp_stats, tp_drops); if (optlen < sizeof(tpstats->tp_freeze_q_cnt)) { printf(", tp_freeze_q_cnt="); print_quoted_hex(tpstats, optlen); } else { PRINT_FIELD_U(", ", *tpstats, tp_freeze_q_cnt); } } } } printf("}"); } printf(", [%d]) = %s\n", *len, errstr); return rc; } int main(void) { TAIL_ALLOC_OBJECT_CONST_PTR(struct tp_stats, tp_stats); TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len); /* offset of (truncated) struct tp_stats.tp_packets */ const unsigned int offset_tp_packets = offsetofend(struct tp_stats, tp_packets); const unsigned int tp_packets_truncated = offset_tp_packets - 1; /* offset of (truncated) struct tp_stats.tp_drops */ const unsigned int offset_tp_drops = offsetofend(struct tp_stats, tp_drops); const unsigned int tp_drops_truncated = offset_tp_drops - 1; /* offset of (truncated) struct tp_stats.tp_freeze_q_cnt */ const unsigned int offset_tp_freeze_q_cnt = offsetofend(struct tp_stats, tp_freeze_q_cnt); const unsigned int tp_freeze_q_cnt_truncated = offset_tp_freeze_q_cnt - 1; *len = sizeof(*tp_stats); /* classic getsockopt */ unsigned int optlen = *len; get_tpacket_stats(tp_stats, &optlen); /* getsockopt with zero optlen */ optlen = 0; get_tpacket_stats(tp_stats, &optlen); /* * getsockopt with optlen less than offsetofend(struct tp_stats.tp_packets): * the part of struct tp_stats.tp_packets is printed in hex. */ optlen = tp_packets_truncated; get_tpacket_stats(tp_stats, &optlen); /* * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_packets): * struct tp_stats.tp_drops and struct tp_stats.offset_tp_freeze_q_cnt * are not printed. */ optlen = offset_tp_packets; get_tpacket_stats(tp_stats, &optlen); /* * getsockopt with optlen greater than offsetofend(struct tp_stats.tp_packets) * but less than offsetofend(struct tp_stats, tp_drops): * the part of struct tp_stats.tp_drops is printed in hex. */ optlen = tp_drops_truncated; get_tpacket_stats(tp_stats, &optlen); /* * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_drops): * struct tp_stats.tp_freeze_q_cnt is not printed. */ optlen = offset_tp_drops; get_tpacket_stats(tp_stats, &optlen); /* * getsockopt with optlen greater than offsetofend(struct tp_stats.tp_drops) * but less than offsetofend(struct tp_stats, tp_freeze_q_cnt): * the part of struct tp_stats.tp_freeze_q_cnt is printed in hex. */ optlen = tp_freeze_q_cnt_truncated; get_tpacket_stats(tp_stats, &optlen); /* * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_freeze_q_cnt): */ optlen = offset_tp_freeze_q_cnt; get_tpacket_stats(tp_stats, &optlen); /* * getsockopt with optlen greater than sizeof(struct tp_stats) */ optlen = offset_tp_freeze_q_cnt + 1; get_tpacket_stats(tp_stats, &optlen); puts("+++ exited with 0 +++"); return 0; }