2 * Copyright (c) 2014, Ericsson AB
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the names of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
37 #include "name_table.h"
41 #include <net/genetlink.h>
42 #include <linux/tipc_config.h>
44 /* The legacy API had an artificial message length limit called
45 * ULTRA_STRING_MAX_LEN.
47 #define ULTRA_STRING_MAX_LEN 32768
49 #define TIPC_SKB_MAX TLV_SPACE(ULTRA_STRING_MAX_LEN)
51 #define REPLY_TRUNCATED "<truncated>\n"
53 struct tipc_nl_compat_msg
{
63 struct tipc_nl_compat_cmd_dump
{
64 int (*header
)(struct tipc_nl_compat_msg
*);
65 int (*dumpit
)(struct sk_buff
*, struct netlink_callback
*);
66 int (*format
)(struct tipc_nl_compat_msg
*msg
, struct nlattr
**attrs
);
69 struct tipc_nl_compat_cmd_doit
{
70 int (*doit
)(struct sk_buff
*skb
, struct genl_info
*info
);
71 int (*transcode
)(struct sk_buff
*skb
, struct tipc_nl_compat_msg
*msg
);
74 static int tipc_skb_tailroom(struct sk_buff
*skb
)
79 tailroom
= skb_tailroom(skb
);
80 limit
= TIPC_SKB_MAX
- skb
->len
;
88 static int tipc_add_tlv(struct sk_buff
*skb
, u16 type
, void *data
, u16 len
)
90 struct tlv_desc
*tlv
= (struct tlv_desc
*)skb_tail_pointer(skb
);
92 if (tipc_skb_tailroom(skb
) < TLV_SPACE(len
))
95 skb_put(skb
, TLV_SPACE(len
));
96 tlv
->tlv_type
= htons(type
);
97 tlv
->tlv_len
= htons(TLV_LENGTH(len
));
99 memcpy(TLV_DATA(tlv
), data
, len
);
104 static void tipc_tlv_init(struct sk_buff
*skb
, u16 type
)
106 struct tlv_desc
*tlv
= (struct tlv_desc
*)skb
->data
;
109 TLV_SET_TYPE(tlv
, type
);
110 skb_put(skb
, sizeof(struct tlv_desc
));
113 static int tipc_tlv_sprintf(struct sk_buff
*skb
, const char *fmt
, ...)
119 struct tlv_desc
*tlv
;
122 rem
= tipc_skb_tailroom(skb
);
124 tlv
= (struct tlv_desc
*)skb
->data
;
125 len
= TLV_GET_LEN(tlv
);
126 buf
= TLV_DATA(tlv
) + len
;
129 n
= vscnprintf(buf
, rem
, fmt
, args
);
132 TLV_SET_LEN(tlv
, n
+ len
);
138 static struct sk_buff
*tipc_tlv_alloc(int size
)
143 size
= TLV_SPACE(size
);
144 hdr_len
= nlmsg_total_size(GENL_HDRLEN
+ TIPC_GENL_HDRLEN
);
146 buf
= alloc_skb(hdr_len
+ size
, GFP_KERNEL
);
150 skb_reserve(buf
, hdr_len
);
155 static struct sk_buff
*tipc_get_err_tlv(char *str
)
157 int str_len
= strlen(str
) + 1;
160 buf
= tipc_tlv_alloc(TLV_SPACE(str_len
));
162 tipc_add_tlv(buf
, TIPC_TLV_ERROR_STRING
, str
, str_len
);
167 static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump
*cmd
,
168 struct tipc_nl_compat_msg
*msg
,
174 struct nlmsghdr
*nlmsg
;
175 struct netlink_callback cb
;
177 memset(&cb
, 0, sizeof(cb
));
178 cb
.nlh
= (struct nlmsghdr
*)arg
->data
;
181 buf
= nlmsg_new(NLMSG_GOODSIZE
, GFP_KERNEL
);
185 buf
->sk
= msg
->dst_sk
;
190 len
= (*cmd
->dumpit
)(buf
, &cb
);
192 nlmsg_for_each_msg(nlmsg
, nlmsg_hdr(buf
), len
, rem
) {
193 struct nlattr
**attrs
;
195 err
= tipc_nlmsg_parse(nlmsg
, &attrs
);
199 err
= (*cmd
->format
)(msg
, attrs
);
203 if (tipc_skb_tailroom(msg
->rep
) <= 1) {
209 skb_reset_tail_pointer(buf
);
219 if (err
== -EMSGSIZE
) {
220 /* The legacy API only considered messages filling
221 * "ULTRA_STRING_MAX_LEN" to be truncated.
223 if ((TIPC_SKB_MAX
- msg
->rep
->len
) <= 1) {
224 char *tail
= skb_tail_pointer(msg
->rep
);
227 sprintf(tail
- sizeof(REPLY_TRUNCATED
) - 1,
237 static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump
*cmd
,
238 struct tipc_nl_compat_msg
*msg
)
243 if (msg
->req_type
&& !TLV_CHECK_TYPE(msg
->req
, msg
->req_type
))
246 msg
->rep
= tipc_tlv_alloc(msg
->rep_size
);
251 tipc_tlv_init(msg
->rep
, msg
->rep_type
);
256 arg
= nlmsg_new(0, GFP_KERNEL
);
262 err
= __tipc_nl_compat_dumpit(cmd
, msg
, arg
);
271 static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit
*cmd
,
272 struct tipc_nl_compat_msg
*msg
)
275 struct sk_buff
*doit_buf
;
276 struct sk_buff
*trans_buf
;
277 struct nlattr
**attrbuf
;
278 struct genl_info info
;
280 trans_buf
= alloc_skb(NLMSG_GOODSIZE
, GFP_KERNEL
);
284 err
= (*cmd
->transcode
)(trans_buf
, msg
);
288 attrbuf
= kmalloc((tipc_genl_family
.maxattr
+ 1) *
289 sizeof(struct nlattr
*), GFP_KERNEL
);
295 err
= nla_parse(attrbuf
, tipc_genl_family
.maxattr
,
296 (const struct nlattr
*)trans_buf
->data
,
297 trans_buf
->len
, NULL
);
301 doit_buf
= alloc_skb(NLMSG_GOODSIZE
, GFP_KERNEL
);
307 doit_buf
->sk
= msg
->dst_sk
;
309 memset(&info
, 0, sizeof(info
));
310 info
.attrs
= attrbuf
;
312 err
= (*cmd
->doit
)(doit_buf
, &info
);
318 kfree_skb(trans_buf
);
323 static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit
*cmd
,
324 struct tipc_nl_compat_msg
*msg
)
328 if (msg
->req_type
&& !TLV_CHECK_TYPE(msg
->req
, msg
->req_type
))
331 err
= __tipc_nl_compat_doit(cmd
, msg
);
335 /* The legacy API considered an empty message a success message */
336 msg
->rep
= tipc_tlv_alloc(0);
343 static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg
*msg
,
344 struct nlattr
**attrs
)
346 struct nlattr
*bearer
[TIPC_NLA_BEARER_MAX
+ 1];
348 nla_parse_nested(bearer
, TIPC_NLA_BEARER_MAX
, attrs
[TIPC_NLA_BEARER
],
351 return tipc_add_tlv(msg
->rep
, TIPC_TLV_BEARER_NAME
,
352 nla_data(bearer
[TIPC_NLA_BEARER_NAME
]),
353 nla_len(bearer
[TIPC_NLA_BEARER_NAME
]));
356 static int tipc_nl_compat_bearer_enable(struct sk_buff
*skb
,
357 struct tipc_nl_compat_msg
*msg
)
360 struct nlattr
*bearer
;
361 struct tipc_bearer_config
*b
;
363 b
= (struct tipc_bearer_config
*)TLV_DATA(msg
->req
);
365 bearer
= nla_nest_start(skb
, TIPC_NLA_BEARER
);
369 if (nla_put_string(skb
, TIPC_NLA_BEARER_NAME
, b
->name
))
372 if (nla_put_u32(skb
, TIPC_NLA_BEARER_DOMAIN
, ntohl(b
->disc_domain
)))
375 if (ntohl(b
->priority
) <= TIPC_MAX_LINK_PRI
) {
376 prop
= nla_nest_start(skb
, TIPC_NLA_BEARER_PROP
);
379 if (nla_put_u32(skb
, TIPC_NLA_PROP_PRIO
, ntohl(b
->priority
)))
381 nla_nest_end(skb
, prop
);
383 nla_nest_end(skb
, bearer
);
388 static int tipc_nl_compat_bearer_disable(struct sk_buff
*skb
,
389 struct tipc_nl_compat_msg
*msg
)
392 struct nlattr
*bearer
;
394 name
= (char *)TLV_DATA(msg
->req
);
396 bearer
= nla_nest_start(skb
, TIPC_NLA_BEARER
);
400 if (nla_put_string(skb
, TIPC_NLA_BEARER_NAME
, name
))
403 nla_nest_end(skb
, bearer
);
408 static inline u32
perc(u32 count
, u32 total
)
410 return (count
* 100 + (total
/ 2)) / total
;
413 static void __fill_bc_link_stat(struct tipc_nl_compat_msg
*msg
,
414 struct nlattr
*prop
[], struct nlattr
*stats
[])
416 tipc_tlv_sprintf(msg
->rep
, " Window:%u packets\n",
417 nla_get_u32(prop
[TIPC_NLA_PROP_WIN
]));
419 tipc_tlv_sprintf(msg
->rep
,
420 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
421 nla_get_u32(stats
[TIPC_NLA_STATS_RX_INFO
]),
422 nla_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTS
]),
423 nla_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTED
]),
424 nla_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLES
]),
425 nla_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLED
]));
427 tipc_tlv_sprintf(msg
->rep
,
428 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
429 nla_get_u32(stats
[TIPC_NLA_STATS_TX_INFO
]),
430 nla_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTS
]),
431 nla_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTED
]),
432 nla_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLES
]),
433 nla_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLED
]));
435 tipc_tlv_sprintf(msg
->rep
, " RX naks:%u defs:%u dups:%u\n",
436 nla_get_u32(stats
[TIPC_NLA_STATS_RX_NACKS
]),
437 nla_get_u32(stats
[TIPC_NLA_STATS_RX_DEFERRED
]),
438 nla_get_u32(stats
[TIPC_NLA_STATS_DUPLICATES
]));
440 tipc_tlv_sprintf(msg
->rep
, " TX naks:%u acks:%u dups:%u\n",
441 nla_get_u32(stats
[TIPC_NLA_STATS_TX_NACKS
]),
442 nla_get_u32(stats
[TIPC_NLA_STATS_TX_ACKS
]),
443 nla_get_u32(stats
[TIPC_NLA_STATS_RETRANSMITTED
]));
445 tipc_tlv_sprintf(msg
->rep
,
446 " Congestion link:%u Send queue max:%u avg:%u",
447 nla_get_u32(stats
[TIPC_NLA_STATS_LINK_CONGS
]),
448 nla_get_u32(stats
[TIPC_NLA_STATS_MAX_QUEUE
]),
449 nla_get_u32(stats
[TIPC_NLA_STATS_AVG_QUEUE
]));
452 static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg
*msg
,
453 struct nlattr
**attrs
)
456 struct nlattr
*link
[TIPC_NLA_LINK_MAX
+ 1];
457 struct nlattr
*prop
[TIPC_NLA_PROP_MAX
+ 1];
458 struct nlattr
*stats
[TIPC_NLA_STATS_MAX
+ 1];
460 nla_parse_nested(link
, TIPC_NLA_LINK_MAX
, attrs
[TIPC_NLA_LINK
], NULL
);
462 nla_parse_nested(prop
, TIPC_NLA_PROP_MAX
, link
[TIPC_NLA_LINK_PROP
],
465 nla_parse_nested(stats
, TIPC_NLA_STATS_MAX
, link
[TIPC_NLA_LINK_STATS
],
468 name
= (char *)TLV_DATA(msg
->req
);
469 if (strcmp(name
, nla_data(link
[TIPC_NLA_LINK_NAME
])) != 0)
472 tipc_tlv_sprintf(msg
->rep
, "\nLink <%s>\n",
473 nla_data(link
[TIPC_NLA_LINK_NAME
]));
475 if (link
[TIPC_NLA_LINK_BROADCAST
]) {
476 __fill_bc_link_stat(msg
, prop
, stats
);
480 if (link
[TIPC_NLA_LINK_ACTIVE
])
481 tipc_tlv_sprintf(msg
->rep
, " ACTIVE");
482 else if (link
[TIPC_NLA_LINK_UP
])
483 tipc_tlv_sprintf(msg
->rep
, " STANDBY");
485 tipc_tlv_sprintf(msg
->rep
, " DEFUNCT");
487 tipc_tlv_sprintf(msg
->rep
, " MTU:%u Priority:%u",
488 nla_get_u32(link
[TIPC_NLA_LINK_MTU
]),
489 nla_get_u32(prop
[TIPC_NLA_PROP_PRIO
]));
491 tipc_tlv_sprintf(msg
->rep
, " Tolerance:%u ms Window:%u packets\n",
492 nla_get_u32(prop
[TIPC_NLA_PROP_TOL
]),
493 nla_get_u32(prop
[TIPC_NLA_PROP_WIN
]));
495 tipc_tlv_sprintf(msg
->rep
,
496 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
497 nla_get_u32(link
[TIPC_NLA_LINK_RX
]) -
498 nla_get_u32(stats
[TIPC_NLA_STATS_RX_INFO
]),
499 nla_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTS
]),
500 nla_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTED
]),
501 nla_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLES
]),
502 nla_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLED
]));
504 tipc_tlv_sprintf(msg
->rep
,
505 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
506 nla_get_u32(link
[TIPC_NLA_LINK_TX
]) -
507 nla_get_u32(stats
[TIPC_NLA_STATS_TX_INFO
]),
508 nla_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTS
]),
509 nla_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTED
]),
510 nla_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLES
]),
511 nla_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLED
]));
513 tipc_tlv_sprintf(msg
->rep
,
514 " TX profile sample:%u packets average:%u octets\n",
515 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_CNT
]),
516 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_TOT
]) /
517 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
]));
519 tipc_tlv_sprintf(msg
->rep
,
520 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% ",
521 perc(nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P0
]),
522 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
])),
523 perc(nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P1
]),
524 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
])),
525 perc(nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P2
]),
526 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
])),
527 perc(nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P3
]),
528 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
])));
530 tipc_tlv_sprintf(msg
->rep
, "-16384:%u%% -32768:%u%% -66000:%u%%\n",
531 perc(nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P4
]),
532 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
])),
533 perc(nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P5
]),
534 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
])),
535 perc(nla_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P6
]),
536 nla_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
])));
538 tipc_tlv_sprintf(msg
->rep
,
539 " RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
540 nla_get_u32(stats
[TIPC_NLA_STATS_RX_STATES
]),
541 nla_get_u32(stats
[TIPC_NLA_STATS_RX_PROBES
]),
542 nla_get_u32(stats
[TIPC_NLA_STATS_RX_NACKS
]),
543 nla_get_u32(stats
[TIPC_NLA_STATS_RX_DEFERRED
]),
544 nla_get_u32(stats
[TIPC_NLA_STATS_DUPLICATES
]));
546 tipc_tlv_sprintf(msg
->rep
,
547 " TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
548 nla_get_u32(stats
[TIPC_NLA_STATS_TX_STATES
]),
549 nla_get_u32(stats
[TIPC_NLA_STATS_TX_PROBES
]),
550 nla_get_u32(stats
[TIPC_NLA_STATS_TX_NACKS
]),
551 nla_get_u32(stats
[TIPC_NLA_STATS_TX_ACKS
]),
552 nla_get_u32(stats
[TIPC_NLA_STATS_RETRANSMITTED
]));
554 tipc_tlv_sprintf(msg
->rep
,
555 " Congestion link:%u Send queue max:%u avg:%u",
556 nla_get_u32(stats
[TIPC_NLA_STATS_LINK_CONGS
]),
557 nla_get_u32(stats
[TIPC_NLA_STATS_MAX_QUEUE
]),
558 nla_get_u32(stats
[TIPC_NLA_STATS_AVG_QUEUE
]));
563 static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg
*msg
,
564 struct nlattr
**attrs
)
566 struct nlattr
*link
[TIPC_NLA_LINK_MAX
+ 1];
567 struct tipc_link_info link_info
;
569 nla_parse_nested(link
, TIPC_NLA_LINK_MAX
, attrs
[TIPC_NLA_LINK
], NULL
);
571 link_info
.dest
= nla_get_flag(link
[TIPC_NLA_LINK_DEST
]);
572 link_info
.up
= htonl(nla_get_flag(link
[TIPC_NLA_LINK_UP
]));
573 strcpy(link_info
.str
, nla_data(link
[TIPC_NLA_LINK_NAME
]));
575 return tipc_add_tlv(msg
->rep
, TIPC_TLV_LINK_INFO
,
576 &link_info
, sizeof(link_info
));
579 static int tipc_nl_compat_link_set(struct sk_buff
*skb
,
580 struct tipc_nl_compat_msg
*msg
)
584 struct tipc_link_config
*lc
;
586 lc
= (struct tipc_link_config
*)TLV_DATA(msg
->req
);
588 link
= nla_nest_start(skb
, TIPC_NLA_LINK
);
592 if (nla_put_string(skb
, TIPC_NLA_LINK_NAME
, lc
->name
))
595 prop
= nla_nest_start(skb
, TIPC_NLA_LINK_PROP
);
599 if (msg
->cmd
== TIPC_CMD_SET_LINK_PRI
) {
600 if (nla_put_u32(skb
, TIPC_NLA_PROP_PRIO
, ntohl(lc
->value
)))
602 } else if (msg
->cmd
== TIPC_CMD_SET_LINK_TOL
) {
603 if (nla_put_u32(skb
, TIPC_NLA_PROP_TOL
, ntohl(lc
->value
)))
605 } else if (msg
->cmd
== TIPC_CMD_SET_LINK_WINDOW
) {
606 if (nla_put_u32(skb
, TIPC_NLA_PROP_WIN
, ntohl(lc
->value
)))
610 nla_nest_end(skb
, prop
);
611 nla_nest_end(skb
, link
);
616 static int tipc_nl_compat_link_reset_stats(struct sk_buff
*skb
,
617 struct tipc_nl_compat_msg
*msg
)
622 name
= (char *)TLV_DATA(msg
->req
);
624 link
= nla_nest_start(skb
, TIPC_NLA_LINK
);
628 if (nla_put_string(skb
, TIPC_NLA_LINK_NAME
, name
))
631 nla_nest_end(skb
, link
);
636 static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg
*msg
)
640 struct tipc_name_table_query
*ntq
;
641 static const char * const header
[] = {
648 ntq
= (struct tipc_name_table_query
*)TLV_DATA(msg
->req
);
650 depth
= ntohl(ntq
->depth
);
654 for (i
= 0; i
< depth
; i
++)
655 tipc_tlv_sprintf(msg
->rep
, header
[i
]);
656 tipc_tlv_sprintf(msg
->rep
, "\n");
661 static int tipc_nl_compat_name_table_dump(struct tipc_nl_compat_msg
*msg
,
662 struct nlattr
**attrs
)
665 struct tipc_name_table_query
*ntq
;
666 struct nlattr
*nt
[TIPC_NLA_NAME_TABLE_MAX
+ 1];
667 struct nlattr
*publ
[TIPC_NLA_PUBL_MAX
+ 1];
668 u32 node
, depth
, type
, lowbound
, upbound
;
669 static const char * const scope_str
[] = {"", " zone", " cluster",
672 nla_parse_nested(nt
, TIPC_NLA_NAME_TABLE_MAX
,
673 attrs
[TIPC_NLA_NAME_TABLE
], NULL
);
675 nla_parse_nested(publ
, TIPC_NLA_PUBL_MAX
, nt
[TIPC_NLA_NAME_TABLE_PUBL
],
678 ntq
= (struct tipc_name_table_query
*)TLV_DATA(msg
->req
);
680 depth
= ntohl(ntq
->depth
);
681 type
= ntohl(ntq
->type
);
682 lowbound
= ntohl(ntq
->lowbound
);
683 upbound
= ntohl(ntq
->upbound
);
685 if (!(depth
& TIPC_NTQ_ALLTYPES
) &&
686 (type
!= nla_get_u32(publ
[TIPC_NLA_PUBL_TYPE
])))
688 if (lowbound
&& (lowbound
> nla_get_u32(publ
[TIPC_NLA_PUBL_UPPER
])))
690 if (upbound
&& (upbound
< nla_get_u32(publ
[TIPC_NLA_PUBL_LOWER
])))
693 tipc_tlv_sprintf(msg
->rep
, "%-10u ",
694 nla_get_u32(publ
[TIPC_NLA_PUBL_TYPE
]));
699 tipc_tlv_sprintf(msg
->rep
, "%-10u %-10u ",
700 nla_get_u32(publ
[TIPC_NLA_PUBL_LOWER
]),
701 nla_get_u32(publ
[TIPC_NLA_PUBL_UPPER
]));
706 node
= nla_get_u32(publ
[TIPC_NLA_PUBL_NODE
]);
707 sprintf(port_str
, "<%u.%u.%u:%u>", tipc_zone(node
), tipc_cluster(node
),
708 tipc_node(node
), nla_get_u32(publ
[TIPC_NLA_PUBL_REF
]));
709 tipc_tlv_sprintf(msg
->rep
, "%-26s ", port_str
);
714 tipc_tlv_sprintf(msg
->rep
, "%-10u %s",
715 nla_get_u32(publ
[TIPC_NLA_PUBL_REF
]),
716 scope_str
[nla_get_u32(publ
[TIPC_NLA_PUBL_SCOPE
])]);
718 tipc_tlv_sprintf(msg
->rep
, "\n");
723 static int __tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg
*msg
,
724 struct nlattr
**attrs
)
726 u32 type
, lower
, upper
;
727 struct nlattr
*publ
[TIPC_NLA_PUBL_MAX
+ 1];
729 nla_parse_nested(publ
, TIPC_NLA_PUBL_MAX
, attrs
[TIPC_NLA_PUBL
], NULL
);
731 type
= nla_get_u32(publ
[TIPC_NLA_PUBL_TYPE
]);
732 lower
= nla_get_u32(publ
[TIPC_NLA_PUBL_LOWER
]);
733 upper
= nla_get_u32(publ
[TIPC_NLA_PUBL_UPPER
]);
736 tipc_tlv_sprintf(msg
->rep
, " {%u,%u}", type
, lower
);
738 tipc_tlv_sprintf(msg
->rep
, " {%u,%u,%u}", type
, lower
, upper
);
743 static int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg
*msg
, u32 sock
)
748 struct sk_buff
*args
;
749 struct tipc_nl_compat_cmd_dump dump
;
751 args
= nlmsg_new(NLMSG_GOODSIZE
, GFP_KERNEL
);
755 hdr
= genlmsg_put(args
, 0, 0, &tipc_genl_family
, NLM_F_MULTI
,
758 nest
= nla_nest_start(args
, TIPC_NLA_SOCK
);
764 if (nla_put_u32(args
, TIPC_NLA_SOCK_REF
, sock
)) {
769 nla_nest_end(args
, nest
);
770 genlmsg_end(args
, hdr
);
772 dump
.dumpit
= tipc_nl_publ_dump
;
773 dump
.format
= __tipc_nl_compat_publ_dump
;
775 err
= __tipc_nl_compat_dumpit(&dump
, msg
, args
);
782 static int tipc_nl_compat_sk_dump(struct tipc_nl_compat_msg
*msg
,
783 struct nlattr
**attrs
)
787 struct nlattr
*sock
[TIPC_NLA_SOCK_MAX
+ 1];
789 nla_parse_nested(sock
, TIPC_NLA_SOCK_MAX
, attrs
[TIPC_NLA_SOCK
], NULL
);
791 sock_ref
= nla_get_u32(sock
[TIPC_NLA_SOCK_REF
]);
792 tipc_tlv_sprintf(msg
->rep
, "%u:", sock_ref
);
794 if (sock
[TIPC_NLA_SOCK_CON
]) {
796 struct nlattr
*con
[TIPC_NLA_CON_MAX
+ 1];
798 nla_parse_nested(con
, TIPC_NLA_CON_MAX
, sock
[TIPC_NLA_SOCK_CON
],
801 node
= nla_get_u32(con
[TIPC_NLA_CON_NODE
]);
802 tipc_tlv_sprintf(msg
->rep
, " connected to <%u.%u.%u:%u>",
806 nla_get_u32(con
[TIPC_NLA_CON_SOCK
]));
808 if (con
[TIPC_NLA_CON_FLAG
])
809 tipc_tlv_sprintf(msg
->rep
, " via {%u,%u}\n",
810 nla_get_u32(con
[TIPC_NLA_CON_TYPE
]),
811 nla_get_u32(con
[TIPC_NLA_CON_INST
]));
813 tipc_tlv_sprintf(msg
->rep
, "\n");
814 } else if (sock
[TIPC_NLA_SOCK_HAS_PUBL
]) {
815 tipc_tlv_sprintf(msg
->rep
, " bound to");
817 err
= tipc_nl_compat_publ_dump(msg
, sock_ref
);
821 tipc_tlv_sprintf(msg
->rep
, "\n");
826 static int tipc_nl_compat_media_dump(struct tipc_nl_compat_msg
*msg
,
827 struct nlattr
**attrs
)
829 struct nlattr
*media
[TIPC_NLA_MEDIA_MAX
+ 1];
831 nla_parse_nested(media
, TIPC_NLA_MEDIA_MAX
, attrs
[TIPC_NLA_MEDIA
],
834 return tipc_add_tlv(msg
->rep
, TIPC_TLV_MEDIA_NAME
,
835 nla_data(media
[TIPC_NLA_MEDIA_NAME
]),
836 nla_len(media
[TIPC_NLA_MEDIA_NAME
]));
839 static int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg
*msg
,
840 struct nlattr
**attrs
)
842 struct tipc_node_info node_info
;
843 struct nlattr
*node
[TIPC_NLA_NODE_MAX
+ 1];
845 nla_parse_nested(node
, TIPC_NLA_NODE_MAX
, attrs
[TIPC_NLA_NODE
], NULL
);
847 node_info
.addr
= htonl(nla_get_u32(node
[TIPC_NLA_NODE_ADDR
]));
848 node_info
.up
= htonl(nla_get_flag(node
[TIPC_NLA_NODE_UP
]));
850 return tipc_add_tlv(msg
->rep
, TIPC_TLV_NODE_INFO
, &node_info
,
854 static int tipc_nl_compat_net_set(struct sk_buff
*skb
,
855 struct tipc_nl_compat_msg
*msg
)
860 val
= ntohl(*(__be32
*)TLV_DATA(msg
->req
));
862 net
= nla_nest_start(skb
, TIPC_NLA_NET
);
866 if (msg
->cmd
== TIPC_CMD_SET_NODE_ADDR
) {
867 if (nla_put_u32(skb
, TIPC_NLA_NET_ADDR
, val
))
869 } else if (msg
->cmd
== TIPC_CMD_SET_NETID
) {
870 if (nla_put_u32(skb
, TIPC_NLA_NET_ID
, val
))
873 nla_nest_end(skb
, net
);
878 static int tipc_nl_compat_net_dump(struct tipc_nl_compat_msg
*msg
,
879 struct nlattr
**attrs
)
882 struct nlattr
*net
[TIPC_NLA_NET_MAX
+ 1];
884 nla_parse_nested(net
, TIPC_NLA_NET_MAX
, attrs
[TIPC_NLA_NET
], NULL
);
885 id
= htonl(nla_get_u32(net
[TIPC_NLA_NET_ID
]));
887 return tipc_add_tlv(msg
->rep
, TIPC_TLV_UNSIGNED
, &id
, sizeof(id
));
890 static int tipc_cmd_show_stats_compat(struct tipc_nl_compat_msg
*msg
)
892 msg
->rep
= tipc_tlv_alloc(ULTRA_STRING_MAX_LEN
);
896 tipc_tlv_init(msg
->rep
, TIPC_TLV_ULTRA_STRING
);
897 tipc_tlv_sprintf(msg
->rep
, "TIPC version " TIPC_MOD_VER
"\n");
902 static int tipc_nl_compat_handle(struct tipc_nl_compat_msg
*msg
)
904 struct tipc_nl_compat_cmd_dump dump
;
905 struct tipc_nl_compat_cmd_doit doit
;
907 memset(&dump
, 0, sizeof(dump
));
908 memset(&doit
, 0, sizeof(doit
));
912 msg
->rep
= tipc_tlv_alloc(0);
916 case TIPC_CMD_GET_BEARER_NAMES
:
917 msg
->rep_size
= MAX_BEARERS
* TLV_SPACE(TIPC_MAX_BEARER_NAME
);
918 dump
.dumpit
= tipc_nl_bearer_dump
;
919 dump
.format
= tipc_nl_compat_bearer_dump
;
920 return tipc_nl_compat_dumpit(&dump
, msg
);
921 case TIPC_CMD_ENABLE_BEARER
:
922 msg
->req_type
= TIPC_TLV_BEARER_CONFIG
;
923 doit
.doit
= tipc_nl_bearer_enable
;
924 doit
.transcode
= tipc_nl_compat_bearer_enable
;
925 return tipc_nl_compat_doit(&doit
, msg
);
926 case TIPC_CMD_DISABLE_BEARER
:
927 msg
->req_type
= TIPC_TLV_BEARER_NAME
;
928 doit
.doit
= tipc_nl_bearer_disable
;
929 doit
.transcode
= tipc_nl_compat_bearer_disable
;
930 return tipc_nl_compat_doit(&doit
, msg
);
931 case TIPC_CMD_SHOW_LINK_STATS
:
932 msg
->req_type
= TIPC_TLV_LINK_NAME
;
933 msg
->rep_size
= ULTRA_STRING_MAX_LEN
;
934 msg
->rep_type
= TIPC_TLV_ULTRA_STRING
;
935 dump
.dumpit
= tipc_nl_link_dump
;
936 dump
.format
= tipc_nl_compat_link_stat_dump
;
937 return tipc_nl_compat_dumpit(&dump
, msg
);
938 case TIPC_CMD_GET_LINKS
:
939 msg
->req_type
= TIPC_TLV_NET_ADDR
;
940 msg
->rep_size
= ULTRA_STRING_MAX_LEN
;
941 dump
.dumpit
= tipc_nl_link_dump
;
942 dump
.format
= tipc_nl_compat_link_dump
;
943 return tipc_nl_compat_dumpit(&dump
, msg
);
944 case TIPC_CMD_SET_LINK_TOL
:
945 case TIPC_CMD_SET_LINK_PRI
:
946 case TIPC_CMD_SET_LINK_WINDOW
:
947 msg
->req_type
= TIPC_TLV_LINK_CONFIG
;
948 doit
.doit
= tipc_nl_link_set
;
949 doit
.transcode
= tipc_nl_compat_link_set
;
950 return tipc_nl_compat_doit(&doit
, msg
);
951 case TIPC_CMD_RESET_LINK_STATS
:
952 msg
->req_type
= TIPC_TLV_LINK_NAME
;
953 doit
.doit
= tipc_nl_link_reset_stats
;
954 doit
.transcode
= tipc_nl_compat_link_reset_stats
;
955 return tipc_nl_compat_doit(&doit
, msg
);
956 case TIPC_CMD_SHOW_NAME_TABLE
:
957 msg
->req_type
= TIPC_TLV_NAME_TBL_QUERY
;
958 msg
->rep_size
= ULTRA_STRING_MAX_LEN
;
959 msg
->rep_type
= TIPC_TLV_ULTRA_STRING
;
960 dump
.header
= tipc_nl_compat_name_table_dump_header
;
961 dump
.dumpit
= tipc_nl_name_table_dump
;
962 dump
.format
= tipc_nl_compat_name_table_dump
;
963 return tipc_nl_compat_dumpit(&dump
, msg
);
964 case TIPC_CMD_SHOW_PORTS
:
965 msg
->rep_size
= ULTRA_STRING_MAX_LEN
;
966 msg
->rep_type
= TIPC_TLV_ULTRA_STRING
;
967 dump
.dumpit
= tipc_nl_sk_dump
;
968 dump
.format
= tipc_nl_compat_sk_dump
;
969 return tipc_nl_compat_dumpit(&dump
, msg
);
970 case TIPC_CMD_GET_MEDIA_NAMES
:
971 msg
->rep_size
= MAX_MEDIA
* TLV_SPACE(TIPC_MAX_MEDIA_NAME
);
972 dump
.dumpit
= tipc_nl_media_dump
;
973 dump
.format
= tipc_nl_compat_media_dump
;
974 return tipc_nl_compat_dumpit(&dump
, msg
);
975 case TIPC_CMD_GET_NODES
:
976 msg
->rep_size
= ULTRA_STRING_MAX_LEN
;
977 dump
.dumpit
= tipc_nl_node_dump
;
978 dump
.format
= tipc_nl_compat_node_dump
;
979 return tipc_nl_compat_dumpit(&dump
, msg
);
980 case TIPC_CMD_SET_NODE_ADDR
:
981 msg
->req_type
= TIPC_TLV_NET_ADDR
;
982 doit
.doit
= tipc_nl_net_set
;
983 doit
.transcode
= tipc_nl_compat_net_set
;
984 return tipc_nl_compat_doit(&doit
, msg
);
985 case TIPC_CMD_SET_NETID
:
986 msg
->req_type
= TIPC_TLV_UNSIGNED
;
987 doit
.doit
= tipc_nl_net_set
;
988 doit
.transcode
= tipc_nl_compat_net_set
;
989 return tipc_nl_compat_doit(&doit
, msg
);
990 case TIPC_CMD_GET_NETID
:
991 msg
->rep_size
= sizeof(u32
);
992 dump
.dumpit
= tipc_nl_net_dump
;
993 dump
.format
= tipc_nl_compat_net_dump
;
994 return tipc_nl_compat_dumpit(&dump
, msg
);
995 case TIPC_CMD_SHOW_STATS
:
996 return tipc_cmd_show_stats_compat(msg
);
1002 static int tipc_nl_compat_recv(struct sk_buff
*skb
, struct genl_info
*info
)
1006 struct tipc_nl_compat_msg msg
;
1007 struct nlmsghdr
*req_nlh
;
1008 struct nlmsghdr
*rep_nlh
;
1009 struct tipc_genlmsghdr
*req_userhdr
= info
->userhdr
;
1010 struct net
*net
= genl_info_net(info
);
1012 memset(&msg
, 0, sizeof(msg
));
1014 req_nlh
= (struct nlmsghdr
*)skb
->data
;
1015 msg
.req
= nlmsg_data(req_nlh
) + GENL_HDRLEN
+ TIPC_GENL_HDRLEN
;
1016 msg
.cmd
= req_userhdr
->cmd
;
1017 msg
.dst_sk
= info
->dst_sk
;
1019 if ((msg
.cmd
& 0xC000) && (!netlink_net_capable(skb
, CAP_NET_ADMIN
))) {
1020 msg
.rep
= tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN
);
1025 len
= nlmsg_attrlen(req_nlh
, GENL_HDRLEN
+ TIPC_GENL_HDRLEN
);
1026 if (TLV_GET_LEN(msg
.req
) && !TLV_OK(msg
.req
, len
)) {
1027 msg
.rep
= tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED
);
1032 err
= tipc_nl_compat_handle(&msg
);
1033 if (err
== -EOPNOTSUPP
)
1034 msg
.rep
= tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED
);
1035 else if (err
== -EINVAL
)
1036 msg
.rep
= tipc_get_err_tlv(TIPC_CFG_TLV_ERROR
);
1041 len
= nlmsg_total_size(GENL_HDRLEN
+ TIPC_GENL_HDRLEN
);
1042 skb_push(msg
.rep
, len
);
1043 rep_nlh
= nlmsg_hdr(msg
.rep
);
1044 memcpy(rep_nlh
, info
->nlhdr
, len
);
1045 rep_nlh
->nlmsg_len
= msg
.rep
->len
;
1046 genlmsg_unicast(net
, msg
.rep
, NETLINK_CB(skb
).portid
);
1051 static struct genl_family tipc_genl_compat_family
= {
1052 .id
= GENL_ID_GENERATE
,
1053 .name
= TIPC_GENL_NAME
,
1054 .version
= TIPC_GENL_VERSION
,
1055 .hdrsize
= TIPC_GENL_HDRLEN
,
1060 static struct genl_ops tipc_genl_compat_ops
[] = {
1062 .cmd
= TIPC_GENL_CMD
,
1063 .doit
= tipc_nl_compat_recv
,
1067 int tipc_netlink_compat_start(void)
1071 res
= genl_register_family_with_ops(&tipc_genl_compat_family
,
1072 tipc_genl_compat_ops
);
1074 pr_err("Failed to register legacy compat interface\n");
1081 void tipc_netlink_compat_stop(void)
1083 genl_unregister_family(&tipc_genl_compat_family
);