148 lines
4.3 KiB
C
148 lines
4.3 KiB
C
#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;
|
|
}
|