netlink-local.h revision 44d362409d5469aed47d19e7908d19bd194493a
144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * netlink-local.h		Local Netlink Interface
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf#ifndef NETLINK_LOCAL_H_
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NETLINK_LOCAL_H_
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <stdio.h>
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <errno.h>
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <stdlib.h>
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <string.h>
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <unistd.h>
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <fcntl.h>
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <math.h>
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <time.h>
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <stdarg.h>
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <ctype.h>
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <sys/types.h>
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <sys/socket.h>
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <inttypes.h>
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <assert.h>
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <arpa/inet.h>
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netdb.h>
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf#ifndef SOL_NETLINK
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define SOL_NETLINK 270
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf
3744d362409d5469aed47d19e7908d19bd194493aThomas Graftypedef uint8_t		__u8;
3844d362409d5469aed47d19e7908d19bd194493aThomas Graftypedef uint16_t	__u16;
3944d362409d5469aed47d19e7908d19bd194493aThomas Graftypedef int16_t		__s16;
4044d362409d5469aed47d19e7908d19bd194493aThomas Graftypedef uint32_t	__u32;
4144d362409d5469aed47d19e7908d19bd194493aThomas Graftypedef int32_t		__s32;
4244d362409d5469aed47d19e7908d19bd194493aThomas Graftypedef uint64_t	__u64;
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf/* local header copies */
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/if.h>
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/if_arp.h>
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/if_ether.h>
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/pkt_sched.h>
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/pkt_cls.h>
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <linux/gen_stats.h>
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/handlers.h>
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/cache.h>
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/tc.h>
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-types.h>
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf
5844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct trans_tbl {
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf	const char *a;
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf};
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define __ADD(id, name) { .i = id, .a = #name },
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf
6544d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct trans_list {
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *a;
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_list_head list;
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf};
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NL_DEBUG	1
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NL_DBG(LVL,FMT,ARG...) \
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf	do {	\
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (LVL <= nl_debug) \
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf			fprintf(stderr, "DBG<" #LVL ">: " FMT, ##ARG); \
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf	} while (0)
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define BUG()                            \
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf	do {                                 \
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf		fprintf(stderr, "BUG: %s:%d\n",  \
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf			__FILE__, __LINE__);         \
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf		assert(0);	\
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf	} while (0)
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RET_ERR(R, E)                    \
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf    do {                                 \
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf		errno = E;                       \
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -R;                       \
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf	} while (0)
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf
9244d362409d5469aed47d19e7908d19bd194493aThomas Grafextern int __nl_error(int, const char *, unsigned int,
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf	const char *, const char *, ...);
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf
9544d362409d5469aed47d19e7908d19bd194493aThomas Grafextern int __nl_read_num_str_file(const char *path,
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf				  int (*cb)(long, const char *));
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf#ifdef NL_ERROR_ASSERT
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <assert.h>
10044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int __assert_error(const char *file, int line, char *func,
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf	const char *fmt, ...)
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_list args;
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(stderr, "%s:%d:%s: ", file, line, func);
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_start(args, fmt);
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf	vfprintf(stderr, fmt, args);
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_end(args);
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf	fprintf(stderr, "\n");
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf	assert(0);
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define nl_error(E, FMT,ARG...) \
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__assert_error(__FILE__, __LINE__, __FUNCTION__, FMT, ##ARG)
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf#else
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define nl_error(E, FMT,ARG...) \
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__nl_error(E, __FILE__, __LINE__, __FUNCTION__, FMT, ##ARG)
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define nl_errno(E)	nl_error(E, NULL)
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf
12344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int __trans_list_add(int i, const char *a,
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf				   struct nl_list_head *head)
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct trans_list *tl;
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf	tl = calloc(1, sizeof(*tl));
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tl)
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return nl_errno(ENOMEM);
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf	tl->i = i;
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf	tl->a = strdup(a);
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_add_tail(&tl->list, head);
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf
14044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void __trans_list_clear(struct nl_list_head *head)
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct trans_list *tl, *next;
14344d362409d5469aed47d19e7908d19bd194493aThomas Graf
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry_safe(tl, next, head, list) {
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf		free(tl->a);
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf		free(tl);
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf
15044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline char *__type2str(int type, char *buf, size_t len,
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf			       struct trans_tbl *tbl, size_t tbl_len)
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i < tbl_len; i++) {
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tbl[i].i == type) {
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf			snprintf(buf, len, "%s", tbl[i].a);
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf			return buf;
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf	snprintf(buf, len, "0x%x", type);
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return buf;
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf
16544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline char *__list_type2str(int type, char *buf, size_t len,
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf				    struct nl_list_head *head)
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct trans_list *tl;
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(tl, head, list) {
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tl->i == type) {
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf			snprintf(buf, len, "%s", tl->a);
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf			return buf;
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf	snprintf(buf, len, "0x%x", type);
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return buf;
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf
18144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline char *__flags2str(int flags, char *buf, size_t len,
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf				struct trans_tbl *tbl, size_t tbl_len)
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf	int tmp = flags;
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf	memset(buf, 0, len);
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i < tbl_len; i++) {
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tbl[i].i & tmp) {
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf			tmp &= ~tbl[i].i;
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf			strncat(buf, tbl[i].a, len - strlen(buf) - 1);
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf			if ((tmp & flags))
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf				strncat(buf, ",", len - strlen(buf) - 1);
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return buf;
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf
20144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int __str2type(const char *buf, struct trans_tbl *tbl,
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf			     size_t tbl_len)
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf	unsigned long l;
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *end;
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*buf == '\0')
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i < tbl_len; i++)
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!strcasecmp(tbl[i].a, buf))
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf			return tbl[i].i;
21444d362409d5469aed47d19e7908d19bd194493aThomas Graf
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf	l = strtoul(buf, &end, 0);
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l == ULONG_MAX || *end != '\0')
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (int) l;
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf
22244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int __list_str2type(const char *buf, struct nl_list_head *head)
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct trans_list *tl;
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf	unsigned long l;
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *end;
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*buf == '\0')
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(tl, head, list) {
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!strcasecmp(tl->a, buf))
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf			return tl->i;
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf	l = strtoul(buf, &end, 0);
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (l == ULONG_MAX || *end != '\0')
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (int) l;
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf
24344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int __str2flags(const char *buf, struct trans_tbl *tbl,
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf			      size_t tbl_len)
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, flags = 0, len;
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *p = (char *) buf, *t;
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (;;) {
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (*p == ' ')
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf			p++;
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf		t = strchr(p, ',');
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf		len = t ? t - p : strlen(p);
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (i = 0; i < tbl_len; i++)
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (!strncasecmp(tbl[i].a, p, len))
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf				flags |= tbl[i].i;
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!t)
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf			return flags;
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf		p = ++t;
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf
26944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void dp_new_line(struct nl_dump_params *params,
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf			       int line_nr)
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (params->dp_prefix) {
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf		int i;
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (i = 0; i < params->dp_prefix; i++) {
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (params->dp_fd)
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf				fprintf(params->dp_fd, " ");
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf			else if (params->dp_buf)
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf				strncat(params->dp_buf, " ",
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf					params->dp_buflen -
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf					sizeof(params->dp_buf) - 1);
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (params->dp_nl_cb)
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf		params->dp_nl_cb(params, line_nr);
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf
28844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void __dp_dump(struct nl_dump_params *parms, const char *fmt,
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     va_list args)
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (parms->dp_fd)
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf		vfprintf(parms->dp_fd, fmt, args);
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (parms->dp_buf || parms->dp_cb) {
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf		char *buf = NULL;
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf		vasprintf(&buf, fmt, args);
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (parms->dp_cb)
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf			parms->dp_cb(parms, buf);
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf		else
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf			strncat(parms->dp_buf, buf,
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf			        parms->dp_buflen - strlen(parms->dp_buf) - 1);
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf		free(buf);
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf
30544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void dp_dump(struct nl_dump_params *parms, const char *fmt, ...)
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_list args;
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_start(args, fmt);
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__dp_dump(parms, fmt, args);
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_end(args);
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf
31444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void dp_dump_line(struct nl_dump_params *parms, int line,
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf				const char *fmt, ...)
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_list args;
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_new_line(parms, line);
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_start(args, fmt);
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__dp_dump(parms, fmt, args);
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf	va_end(args);
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf
32644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void dump_from_ops(struct nl_object *obj,
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf				 struct nl_dump_params *params)
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int type = params->dp_type;
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (type < 0 || type > NL_DUMP_MAX)
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf		BUG();
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (params->dp_dump_msgtype) {
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* XXX */
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf		char buf[64];
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(params, 0, "%s ",
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_cache_mngt_type2name(obj->ce_ops,
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf			     			     obj->ce_ops->co_protocol,
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf						     obj->ce_msgtype,
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf						     buf, sizeof(buf)));
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf		params->dp_pre_dump = 1;
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_new_line(params, 0);
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (obj->ce_ops->oo_dump[type])
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf		obj->ce_ops->oo_dump[type](obj, params);
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf
35344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct nl_cache *dp_cache(struct nl_object *obj)
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (obj->ce_cache == NULL)
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return nl_cache_mngt_require(obj->ce_ops->oo_name);
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return obj->ce_cache;
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf
36144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return cb->cb_set[type](msg, cb->cb_args[type]);
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define __init __attribute__ ((constructor))
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define __exit __attribute__ ((destructor))
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define P_ACCEPT 0
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define P_IGNORE 0
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define min(x,y) ({ \
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf	typeof(x) _x = (x);	\
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf	typeof(y) _y = (y);	\
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf	(void) (&_x == &_y);		\
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf	_x < _y ? _x : _y; })
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define max(x,y) ({ \
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf	typeof(x) _x = (x);	\
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf	typeof(y) _y = (y);	\
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf	(void) (&_x == &_y);		\
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf	_x > _y ? _x : _y; })
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define min_t(type,x,y) \
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf	({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define max_t(type,x,y) \
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf	({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf
39244d362409d5469aed47d19e7908d19bd194493aThomas Grafextern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *,
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf			  struct nlmsghdr *, struct nl_parser_param *);
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf
39644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void rtnl_copy_ratespec(struct rtnl_ratespec *dst,
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf				      struct tc_ratespec *src)
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
39944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->rs_cell_log = src->cell_log;
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->rs_feature = src->feature;
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->rs_addend = src->addend;
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->rs_mpu = src->mpu;
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->rs_rate = src->rate;
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf
40644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline void rtnl_rcopy_ratespec(struct tc_ratespec *dst,
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf				       struct rtnl_ratespec *src)
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->cell_log = src->rs_cell_log;
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->feature = src->rs_feature;
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->addend = src->rs_addend;
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->mpu = src->rs_mpu;
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst->rate = src->rs_rate;
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf
41644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline char *nl_cache_name(struct nl_cache *cache)
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return cache->c_ops ? cache->c_ops->co_name : "unknown";
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define GENL_FAMILY(id, name) \
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf	{ \
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf		{ id, NL_ACT_UNSPEC, name }, \
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf		END_OF_MSGTYPES_LIST, \
42544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define REQUESTED(LIST, ATTR)	((LIST) & (ATTR))
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define AVAILABLE(A, B, ATTR)	(((A)->ce_mask & (B)->ce_mask) & (ATTR))
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ATTR_MATCH(A, B, ATTR, EXPR)	(!AVAILABLE(A, B, ATTR) || (EXPR))
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf({	int diff = 0; \
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (REQUESTED(LIST, ATTR) && ATTR_MATCH(A, B, ATTR, EXPR)) \
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff = ATTR; \
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff; })
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
437