msg.c revision 7945c1fb02ef08316df8c054ce180bf3f4e35ae4
1/*
2 * net/tipc/msg.c: TIPC message header routines
3 *
4 * Copyright (c) 2000-2006, Ericsson AB
5 * Copyright (c) 2005, 2010-2011, Wind River Systems
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 *    contributors may be used to endorse or promote products derived from
18 *    this software without specific prior written permission.
19 *
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "msg.h"
39
40u32 tipc_msg_tot_importance(struct tipc_msg *m)
41{
42	if (likely(msg_isdata(m))) {
43		if (likely(msg_orignode(m) == tipc_own_addr))
44			return msg_importance(m);
45		return msg_importance(m) + 4;
46	}
47	if ((msg_user(m) == MSG_FRAGMENTER)  &&
48	    (msg_type(m) == FIRST_FRAGMENT))
49		return msg_importance(msg_get_wrapped(m));
50	return msg_importance(m);
51}
52
53
54void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type,
55			    u32 hsize, u32 destnode)
56{
57	memset(m, 0, hsize);
58	msg_set_version(m);
59	msg_set_user(m, user);
60	msg_set_hdr_sz(m, hsize);
61	msg_set_size(m, hsize);
62	msg_set_prevnode(m, tipc_own_addr);
63	msg_set_type(m, type);
64	if (!msg_short(m)) {
65		msg_set_orignode(m, tipc_own_addr);
66		msg_set_destnode(m, destnode);
67	}
68}
69
70/**
71 * tipc_msg_calc_data_size - determine total data size for message
72 */
73
74int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect)
75{
76	int dsz = 0;
77	int i;
78
79	for (i = 0; i < num_sect; i++)
80		dsz += msg_sect[i].iov_len;
81	return dsz;
82}
83
84/**
85 * tipc_msg_build - create message using specified header and data
86 *
87 * Note: Caller must not hold any locks in case copy_from_user() is interrupted!
88 *
89 * Returns message data size or errno
90 */
91
92int tipc_msg_build(struct tipc_msg *hdr,
93			    struct iovec const *msg_sect, u32 num_sect,
94			    int max_size, int usrmem, struct sk_buff **buf)
95{
96	int dsz, sz, hsz, pos, res, cnt;
97
98	dsz = tipc_msg_calc_data_size(msg_sect, num_sect);
99	if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) {
100		*buf = NULL;
101		return -EINVAL;
102	}
103
104	pos = hsz = msg_hdr_sz(hdr);
105	sz = hsz + dsz;
106	msg_set_size(hdr, sz);
107	if (unlikely(sz > max_size)) {
108		*buf = NULL;
109		return dsz;
110	}
111
112	*buf = tipc_buf_acquire(sz);
113	if (!(*buf))
114		return -ENOMEM;
115	skb_copy_to_linear_data(*buf, hdr, hsz);
116	for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
117		if (likely(usrmem))
118			res = !copy_from_user((*buf)->data + pos,
119					      msg_sect[cnt].iov_base,
120					      msg_sect[cnt].iov_len);
121		else
122			skb_copy_to_linear_data_offset(*buf, pos,
123						       msg_sect[cnt].iov_base,
124						       msg_sect[cnt].iov_len);
125		pos += msg_sect[cnt].iov_len;
126	}
127	if (likely(res))
128		return dsz;
129
130	buf_discard(*buf);
131	*buf = NULL;
132	return -EFAULT;
133}
134
135#ifdef CONFIG_TIPC_DEBUG
136
137void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str)
138{
139	u32 usr = msg_user(msg);
140	tipc_printf(buf, KERN_DEBUG);
141	tipc_printf(buf, str);
142
143	switch (usr) {
144	case MSG_BUNDLER:
145		tipc_printf(buf, "BNDL::");
146		tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg));
147		break;
148	case BCAST_PROTOCOL:
149		tipc_printf(buf, "BCASTP::");
150		break;
151	case MSG_FRAGMENTER:
152		tipc_printf(buf, "FRAGM::");
153		switch (msg_type(msg)) {
154		case FIRST_FRAGMENT:
155			tipc_printf(buf, "FIRST:");
156			break;
157		case FRAGMENT:
158			tipc_printf(buf, "BODY:");
159			break;
160		case LAST_FRAGMENT:
161			tipc_printf(buf, "LAST:");
162			break;
163		default:
164			tipc_printf(buf, "UNKNOWN:%x", msg_type(msg));
165
166		}
167		tipc_printf(buf, "NO(%u/%u):", msg_long_msgno(msg),
168			    msg_fragm_no(msg));
169		break;
170	case TIPC_LOW_IMPORTANCE:
171	case TIPC_MEDIUM_IMPORTANCE:
172	case TIPC_HIGH_IMPORTANCE:
173	case TIPC_CRITICAL_IMPORTANCE:
174		tipc_printf(buf, "DAT%u:", msg_user(msg));
175		if (msg_short(msg)) {
176			tipc_printf(buf, "CON:");
177			break;
178		}
179		switch (msg_type(msg)) {
180		case TIPC_CONN_MSG:
181			tipc_printf(buf, "CON:");
182			break;
183		case TIPC_MCAST_MSG:
184			tipc_printf(buf, "MCST:");
185			break;
186		case TIPC_NAMED_MSG:
187			tipc_printf(buf, "NAM:");
188			break;
189		case TIPC_DIRECT_MSG:
190			tipc_printf(buf, "DIR:");
191			break;
192		default:
193			tipc_printf(buf, "UNKNOWN TYPE %u", msg_type(msg));
194		}
195		if (msg_routed(msg) && !msg_non_seq(msg))
196			tipc_printf(buf, "ROUT:");
197		if (msg_reroute_cnt(msg))
198			tipc_printf(buf, "REROUTED(%u):",
199				    msg_reroute_cnt(msg));
200		break;
201	case NAME_DISTRIBUTOR:
202		tipc_printf(buf, "NMD::");
203		switch (msg_type(msg)) {
204		case PUBLICATION:
205			tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20);	/* Items */
206			break;
207		case WITHDRAWAL:
208			tipc_printf(buf, "WDRW:");
209			break;
210		default:
211			tipc_printf(buf, "UNKNOWN:%x", msg_type(msg));
212		}
213		if (msg_routed(msg))
214			tipc_printf(buf, "ROUT:");
215		if (msg_reroute_cnt(msg))
216			tipc_printf(buf, "REROUTED(%u):",
217				    msg_reroute_cnt(msg));
218		break;
219	case CONN_MANAGER:
220		tipc_printf(buf, "CONN_MNG:");
221		switch (msg_type(msg)) {
222		case CONN_PROBE:
223			tipc_printf(buf, "PROBE:");
224			break;
225		case CONN_PROBE_REPLY:
226			tipc_printf(buf, "PROBE_REPLY:");
227			break;
228		case CONN_ACK:
229			tipc_printf(buf, "CONN_ACK:");
230			tipc_printf(buf, "ACK(%u):", msg_msgcnt(msg));
231			break;
232		default:
233			tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg));
234		}
235		if (msg_routed(msg))
236			tipc_printf(buf, "ROUT:");
237		if (msg_reroute_cnt(msg))
238			tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg));
239		break;
240	case LINK_PROTOCOL:
241		switch (msg_type(msg)) {
242		case STATE_MSG:
243			tipc_printf(buf, "STATE:");
244			tipc_printf(buf, "%s:", msg_probe(msg) ? "PRB" : "");
245			tipc_printf(buf, "NXS(%u):", msg_next_sent(msg));
246			tipc_printf(buf, "GAP(%u):", msg_seq_gap(msg));
247			tipc_printf(buf, "LSTBC(%u):", msg_last_bcast(msg));
248			break;
249		case RESET_MSG:
250			tipc_printf(buf, "RESET:");
251			if (msg_size(msg) != msg_hdr_sz(msg))
252				tipc_printf(buf, "BEAR:%s:", msg_data(msg));
253			break;
254		case ACTIVATE_MSG:
255			tipc_printf(buf, "ACTIVATE:");
256			break;
257		default:
258			tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg));
259		}
260		tipc_printf(buf, "PLANE(%c):", msg_net_plane(msg));
261		tipc_printf(buf, "SESS(%u):", msg_session(msg));
262		break;
263	case CHANGEOVER_PROTOCOL:
264		tipc_printf(buf, "TUNL:");
265		switch (msg_type(msg)) {
266		case DUPLICATE_MSG:
267			tipc_printf(buf, "DUPL:");
268			break;
269		case ORIGINAL_MSG:
270			tipc_printf(buf, "ORIG:");
271			tipc_printf(buf, "EXP(%u)", msg_msgcnt(msg));
272			break;
273		default:
274			tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg));
275		}
276		break;
277	case LINK_CONFIG:
278		tipc_printf(buf, "CFG:");
279		switch (msg_type(msg)) {
280		case DSC_REQ_MSG:
281			tipc_printf(buf, "DSC_REQ:");
282			break;
283		case DSC_RESP_MSG:
284			tipc_printf(buf, "DSC_RESP:");
285			break;
286		default:
287			tipc_printf(buf, "UNKNOWN TYPE:%x:", msg_type(msg));
288			break;
289		}
290		break;
291	default:
292		tipc_printf(buf, "UNKNOWN USER:");
293	}
294
295	switch (usr) {
296	case CONN_MANAGER:
297	case TIPC_LOW_IMPORTANCE:
298	case TIPC_MEDIUM_IMPORTANCE:
299	case TIPC_HIGH_IMPORTANCE:
300	case TIPC_CRITICAL_IMPORTANCE:
301		switch (msg_errcode(msg)) {
302		case TIPC_OK:
303			break;
304		case TIPC_ERR_NO_NAME:
305			tipc_printf(buf, "NO_NAME:");
306			break;
307		case TIPC_ERR_NO_PORT:
308			tipc_printf(buf, "NO_PORT:");
309			break;
310		case TIPC_ERR_NO_NODE:
311			tipc_printf(buf, "NO_PROC:");
312			break;
313		case TIPC_ERR_OVERLOAD:
314			tipc_printf(buf, "OVERLOAD:");
315			break;
316		case TIPC_CONN_SHUTDOWN:
317			tipc_printf(buf, "SHUTDOWN:");
318			break;
319		default:
320			tipc_printf(buf, "UNKNOWN ERROR(%x):",
321				    msg_errcode(msg));
322		}
323	default:
324		break;
325	}
326
327	tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg));
328	tipc_printf(buf, "SZ(%u):", msg_size(msg));
329	tipc_printf(buf, "SQNO(%u):", msg_seqno(msg));
330
331	if (msg_non_seq(msg))
332		tipc_printf(buf, "NOSEQ:");
333	else
334		tipc_printf(buf, "ACK(%u):", msg_ack(msg));
335	tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg));
336	tipc_printf(buf, "PRND(%x)", msg_prevnode(msg));
337
338	if (msg_isdata(msg)) {
339		if (msg_named(msg)) {
340			tipc_printf(buf, "NTYP(%u):", msg_nametype(msg));
341			tipc_printf(buf, "NINST(%u)", msg_nameinst(msg));
342		}
343	}
344
345	if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) &&
346	    (usr != MSG_BUNDLER)) {
347		if (!msg_short(msg)) {
348			tipc_printf(buf, ":ORIG(%x:%u):",
349				    msg_orignode(msg), msg_origport(msg));
350			tipc_printf(buf, ":DEST(%x:%u):",
351				    msg_destnode(msg), msg_destport(msg));
352		} else {
353			tipc_printf(buf, ":OPRT(%u):", msg_origport(msg));
354			tipc_printf(buf, ":DPRT(%u):", msg_destport(msg));
355		}
356	}
357	if (msg_user(msg) == NAME_DISTRIBUTOR) {
358		tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg));
359		tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg));
360	}
361
362	if (msg_user(msg) ==  LINK_CONFIG) {
363		u32 *raw = (u32 *)msg;
364		struct tipc_media_addr *orig = (struct tipc_media_addr *)&raw[5];
365		tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg));
366		tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg));
367		tipc_media_addr_printf(buf, orig);
368	}
369	if (msg_user(msg) == BCAST_PROTOCOL) {
370		tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg));
371		tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg));
372	}
373	tipc_printf(buf, "\n");
374	if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg)))
375		tipc_msg_dbg(buf, msg_get_wrapped(msg), "      /");
376	if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT))
377		tipc_msg_dbg(buf, msg_get_wrapped(msg), "      /");
378}
379
380#endif
381