• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/idiag/idiagnl_msg_obj.c Inet Diag Message Object
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2013 Sassano Systems LLC <joe@sassanosystems.com>
10  */
11 
12 #include <netlink-private/netlink.h>
13 #include <netlink/idiag/msg.h>
14 #include <netlink/idiag/meminfo.h>
15 #include <netlink/idiag/vegasinfo.h>
16 #include <linux/inet_diag.h>
17 
18 /**
19  * @ingroup idiag
20  * @defgroup idiagnl_msg Inet Diag Messages
21  *
22  * @details
23  * @idiagnl_doc{idiagnl_msg, Inet Diag Message Documentation}
24  * @{
25  */
idiagnl_msg_alloc(void)26 struct idiagnl_msg *idiagnl_msg_alloc(void)
27 {
28 	return (struct idiagnl_msg *) nl_object_alloc(&idiagnl_msg_obj_ops);
29 }
30 
idiagnl_msg_get(struct idiagnl_msg * msg)31 void idiagnl_msg_get(struct idiagnl_msg *msg)
32 {
33 	nl_object_get((struct nl_object *) msg);
34 }
35 
idiagnl_msg_put(struct idiagnl_msg * msg)36 void idiagnl_msg_put(struct idiagnl_msg *msg)
37 {
38 	nl_object_put((struct nl_object *) msg);
39 }
40 
41 static struct nl_cache_ops idiagnl_msg_ops;
42 
idiagnl_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)43 static int idiagnl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
44 		struct nlmsghdr *nlh, struct nl_parser_param *pp)
45 {
46 	struct idiagnl_msg *msg = NULL;
47 	int err = 0;
48 
49 	if ((err = idiagnl_msg_parse(nlh, &msg)) < 0)
50 		return err;
51 
52 	err = pp->pp_cb((struct nl_object *) msg, pp);
53 	idiagnl_msg_put(msg);
54 
55 	return err;
56 }
57 
idiagnl_request_update(struct nl_cache * cache,struct nl_sock * sk)58 static int idiagnl_request_update(struct nl_cache *cache, struct nl_sock *sk)
59 {
60 	int family = cache->c_iarg1;
61 	int states = cache->c_iarg2;
62 
63 	return idiagnl_send_simple(sk, 0, family, states, IDIAG_ATTR_ALL);
64 }
65 
66 static struct nl_cache_ops idiagnl_msg_ops = {
67 	.co_name		= "idiag/idiag",
68 	.co_hdrsize		= sizeof(struct inet_diag_msg),
69 	.co_msgtypes		= {
70 		{ IDIAG_TCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
71 		{ IDIAG_DCCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
72 		END_OF_MSGTYPES_LIST,
73 	},
74 	.co_protocol		= NETLINK_INET_DIAG,
75 	.co_request_update	= idiagnl_request_update,
76 	.co_msg_parser		= idiagnl_msg_parser,
77 	.co_obj_ops		= &idiagnl_msg_obj_ops,
78 };
79 
idiagnl_init(void)80 static void __init idiagnl_init(void)
81 {
82 	nl_cache_mngt_register(&idiagnl_msg_ops);
83 }
84 
idiagnl_exit(void)85 static void __exit idiagnl_exit(void)
86 {
87 	nl_cache_mngt_unregister(&idiagnl_msg_ops);
88 }
89 
90 /**
91  * @name Cache Management
92  * @{
93  */
94 
95 /**
96  * Build an inetdiag cache to hold socket state information.
97  * @arg	sk      Netlink socket
98  * @arg family  The address family to query
99  * @arg states  Socket states to query
100  * @arg result  Result pointer
101  *
102  * @note The caller is responsible for destroying and free the cache after using
103  *  it.
104  * @return 0 on success of a negative error code.
105  */
idiagnl_msg_alloc_cache(struct nl_sock * sk,int family,int states,struct nl_cache ** result)106 int idiagnl_msg_alloc_cache(struct nl_sock *sk, int family, int states,
107 		struct nl_cache **result)
108 {
109 	struct nl_cache *cache = NULL;
110 	int err;
111 
112 	if (!(cache = nl_cache_alloc(&idiagnl_msg_ops)))
113 		return -NLE_NOMEM;
114 
115 	cache->c_iarg1 = family;
116 	cache->c_iarg2 = states;
117 
118 	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
119 		free(cache);
120 		return err;
121 	}
122 
123 	*result = cache;
124 	return 0;
125 }
126 
127 /** @} */
128 
129 /**
130  * @name Attributes
131  * @{
132  */
133 
idiagnl_msg_get_family(const struct idiagnl_msg * msg)134 uint8_t idiagnl_msg_get_family(const struct idiagnl_msg *msg)
135 {
136 	return msg->idiag_family;
137 }
138 
idiagnl_msg_set_family(struct idiagnl_msg * msg,uint8_t family)139 void idiagnl_msg_set_family(struct idiagnl_msg *msg, uint8_t family)
140 {
141 	msg->idiag_family = family;
142 }
143 
idiagnl_msg_get_state(const struct idiagnl_msg * msg)144 uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg)
145 {
146 	return msg->idiag_state;
147 }
148 
idiagnl_msg_set_state(struct idiagnl_msg * msg,uint8_t state)149 void idiagnl_msg_set_state(struct idiagnl_msg *msg, uint8_t state)
150 {
151 	msg->idiag_state = state;
152 }
153 
idiagnl_msg_get_timer(const struct idiagnl_msg * msg)154 uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg)
155 {
156 	return msg->idiag_timer;
157 }
158 
idiagnl_msg_set_timer(struct idiagnl_msg * msg,uint8_t timer)159 void idiagnl_msg_set_timer(struct idiagnl_msg *msg, uint8_t timer)
160 {
161 	msg->idiag_timer = timer;
162 }
163 
idiagnl_msg_get_retrans(const struct idiagnl_msg * msg)164 uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg)
165 {
166 	return msg->idiag_retrans;
167 }
168 
idiagnl_msg_set_retrans(struct idiagnl_msg * msg,uint8_t retrans)169 void idiagnl_msg_set_retrans(struct idiagnl_msg *msg, uint8_t retrans)
170 {
171 	msg->idiag_retrans = retrans;
172 }
173 
idiagnl_msg_get_sport(struct idiagnl_msg * msg)174 uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg)
175 {
176 	return msg->idiag_sport;
177 }
178 
idiagnl_msg_set_sport(struct idiagnl_msg * msg,uint16_t port)179 void idiagnl_msg_set_sport(struct idiagnl_msg *msg, uint16_t port)
180 {
181 	msg->idiag_sport = port;
182 }
183 
idiagnl_msg_get_dport(struct idiagnl_msg * msg)184 uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg)
185 {
186 	return msg->idiag_dport;
187 }
188 
idiagnl_msg_set_dport(struct idiagnl_msg * msg,uint16_t port)189 void idiagnl_msg_set_dport(struct idiagnl_msg *msg, uint16_t port)
190 {
191 	msg->idiag_dport = port;
192 }
193 
idiagnl_msg_get_src(const struct idiagnl_msg * msg)194 struct nl_addr *idiagnl_msg_get_src(const struct idiagnl_msg *msg)
195 {
196 	return msg->idiag_src;
197 }
198 
idiagnl_msg_set_src(struct idiagnl_msg * msg,struct nl_addr * addr)199 int idiagnl_msg_set_src(struct idiagnl_msg *msg, struct nl_addr *addr)
200 {
201 	if (msg->idiag_src)
202 		nl_addr_put(msg->idiag_src);
203 
204 	nl_addr_get(addr);
205 	msg->idiag_src = addr;
206 
207 	return 0;
208 }
209 
idiagnl_msg_get_dst(const struct idiagnl_msg * msg)210 struct nl_addr *idiagnl_msg_get_dst(const struct idiagnl_msg *msg)
211 {
212 	return msg->idiag_dst;
213 }
214 
idiagnl_msg_set_dst(struct idiagnl_msg * msg,struct nl_addr * addr)215 int idiagnl_msg_set_dst(struct idiagnl_msg *msg, struct nl_addr *addr)
216 {
217 	if (msg->idiag_dst)
218 		nl_addr_put(msg->idiag_dst);
219 
220 	nl_addr_get(addr);
221 	msg->idiag_dst = addr;
222 
223 	return 0;
224 }
225 
idiagnl_msg_get_ifindex(const struct idiagnl_msg * msg)226 uint32_t idiagnl_msg_get_ifindex(const struct idiagnl_msg *msg)
227 {
228 	return msg->idiag_ifindex;
229 }
230 
idiagnl_msg_set_ifindex(struct idiagnl_msg * msg,uint32_t ifindex)231 void idiagnl_msg_set_ifindex(struct idiagnl_msg *msg, uint32_t ifindex)
232 {
233 	msg->idiag_ifindex = ifindex;
234 }
235 
idiagnl_msg_get_expires(const struct idiagnl_msg * msg)236 uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg)
237 {
238 	return msg->idiag_expires;
239 }
240 
idiagnl_msg_set_expires(struct idiagnl_msg * msg,uint32_t expires)241 void idiagnl_msg_set_expires(struct idiagnl_msg *msg, uint32_t expires)
242 {
243 	msg->idiag_expires = expires;
244 }
245 
idiagnl_msg_get_rqueue(const struct idiagnl_msg * msg)246 uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg)
247 {
248 	return msg->idiag_rqueue;
249 }
250 
idiagnl_msg_set_rqueue(struct idiagnl_msg * msg,uint32_t rqueue)251 void idiagnl_msg_set_rqueue(struct idiagnl_msg *msg, uint32_t rqueue)
252 {
253 	msg->idiag_rqueue = rqueue;
254 }
255 
idiagnl_msg_get_wqueue(const struct idiagnl_msg * msg)256 uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg)
257 {
258 	return msg->idiag_wqueue;
259 }
260 
idiagnl_msg_set_wqueue(struct idiagnl_msg * msg,uint32_t wqueue)261 void idiagnl_msg_set_wqueue(struct idiagnl_msg *msg, uint32_t wqueue)
262 {
263 	msg->idiag_wqueue = wqueue;
264 }
265 
idiagnl_msg_get_uid(const struct idiagnl_msg * msg)266 uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg)
267 {
268 	return msg->idiag_uid;
269 }
270 
idiagnl_msg_set_uid(struct idiagnl_msg * msg,uint32_t uid)271 void idiagnl_msg_set_uid(struct idiagnl_msg *msg, uint32_t uid)
272 {
273 	msg->idiag_uid = uid;
274 }
275 
idiagnl_msg_get_inode(const struct idiagnl_msg * msg)276 uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg)
277 {
278 	return msg->idiag_inode;
279 }
280 
idiagnl_msg_set_inode(struct idiagnl_msg * msg,uint32_t inode)281 void idiagnl_msg_set_inode(struct idiagnl_msg *msg, uint32_t inode)
282 {
283 	msg->idiag_inode = inode;
284 }
285 
idiagnl_msg_get_tos(const struct idiagnl_msg * msg)286 uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg)
287 {
288 	return msg->idiag_tos;
289 }
290 
idiagnl_msg_set_tos(struct idiagnl_msg * msg,uint8_t tos)291 void idiagnl_msg_set_tos(struct idiagnl_msg *msg, uint8_t tos)
292 {
293 	msg->idiag_tos = tos;
294 }
295 
idiagnl_msg_get_tclass(const struct idiagnl_msg * msg)296 uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg)
297 {
298 	return msg->idiag_tclass;
299 }
300 
idiagnl_msg_set_tclass(struct idiagnl_msg * msg,uint8_t tclass)301 void idiagnl_msg_set_tclass(struct idiagnl_msg *msg, uint8_t tclass)
302 {
303 	msg->idiag_tclass = tclass;
304 }
305 
idiagnl_msg_get_shutdown(const struct idiagnl_msg * msg)306 uint8_t	idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg)
307 {
308 	return msg->idiag_shutdown;
309 }
310 
idiagnl_msg_set_shutdown(struct idiagnl_msg * msg,uint8_t shutdown)311 void  idiagnl_msg_set_shutdown(struct idiagnl_msg *msg, uint8_t shutdown)
312 {
313 	msg->idiag_shutdown = shutdown;
314 }
315 
idiagnl_msg_get_cong(const struct idiagnl_msg * msg)316 char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg)
317 {
318 	return msg->idiag_cong;
319 }
320 
idiagnl_msg_set_cong(struct idiagnl_msg * msg,char * cong)321 void idiagnl_msg_set_cong(struct idiagnl_msg *msg, char *cong)
322 {
323 	msg->idiag_cong = strdup(cong);
324 }
325 
idiagnl_msg_get_meminfo(const struct idiagnl_msg * msg)326 struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg)
327 {
328 	return msg->idiag_meminfo;
329 }
330 
idiagnl_msg_set_meminfo(struct idiagnl_msg * msg,struct idiagnl_meminfo * minfo)331 void idiagnl_msg_set_meminfo(struct idiagnl_msg *msg, struct idiagnl_meminfo
332 		*minfo)
333 {
334 	if (msg->idiag_meminfo)
335 		idiagnl_meminfo_put(msg->idiag_meminfo);
336 
337 	idiagnl_meminfo_get(minfo);
338 	msg->idiag_meminfo = minfo;
339 }
340 
idiagnl_msg_get_vegasinfo(const struct idiagnl_msg * msg)341 struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *msg)
342 {
343 	return msg->idiag_vegasinfo;
344 }
345 
idiagnl_msg_set_vegasinfo(struct idiagnl_msg * msg,struct idiagnl_vegasinfo * vinfo)346 void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *msg, struct idiagnl_vegasinfo
347 		*vinfo)
348 {
349 	if (msg->idiag_vegasinfo)
350 		idiagnl_vegasinfo_put(msg->idiag_vegasinfo);
351 
352 	idiagnl_vegasinfo_get(vinfo);
353 	msg->idiag_vegasinfo = vinfo;
354 }
355 
idiagnl_msg_get_tcpinfo(const struct idiagnl_msg * msg)356 struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg)
357 {
358 	return msg->idiag_tcpinfo;
359 }
360 
idiagnl_msg_set_tcpinfo(struct idiagnl_msg * msg,struct tcp_info * tinfo)361 void idiagnl_msg_set_tcpinfo(struct idiagnl_msg *msg, struct tcp_info *tinfo)
362 {
363 	memcpy(&msg->idiag_tcpinfo, tinfo, sizeof(struct tcp_info));
364 }
365 
366 /** @} */
367 
idiag_msg_dump_line(struct nl_object * a,struct nl_dump_params * p)368 static void idiag_msg_dump_line(struct nl_object *a, struct nl_dump_params *p)
369 {
370 	struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
371 	char buf[64] = { 0 };
372 
373 	nl_dump_line(p, "family: %s ", nl_af2str(msg->idiag_family, buf, sizeof(buf)));
374 	nl_dump(p, "src: %s:%d ", nl_addr2str(msg->idiag_src, buf, sizeof(buf)),
375 			ntohs(msg->idiag_sport));
376 	nl_dump(p, "dst: %s:%d ", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)),
377 			ntohs(msg->idiag_dport));
378 	nl_dump(p, "iif: %d ", msg->idiag_ifindex);
379 	nl_dump(p, "\n");
380 }
381 
idiag_msg_dump_details(struct nl_object * a,struct nl_dump_params * p)382 static void idiag_msg_dump_details(struct nl_object *a, struct nl_dump_params *p)
383 {
384 	struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
385 	char buf[64], buf2[64];
386 
387 	nl_dump(p, "\nfamily: %s\n", nl_af2str(msg->idiag_family, buf, sizeof(buf)));
388 	nl_dump(p, "state: %s\n",
389 			idiagnl_state2str(msg->idiag_state, buf, sizeof(buf)));
390 	nl_dump(p, "timer (%s, %s, retransmits: %d)\n",
391 			idiagnl_timer2str(msg->idiag_timer, buf, sizeof(buf)),
392 			nl_msec2str(msg->idiag_expires, buf2, sizeof(buf2)),
393 			msg->idiag_retrans);
394 
395 	nl_dump(p, "source: %s:%d\n", nl_addr2str(msg->idiag_src, buf, sizeof(buf)),
396 			ntohs(msg->idiag_sport));
397 	nl_dump(p, "destination: %s:%d\n", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)),
398 			ntohs(msg->idiag_dport));
399 
400 	nl_dump(p, "ifindex: %d\n", msg->idiag_ifindex);
401 	nl_dump(p, "rqueue: %-6d wqueue: %-6d\n", msg->idiag_rqueue, msg->idiag_wqueue);
402 	nl_dump(p, "uid %d\n", msg->idiag_uid);
403 	nl_dump(p, "inode %d\n", msg->idiag_inode);
404 	if (msg->idiag_shutdown) {
405 		nl_dump(p, "socket shutdown: %s\n",
406 				idiagnl_shutdown2str(msg->idiag_shutdown,
407 					buf, sizeof(buf)));
408 	}
409 
410 	nl_dump(p, "tos: 0x%x\n", msg->idiag_tos);
411 	nl_dump(p, "traffic class: %d\n", msg->idiag_tclass);
412 	nl_dump(p, "congestion algorithm: %s\n", msg->idiag_cong);
413 }
414 
idiag_msg_dump_stats(struct nl_object * obj,struct nl_dump_params * p)415 static void idiag_msg_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
416 {
417 	struct idiagnl_msg *msg = (struct idiagnl_msg *) obj;
418 	char buf[64];
419 
420 	idiag_msg_dump_details(obj, p);
421 
422 	nl_dump(p, "tcp info:  [\n");
423 	nl_dump(p, "\tsocket state: %s\n",
424 			idiagnl_state2str(msg->idiag_tcpinfo.tcpi_state,
425 				buf, sizeof(buf)));
426 	nl_dump(p, "\ttcp state: %s\n",
427 			idiagnl_tcpstate2str(msg->idiag_tcpinfo.tcpi_ca_state,
428 				buf, sizeof(buf)));
429 	nl_dump(p, "\tretransmits: %d\n",
430 			msg->idiag_tcpinfo.tcpi_retransmits);
431 	nl_dump(p, "\tprobes: %d\n",
432 			msg->idiag_tcpinfo.tcpi_probes);
433 	nl_dump(p, "\tbackoff: %d\n",
434 			msg->idiag_tcpinfo.tcpi_backoff);
435 	nl_dump(p, "\toptions: %s\n",
436 			idiagnl_tcpopts2str(msg->idiag_tcpinfo.tcpi_options,
437 				buf, sizeof(buf)));
438 	nl_dump(p, "\tsnd_wscale: %d\n", msg->idiag_tcpinfo.tcpi_snd_wscale);
439 	nl_dump(p, "\trcv_wscale: %d\n", msg->idiag_tcpinfo.tcpi_rcv_wscale);
440 	nl_dump(p, "\trto: %d\n", msg->idiag_tcpinfo.tcpi_rto);
441 	nl_dump(p, "\tato: %d\n", msg->idiag_tcpinfo.tcpi_ato);
442 	nl_dump(p, "\tsnd_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_snd_mss,
443 				buf, sizeof(buf)));
444 	nl_dump(p, "\trcv_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_mss,
445 				buf, sizeof(buf)));
446 	nl_dump(p, "\tunacked: %d\n", msg->idiag_tcpinfo.tcpi_unacked);
447 	nl_dump(p, "\tsacked: %d\n", msg->idiag_tcpinfo.tcpi_sacked);
448 
449 	nl_dump(p, "\tlost: %d\n", msg->idiag_tcpinfo.tcpi_lost);
450 	nl_dump(p, "\tretransmit segments: %d\n",
451 			msg->idiag_tcpinfo.tcpi_retrans);
452 	nl_dump(p, "\tfackets: %d\n",
453 			msg->idiag_tcpinfo.tcpi_fackets);
454 	nl_dump(p, "\tlast data sent: %s\n",
455 			nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_sent, buf,
456 				sizeof(buf)));
457 	nl_dump(p, "\tlast ack sent: %s\n",
458 			nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_sent, buf, sizeof(buf)));
459 	nl_dump(p, "\tlast data recv: %s\n",
460 			nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_recv, buf,
461 				sizeof(buf)));
462 	nl_dump(p, "\tlast ack recv: %s\n",
463 			nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_recv, buf,
464 				sizeof(buf)));
465 	nl_dump(p, "\tpath mtu: %s\n",
466 			nl_size2str(msg->idiag_tcpinfo.tcpi_pmtu, buf,
467 				sizeof(buf)));
468 	nl_dump(p, "\trcv ss threshold: %d\n",
469 			msg->idiag_tcpinfo.tcpi_rcv_ssthresh);
470 	nl_dump(p, "\tsmoothed round trip time: %d\n",
471 			msg->idiag_tcpinfo.tcpi_rtt);
472 	nl_dump(p, "\tround trip time variation: %d\n",
473 			msg->idiag_tcpinfo.tcpi_rttvar);
474 	nl_dump(p, "\tsnd ss threshold: %s\n",
475 			nl_size2str(msg->idiag_tcpinfo.tcpi_snd_ssthresh, buf,
476 				sizeof(buf)));
477 	nl_dump(p, "\tsend congestion window: %d\n",
478 			msg->idiag_tcpinfo.tcpi_snd_cwnd);
479 	nl_dump(p, "\tadvertised mss: %s\n",
480 			nl_size2str(msg->idiag_tcpinfo.tcpi_advmss, buf,
481 				sizeof(buf)));
482 	nl_dump(p, "\treordering: %d\n",
483 			msg->idiag_tcpinfo.tcpi_reordering);
484 	nl_dump(p, "\trcv rround trip time: %d\n",
485 			msg->idiag_tcpinfo.tcpi_rcv_rtt);
486 	nl_dump(p, "\treceive queue space: %s\n",
487 			nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_space, buf,
488 				sizeof(buf)));
489 	nl_dump(p, "\ttotal retransmits: %d\n",
490 			msg->idiag_tcpinfo.tcpi_total_retrans);
491 	nl_dump(p, "]\n");
492 
493 	if (msg->idiag_meminfo) {
494 		nl_dump(p, "meminfo:  [\n");
495 		nl_dump(p, "\trmem: %s\n",
496 				nl_size2str(msg->idiag_meminfo->idiag_rmem,
497 					    buf,
498 					    sizeof(buf)));
499 		nl_dump(p, "\twmem: %s\n",
500 				nl_size2str(msg->idiag_meminfo->idiag_wmem,
501 					    buf,
502 					    sizeof(buf)));
503 		nl_dump(p, "\tfmem: %s\n",
504 				nl_size2str(msg->idiag_meminfo->idiag_fmem,
505 					    buf,
506 					    sizeof(buf)));
507 		nl_dump(p, "\ttmem: %s\n",
508 				nl_size2str(msg->idiag_meminfo->idiag_tmem,
509 					    buf,
510 					    sizeof(buf)));
511 		nl_dump(p, "]\n");
512 	}
513 
514 	if (msg->idiag_vegasinfo) {
515 		nl_dump(p, "vegasinfo:  [\n");
516 		nl_dump(p, "\tvegas enabled: %d\n",
517 				msg->idiag_vegasinfo->tcpv_enabled);
518 		if (msg->idiag_vegasinfo->tcpv_enabled) {
519 			nl_dump(p, "\trtt cnt: %d",
520 					msg->idiag_vegasinfo->tcpv_rttcnt);
521 			nl_dump(p, "\trtt (propagation delay): %d",
522 					msg->idiag_vegasinfo->tcpv_rtt);
523 			nl_dump(p, "\tmin rtt: %d",
524 					msg->idiag_vegasinfo->tcpv_minrtt);
525 		}
526 		nl_dump(p, "]\n");
527 	}
528 
529 	nl_dump(p, "skmeminfo:  [\n");
530 	nl_dump(p, "\trmem alloc: %d\n",
531 			msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RMEM_ALLOC]);
532 	nl_dump(p, "\trcv buf: %s\n",
533 			nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RCVBUF],
534 				buf, sizeof(buf)));
535 	nl_dump(p, "\twmem alloc: %d\n",
536 			msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_ALLOC]);
537 	nl_dump(p, "\tsnd buf: %s\n",
538 			nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_SNDBUF],
539 				buf, sizeof(buf)));
540 	nl_dump(p, "\tfwd alloc: %d\n",
541 			msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_FWD_ALLOC]);
542 	nl_dump(p, "\twmem queued: %s\n",
543 			nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_QUEUED],
544 				buf, sizeof(buf)));
545 	nl_dump(p, "\topt mem: %d\n",
546 			msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_OPTMEM]);
547 	nl_dump(p, "\tbacklog: %d\n",
548 			msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_BACKLOG]);
549 	nl_dump(p, "]\n\n");
550 }
551 
idiagnl_msg_free(struct nl_object * a)552 static void idiagnl_msg_free(struct nl_object *a)
553 {
554 	struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
555 	if (a == NULL)
556 		return;
557 
558 	free(msg->idiag_cong);
559 	nl_addr_put(msg->idiag_src);
560 	nl_addr_put(msg->idiag_dst);
561 	idiagnl_meminfo_put(msg->idiag_meminfo);
562 	idiagnl_vegasinfo_put(msg->idiag_vegasinfo);
563 }
564 
idiagnl_msg_clone(struct nl_object * _dst,struct nl_object * _src)565 static int idiagnl_msg_clone(struct nl_object *_dst, struct nl_object *_src)
566 {
567 	struct idiagnl_msg *dst = (struct idiagnl_msg *) _dst;
568 	struct idiagnl_msg *src = (struct idiagnl_msg *) _src;
569 
570 	if (src->idiag_src)
571 		if (!(dst->idiag_src = nl_addr_clone(src->idiag_src)))
572 			return -NLE_NOMEM;
573 
574 	if (src->idiag_dst)
575 		if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst)))
576 			return -NLE_NOMEM;
577 
578 	return 0;
579 }
580 
581 static struct nla_policy ext_policy[IDIAG_ATTR_MAX] = {
582 	[IDIAG_ATTR_MEMINFO]    = { .minlen = sizeof(struct inet_diag_meminfo) },
583 	[IDIAG_ATTR_INFO]       = { .minlen = sizeof(struct tcp_info)	},
584 	[IDIAG_ATTR_VEGASINFO]  = { .minlen = sizeof(struct tcpvegas_info) },
585 	[IDIAG_ATTR_CONG]       = { .type = NLA_STRING },
586 	[IDIAG_ATTR_TOS]        = { .type = NLA_U8 },
587 	[IDIAG_ATTR_TCLASS]     = { .type = NLA_U8 },
588 	[IDIAG_ATTR_SKMEMINFO]  = { .minlen = (sizeof(uint32_t) * IDIAG_SK_MEMINFO_VARS)  },
589 	[IDIAG_ATTR_SHUTDOWN]   = { .type = NLA_U8 },
590 };
591 
idiagnl_msg_parse(struct nlmsghdr * nlh,struct idiagnl_msg ** result)592 int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
593 {
594 	struct idiagnl_msg *msg = NULL;
595 	struct inet_diag_msg *raw_msg = NULL;
596 	struct nl_addr *src = NULL, *dst = NULL;
597 	struct nlattr *tb[IDIAG_ATTR_MAX];
598 	int err = 0;
599 
600 	msg = idiagnl_msg_alloc();
601 	if (!msg)
602 		goto errout_nomem;
603 
604 	err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, IDIAG_ATTR_MAX,
605 			ext_policy);
606 	if (err < 0)
607 		goto errout;
608 
609 	raw_msg = nlmsg_data(nlh);
610 	msg->idiag_family = raw_msg->idiag_family;
611 	msg->idiag_state = raw_msg->idiag_state;
612 	msg->idiag_timer = raw_msg->idiag_timer;
613 	msg->idiag_retrans = raw_msg->idiag_retrans;
614 	msg->idiag_expires = raw_msg->idiag_expires;
615 	msg->idiag_rqueue = raw_msg->idiag_rqueue;
616 	msg->idiag_wqueue = raw_msg->idiag_wqueue;
617 	msg->idiag_uid = raw_msg->idiag_uid;
618 	msg->idiag_inode = raw_msg->idiag_inode;
619 	msg->idiag_sport = raw_msg->id.idiag_sport;
620 	msg->idiag_dport = raw_msg->id.idiag_dport;
621 	msg->idiag_ifindex = raw_msg->id.idiag_if;
622 
623 	dst = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_dst,
624 			sizeof(raw_msg->id.idiag_dst));
625 	if (!dst)
626 		goto errout_nomem;
627 
628 	err = idiagnl_msg_set_dst(msg, dst);
629 	if (err < 0)
630 		goto errout;
631 
632 	nl_addr_put(dst);
633 
634 	src = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_src,
635 			sizeof(raw_msg->id.idiag_src));
636 	if (!src)
637 		goto errout_nomem;
638 
639 	err = idiagnl_msg_set_src(msg, src);
640 	if (err < 0)
641 		goto errout;
642 
643 	nl_addr_put(src);
644 
645 	if (tb[IDIAG_ATTR_TOS])
646 		msg->idiag_tos = nla_get_u8(tb[IDIAG_ATTR_TOS]);
647 
648 	if (tb[IDIAG_ATTR_TCLASS])
649 		msg->idiag_tclass = nla_get_u8(tb[IDIAG_ATTR_TCLASS]);
650 
651 	if (tb[IDIAG_ATTR_SHUTDOWN])
652 		msg->idiag_shutdown = nla_get_u8(tb[IDIAG_ATTR_SHUTDOWN]);
653 
654 	if (tb[IDIAG_ATTR_CONG])
655 		msg->idiag_cong = nla_strdup(tb[IDIAG_ATTR_CONG]);
656 
657 	if (tb[IDIAG_ATTR_INFO])
658 		nla_memcpy(&msg->idiag_tcpinfo, tb[IDIAG_ATTR_INFO],
659 				sizeof(msg->idiag_tcpinfo));
660 
661 	if (tb[IDIAG_ATTR_MEMINFO]) {
662 		struct idiagnl_meminfo *minfo = idiagnl_meminfo_alloc();
663 		struct inet_diag_meminfo *raw_minfo = NULL;
664 
665 		if (!minfo)
666 			goto errout_nomem;
667 
668 		raw_minfo = (struct inet_diag_meminfo *)
669 			nla_data(tb[IDIAG_ATTR_MEMINFO]);
670 
671 		idiagnl_meminfo_set_rmem(minfo, raw_minfo->idiag_rmem);
672 		idiagnl_meminfo_set_wmem(minfo, raw_minfo->idiag_wmem);
673 		idiagnl_meminfo_set_fmem(minfo, raw_minfo->idiag_fmem);
674 		idiagnl_meminfo_set_tmem(minfo, raw_minfo->idiag_tmem);
675 
676 		msg->idiag_meminfo = minfo;
677 	}
678 
679 	if (tb[IDIAG_ATTR_VEGASINFO]) {
680 		struct idiagnl_vegasinfo *vinfo = idiagnl_vegasinfo_alloc();
681 		struct tcpvegas_info *raw_vinfo = NULL;
682 
683 		if (!vinfo)
684 			goto errout_nomem;
685 
686 		raw_vinfo = (struct tcpvegas_info *)
687 			nla_data(tb[IDIAG_ATTR_VEGASINFO]);
688 
689 		idiagnl_vegasinfo_set_enabled(vinfo, raw_vinfo->tcpv_enabled);
690 		idiagnl_vegasinfo_set_rttcnt(vinfo, raw_vinfo->tcpv_rttcnt);
691 		idiagnl_vegasinfo_set_rtt(vinfo, raw_vinfo->tcpv_rtt);
692 		idiagnl_vegasinfo_set_minrtt(vinfo, raw_vinfo->tcpv_minrtt);
693 
694 		msg->idiag_vegasinfo = vinfo;
695 	}
696 
697 	if (tb[IDIAG_ATTR_SKMEMINFO])
698 		nla_memcpy(&msg->idiag_skmeminfo, tb[IDIAG_ATTR_SKMEMINFO],
699 				sizeof(msg->idiag_skmeminfo));
700 
701 	*result = msg;
702 	return 0;
703 
704 errout:
705 	idiagnl_msg_put(msg);
706 	return err;
707 
708 errout_nomem:
709 	err = -NLE_NOMEM;
710 	goto errout;
711 }
712 
713 /** @cond SKIP */
714 struct nl_object_ops idiagnl_msg_obj_ops = {
715 	.oo_name			 = "idiag/idiag_msg",
716 	.oo_size			 = sizeof(struct idiagnl_msg),
717 	.oo_free_data			 = idiagnl_msg_free,
718 	.oo_clone			 = idiagnl_msg_clone,
719 	.oo_dump			 = {
720 		[NL_DUMP_LINE]		 = idiag_msg_dump_line,
721 		[NL_DUMP_DETAILS]	 = idiag_msg_dump_details,
722 		[NL_DUMP_STATS]		 = idiag_msg_dump_stats,
723 	},
724 	.oo_attrs2str			= idiagnl_attrs2str,
725 	.oo_id_attrs			= (IDIAG_ATTR_INFO)
726 };
727 /** @endcond */
728 
729 /** @} */
730