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