Use "tvb_get_ntohieee_float()" to fetch floating-point numbers.
[obnox/wireshark/wip.git] / packet-who.c
1 /* packet-who.c
2  * Routines for who protocol (see man rwhod)
3  * Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * $Id: packet-who.c,v 1.23 2002/01/24 09:20:52 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <string.h>
35 #include <time.h>
36 #include <glib.h>
37 #include <epan/packet.h>
38
39
40 /*
41  *
42 RWHOD(8)                 UNIX System Manager's Manual                 RWHOD(8)
43
44
45      The messages sent and received, are of the form:
46
47            struct  outmp {
48 0                   char    out_line[8];             tty name 
49 8                   char    out_name[8];             user id 
50 16                   long    out_time;               time on 
51            };
52
53            struct  whod {
54  0                   char    wd_vers;
55  1                   char    wd_type;
56  2                   char    wd_fill[2];
57  4                   int     wd_sendtime;
58  8                   int     wd_recvtime;
59 12                   char    wd_hostname[32];
60 44                   int     wd_loadav[3];
61 56                   int     wd_boottime;
62 60                   struct  whoent {
63                            struct  outmp we_utmp;
64 (20 each)                  int     we_idle;
65                    } wd_we[1024 / sizeof (struct whoent)];
66            };
67
68  Linux 2.0                       May 13, 1997                                2
69
70  *
71  */
72
73 static int proto_who = -1;
74 static int hf_who_vers = -1;
75 static int hf_who_type = -1;
76 static int hf_who_sendtime = -1;
77 static int hf_who_recvtime = -1;
78 static int hf_who_hostname = -1;
79 static int hf_who_loadav_5 = -1;
80 static int hf_who_loadav_10 = -1;
81 static int hf_who_loadav_15 = -1;
82 static int hf_who_boottime = -1;
83 static int hf_who_whoent = -1;
84 static int hf_who_tty = -1;
85 static int hf_who_uid = -1;
86 static int hf_who_timeon = -1;
87 static int hf_who_idle = -1;
88
89 static gint ett_who = -1;
90 static gint ett_whoent = -1;
91
92 #define UDP_PORT_WHO    513
93
94 static void dissect_whoent(tvbuff_t *tvb, int offset, proto_tree *tree);
95
96 static void
97 dissect_who(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
98 {
99         int             offset = 0;
100         proto_tree      *who_tree = NULL;
101         proto_item      *who_ti = NULL;
102         gchar           server_name[33];
103         double          loadav_5 = 0.0, loadav_10 = 0.0, loadav_15 = 0.0;
104         nstime_t        ts;
105
106         /* Summary information */
107         if (check_col(pinfo->cinfo, COL_PROTOCOL))
108                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WHO");
109         if (check_col(pinfo->cinfo, COL_INFO))
110                 col_clear(pinfo->cinfo, COL_INFO);
111
112         ts.nsecs = 0;
113
114         if (tree) {
115                 who_ti = proto_tree_add_item(tree, proto_who, tvb, offset, -1,
116                     FALSE);
117                 who_tree = proto_item_add_subtree(who_ti, ett_who);
118         }
119
120         if (tree)
121                 proto_tree_add_item(who_tree, hf_who_vers, tvb, offset, 1, FALSE);
122         offset += 1;
123
124         if (tree)
125                 proto_tree_add_item(who_tree, hf_who_type, tvb, offset, 1, FALSE);
126         offset += 1;
127
128         /* 2 filler bytes */
129         offset += 2;
130
131         if (tree) {
132                 ts.secs = tvb_get_ntohl(tvb, offset);
133                 proto_tree_add_time(who_tree, hf_who_sendtime, tvb, offset, 4,
134                     &ts);
135         }
136         offset += 4;
137
138         if (tree) {
139                 ts.secs = tvb_get_ntohl(tvb, offset);
140                 proto_tree_add_time(who_tree, hf_who_recvtime, tvb, offset, 4,
141                     &ts);
142         }
143         offset += 4;
144
145         tvb_get_nstringz0(tvb, offset, 32, server_name);
146         if (tree)
147                 proto_tree_add_string(who_tree, hf_who_hostname, tvb, offset,
148                     32, server_name);
149         offset += 32;
150
151         loadav_5  = (double) tvb_get_ntohl(tvb, offset) / 100.0;
152         if (tree)
153                 proto_tree_add_double(who_tree, hf_who_loadav_5, tvb, offset,
154                     4, loadav_5);
155         offset += 4;
156
157         loadav_10 = (double) tvb_get_ntohl(tvb, offset) / 100.0;
158         if (tree)
159                 proto_tree_add_double(who_tree, hf_who_loadav_10, tvb, offset,
160                     4, loadav_10);
161         offset += 4;
162
163         loadav_15 = (double) tvb_get_ntohl(tvb, offset) / 100.0;
164         if (tree)
165                 proto_tree_add_double(who_tree, hf_who_loadav_15, tvb, offset,
166                     4, loadav_15);
167         offset += 4;
168
169         /* Summary information */
170         if (check_col(pinfo->cinfo, COL_INFO))
171                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %.02f %.02f %.02f",
172                                 server_name, loadav_5, loadav_10, loadav_15);
173
174         if (tree) {
175                 ts.secs = tvb_get_ntohl(tvb, offset);
176                 proto_tree_add_time(who_tree, hf_who_boottime, tvb, offset, 4,
177                     &ts);
178                 offset += 4;
179
180                 dissect_whoent(tvb, offset, who_tree);
181         }
182 }
183
184 /* The man page says that (1024 / sizeof(struct whoent)) is the maximum number
185  * of whoent structures in the packet. */
186 #define SIZE_OF_WHOENT  24
187 #define MAX_NUM_WHOENTS (1024 / SIZE_OF_WHOENT)
188
189 static void
190 dissect_whoent(tvbuff_t *tvb, int offset, proto_tree *tree)
191 {
192         proto_tree      *whoent_tree = NULL;
193         proto_item      *whoent_ti = NULL;
194         int             line_offset = offset;
195         gchar           out_line[9];    
196         gchar           out_name[9];    
197         nstime_t        ts;
198         int             whoent_num = 0;
199         guint32         idle_secs; /* say that out loud... */
200
201         ts.nsecs = 0;
202
203         while (tvb_reported_length_remaining(tvb, line_offset) > 0
204             && whoent_num < MAX_NUM_WHOENTS) {
205                 whoent_ti = proto_tree_add_item(tree, hf_who_whoent, tvb,
206                     line_offset, SIZE_OF_WHOENT, FALSE);
207                 whoent_tree = proto_item_add_subtree(whoent_ti, ett_whoent);
208
209                 tvb_get_nstringz0(tvb, line_offset, 8, out_line);
210                 proto_tree_add_string(whoent_tree, hf_who_tty, tvb, line_offset,
211                     8, out_line);
212                 line_offset += 8;
213
214                 tvb_get_nstringz0(tvb, line_offset, 8, out_name);
215                 proto_tree_add_string(whoent_tree, hf_who_uid, tvb, line_offset,
216                     8, out_name);
217                 line_offset += 8;
218
219                 ts.secs = tvb_get_ntohl(tvb, line_offset);
220                 proto_tree_add_time(whoent_tree, hf_who_timeon, tvb,
221                     line_offset, 4, &ts);
222                 line_offset += 4;
223
224                 idle_secs = tvb_get_ntohl(tvb, line_offset);
225                 proto_tree_add_uint_format(whoent_tree, hf_who_idle, tvb,
226                     line_offset, 4, idle_secs, "Idle: %s",
227                     time_secs_to_str(idle_secs));
228                 line_offset += 4;
229
230                 whoent_num++;
231         }
232 }
233
234 void
235 proto_register_who(void)
236 {
237         static hf_register_info hf[] = {
238                 { &hf_who_vers,
239                 { "Version",    "who.vers", FT_UINT8, BASE_DEC, NULL, 0x0,
240                         "", HFILL }},
241
242                 { &hf_who_type,
243                 { "Type",       "who.type", FT_UINT8, BASE_DEC, NULL, 0x0,
244                         "", HFILL }},
245
246                 { &hf_who_sendtime,
247                 { "Send Time",  "who.sendtime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
248                         "", HFILL }},
249
250                 { &hf_who_recvtime,
251                 { "Receive Time", "who.recvtime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
252                         "", HFILL }},
253
254                 { &hf_who_hostname,
255                 { "Hostname", "who.hostname", FT_STRING, BASE_NONE, NULL, 0x0,
256                         "", HFILL }},
257
258                 { &hf_who_loadav_5,
259                 { "Load Average Over Past  5 Minutes", "who.loadav_5", FT_DOUBLE, BASE_NONE, NULL, 0x0,
260                         "", HFILL }},
261
262                 { &hf_who_loadav_10,
263                 { "Load Average Over Past 10 Minutes", "who.loadav_10", FT_DOUBLE, BASE_NONE, NULL, 0x0,
264                         "", HFILL }},
265
266                 { &hf_who_loadav_15,
267                 { "Load Average Over Past 15 Minutes", "who.loadav_15", FT_DOUBLE, BASE_NONE, NULL, 0x0,
268                         "", HFILL }},
269
270                 { &hf_who_boottime,
271                 { "Boot Time", "who.boottime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
272                         "", HFILL }},
273
274                 { &hf_who_whoent,
275                 { "Who utmp Entry", "who.whoent", FT_NONE, BASE_NONE, NULL, 0x0,
276                         "", HFILL }},
277
278                 { &hf_who_tty,
279                 { "TTY Name", "who.tty", FT_STRING, BASE_NONE, NULL, 0x0,
280                         "", HFILL }},
281
282                 { &hf_who_uid,
283                 { "User ID", "who.uid", FT_STRING, BASE_NONE, NULL, 0x0,
284                         "", HFILL }},
285
286                 { &hf_who_timeon,
287                 { "Time On", "who.timeon", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
288                         "", HFILL }},
289
290                 { &hf_who_idle,
291                 { "Time Idle", "who.idle", FT_UINT32, BASE_DEC, NULL, 0x0,
292                         "", HFILL }},
293         };
294
295         static gint *ett[] = {
296                 &ett_who,
297                 &ett_whoent,
298         };
299
300         proto_who = proto_register_protocol("Who", "WHO", "who");
301         proto_register_field_array(proto_who, hf, array_length(hf));
302         proto_register_subtree_array(ett, array_length(ett));
303 }
304
305 void
306 proto_reg_handoff_who(void)
307 {
308         dissector_handle_t who_handle;
309
310         who_handle = create_dissector_handle(dissect_who, proto_who);
311         dissector_add("udp.port", UDP_PORT_WHO, who_handle);
312 }