2 * Routines for Common Unix Printing System (CUPS) Browsing Protocol
3 * packet disassembly for the Ethereal network traffic analyzer.
5 * Charles Levert <charles@comm.polymtl.ca>
6 * Copyright 2001 Charles Levert
8 * $Id: packet-cups.c,v 1.10 2002/01/24 09:20:47 guy Exp $
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
38 #include <epan/packet.h>
39 #include <epan/strutil.h>
41 /**********************************************************************/
43 /* From cups/cups.h, GNU GPL, Copyright 1997-2001 by Easy Software Products. */
44 typedef guint32 cups_ptype_t; /**** Printer Type/Capability Bits ****/
45 enum /* Not a typedef'd enum so we can OR */
47 CUPS_PRINTER_LOCAL = 0x0000, /* Local printer or class */
48 CUPS_PRINTER_CLASS = 0x0001, /* Printer class */
49 CUPS_PRINTER_REMOTE = 0x0002, /* Remote printer or class */
50 CUPS_PRINTER_BW = 0x0004, /* Can do B&W printing */
51 CUPS_PRINTER_COLOR = 0x0008, /* Can do color printing */
52 CUPS_PRINTER_DUPLEX = 0x0010, /* Can do duplexing */
53 CUPS_PRINTER_STAPLE = 0x0020, /* Can staple output */
54 CUPS_PRINTER_COPIES = 0x0040, /* Can do copies */
55 CUPS_PRINTER_COLLATE = 0x0080, /* Can collage copies */
56 CUPS_PRINTER_PUNCH = 0x0100, /* Can punch output */
57 CUPS_PRINTER_COVER = 0x0200, /* Can cover output */
58 CUPS_PRINTER_BIND = 0x0400, /* Can bind output */
59 CUPS_PRINTER_SORT = 0x0800, /* Can sort output */
60 CUPS_PRINTER_SMALL = 0x1000, /* Can do Letter/Legal/A4 */
61 CUPS_PRINTER_MEDIUM = 0x2000, /* Can do Tabloid/B/C/A3/A2 */
62 CUPS_PRINTER_LARGE = 0x4000, /* Can do D/E/A1/A0 */
63 CUPS_PRINTER_VARIABLE = 0x8000, /* Can do variable sizes */
64 CUPS_PRINTER_IMPLICIT = 0x10000, /* Implicit class */
65 CUPS_PRINTER_DEFAULT = 0x20000, /* Default printer on network */
66 CUPS_PRINTER_OPTIONS = 0xfffc /* ~(CLASS | REMOTE | IMPLICIT) */
68 /* End insert from cups/cups.h */
74 } cups_ptype_bit_info;
76 static const cups_ptype_bit_info cups_ptype_bits[] = {
77 { CUPS_PRINTER_DEFAULT,
78 "Default printer on network", "Not default printer" },
79 { CUPS_PRINTER_IMPLICIT,
80 "Implicit class", "Explicit class" },
81 { CUPS_PRINTER_VARIABLE,
82 "Can print variable sizes", "Cannot print variable sizes" },
84 "Can print up to 36x48 inches", "Cannot print up to 36x48 inches" },
85 { CUPS_PRINTER_MEDIUM,
86 "Can print up to 18x24 inches", "Cannot print up to 18x24 inches" },
88 "Can print up to 9x14 inches", "Cannot print up to 9x14 inches" },
90 "Can sort", "Cannot sort" },
92 "Can bind", "Cannot bind" },
94 "Can cover", "Cannot cover" },
96 "Can punch holes", "Cannot punch holes" },
97 { CUPS_PRINTER_COLLATE,
98 "Can do fast collating", "Cannot do fast collating" },
99 { CUPS_PRINTER_COPIES,
100 "Can do fast copies", "Cannot do fast copies" },
101 { CUPS_PRINTER_STAPLE,
102 "Can staple", "Cannot staple" },
103 { CUPS_PRINTER_DUPLEX,
104 "Can duplex", "Cannot duplex" },
105 { CUPS_PRINTER_COLOR,
106 "Can print color", "Cannot print color" },
108 "Can print black", "Cannot print black" },
109 { CUPS_PRINTER_REMOTE,
110 "Remote", "Local (illegal)" },
111 { CUPS_PRINTER_CLASS,
112 "Printer class", "Single printer" }
115 #define N_CUPS_PTYPE_BITS (sizeof cups_ptype_bits / sizeof cups_ptype_bits[0])
117 typedef enum _cups_state {
123 static const value_string cups_state_values[] = {
124 { CUPS_IDLE, "idle" },
125 { CUPS_PROCESSING, "processing" },
126 { CUPS_STOPPED, "stopped" },
130 static int proto_cups = -1;
131 static int hf_cups_ptype = -1;
132 static int hf_cups_state = -1;
134 static gint ett_cups = -1;
135 static gint ett_cups_ptype = -1;
137 /* This protocol is heavily related to IPP, but it is CUPS-specific
139 #define UDP_PORT_CUPS 631
140 #define PROTO_TAG_CUPS "CUPS"
142 static guint get_hex_uint(tvbuff_t *tvb, gint offset,
144 static gboolean skip_space(tvbuff_t *tvb, gint offset,
146 static const guint8* get_quoted_string(tvbuff_t *tvb, gint offset,
147 gint *next_offset, guint *len);
148 static const guint8* get_unquoted_string(tvbuff_t *tvb, gint offset,
149 gint *next_offset, guint *len);
151 /**********************************************************************/
154 dissect_cups(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
156 proto_tree *cups_tree = 0;
157 proto_tree *ptype_subtree = 0;
167 if (check_col(pinfo->cinfo, COL_PROTOCOL))
168 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_CUPS);
169 if (check_col(pinfo->cinfo, COL_INFO))
170 col_clear(pinfo->cinfo, COL_INFO);
173 ti = proto_tree_add_item(tree, proto_cups, tvb, offset, -1,
175 cups_tree = proto_item_add_subtree(ti, ett_cups);
178 /* Format (1450 bytes max.): */
179 /* type state uri ["location" ["info" ["make-and-model"]]]\n */
181 ptype = get_hex_uint(tvb, offset, &next_offset);
182 len = next_offset - offset;
185 ti = proto_tree_add_uint(cups_tree, hf_cups_ptype,
186 tvb, offset, len, ptype);
187 ptype_subtree = proto_item_add_subtree(ti,
189 for (u = 0; u < N_CUPS_PTYPE_BITS; u++) {
190 proto_tree_add_text(ptype_subtree, tvb,
192 decode_boolean_bitfield(ptype,
193 cups_ptype_bits[u].bit, sizeof (ptype)*8,
194 cups_ptype_bits[u].on_string,
195 cups_ptype_bits[u].off_string));
199 offset = next_offset;
201 if (!skip_space(tvb, offset, &next_offset))
202 return; /* end of packet */
203 offset = next_offset;
205 state = get_hex_uint(tvb, offset, &next_offset);
206 len = next_offset - offset;
209 proto_tree_add_uint(cups_tree, hf_cups_state,
210 tvb, offset, len, state);
212 offset = next_offset;
214 if (!skip_space(tvb, offset, &next_offset))
215 return; /* end of packet */
216 offset = next_offset;
218 str = get_unquoted_string(tvb, offset, &next_offset, &len);
220 return; /* separator/terminator not found */
222 proto_tree_add_text(cups_tree, tvb, offset, len,
225 if (check_col(pinfo->cinfo, COL_INFO))
226 col_add_fstr(pinfo->cinfo, COL_INFO,
229 val_to_str(state, cups_state_values, "0x%x"));
230 offset = next_offset;
235 if (!skip_space(tvb, offset, &next_offset))
236 return; /* end of packet */
237 offset = next_offset;
239 str = get_quoted_string(tvb, offset, &next_offset, &len);
241 return; /* separator/terminator not found */
242 proto_tree_add_text(cups_tree, tvb, offset+1, len,
243 "Location: \"%.*s\"",
245 offset = next_offset;
247 if (!skip_space(tvb, offset, &next_offset))
248 return; /* end of packet */
249 offset = next_offset;
251 str = get_quoted_string(tvb, offset, &next_offset, &len);
253 return; /* separator/terminator not found */
254 proto_tree_add_text(cups_tree, tvb, offset+1, len,
255 "Information: \"%.*s\"",
257 offset = next_offset;
259 if (!skip_space(tvb, offset, &next_offset))
260 return; /* end of packet */
261 offset = next_offset;
263 str = get_quoted_string(tvb, offset, &next_offset, &len);
265 return; /* separator/terminator not found */
266 proto_tree_add_text(cups_tree, tvb, offset+1, len,
267 "Make and model: \"%.*s\"",
269 offset = next_offset;
275 get_hex_uint(tvbuff_t *tvb, gint offset, gint *next_offset)
280 while (isxdigit(c = tvb_get_guint8(tvb, offset))) {
288 c = 0; /* This should not happen. */
295 *next_offset = offset;
301 skip_space(tvbuff_t *tvb, gint offset, gint *next_offset)
305 while ((c = tvb_get_guint8(tvb, offset)) == ' ')
307 if (c == '\r' || c == '\n')
308 return FALSE; /* end of packet */
310 *next_offset = offset;
316 get_quoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len)
319 const guint8* s = NULL;
323 c = tvb_get_guint8(tvb, offset);
325 o = tvb_find_guint8(tvb, offset+1, -1, '"');
329 s = tvb_get_ptr(tvb, offset, l);
334 *next_offset = offset;
341 get_unquoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len)
343 const guint8* s = NULL;
347 o = tvb_pbrk_guint8(tvb, offset, -1, " \t\r\n");
350 s = tvb_get_ptr(tvb, offset, l);
354 *next_offset = offset;
360 /**********************************************************************/
363 proto_register_cups(void)
365 static hf_register_info hf[] = {
366 /* This one could be split in separate fields. */
368 { "Type", "cups.ptype", FT_UINT32, BASE_HEX,
369 NULL, 0x0, "", HFILL }},
372 { "State", "cups.state", FT_UINT8, BASE_HEX,
373 VALS(cups_state_values), 0x0, "", HFILL }}
376 static gint *ett[] = {
381 proto_cups = proto_register_protocol(
382 "Common Unix Printing System (CUPS) Browsing Protocol",
384 proto_register_field_array(proto_cups, hf, array_length(hf));
385 proto_register_subtree_array(ett, array_length(ett));
389 proto_reg_handoff_cups(void)
391 dissector_handle_t cups_handle;
393 cups_handle = create_dissector_handle(dissect_cups, proto_cups);
394 dissector_add("udp.port", UDP_PORT_CUPS, cups_handle);