2 * Routines for Common Unix Printing System (CUPS) Browsing Protocol
3 * packet disassembly for the Wireshark network traffic analyzer.
5 * Charles Levert <charles@comm.polymtl.ca>
6 * Copyright 2001 Charles Levert
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <epan/packet.h>
33 /**********************************************************************/
35 void proto_register_cups(void);
36 void proto_reg_handoff_cups(void);
38 /* From cups/cups.h, GNU GPL, Copyright 1997-2001 by Easy Software Products. */
39 typedef guint32 cups_ptype_t
; /**** Printer Type/Capability Bits ****/
40 enum /* Not a typedef'd enum so we can OR */
42 CUPS_PRINTER_LOCAL
= 0x0000, /* Local printer or class */
43 CUPS_PRINTER_CLASS
= 0x0001, /* Printer class */
44 CUPS_PRINTER_REMOTE
= 0x0002, /* Remote printer or class */
45 CUPS_PRINTER_BW
= 0x0004, /* Can do B&W printing */
46 CUPS_PRINTER_COLOR
= 0x0008, /* Can do color printing */
47 CUPS_PRINTER_DUPLEX
= 0x0010, /* Can do duplexing */
48 CUPS_PRINTER_STAPLE
= 0x0020, /* Can staple output */
49 CUPS_PRINTER_COPIES
= 0x0040, /* Can do copies */
50 CUPS_PRINTER_COLLATE
= 0x0080, /* Can collage copies */
51 CUPS_PRINTER_PUNCH
= 0x0100, /* Can punch output */
52 CUPS_PRINTER_COVER
= 0x0200, /* Can cover output */
53 CUPS_PRINTER_BIND
= 0x0400, /* Can bind output */
54 CUPS_PRINTER_SORT
= 0x0800, /* Can sort output */
55 CUPS_PRINTER_SMALL
= 0x1000, /* Can do Letter/Legal/A4 */
56 CUPS_PRINTER_MEDIUM
= 0x2000, /* Can do Tabloid/B/C/A3/A2 */
57 CUPS_PRINTER_LARGE
= 0x4000, /* Can do D/E/A1/A0 */
58 CUPS_PRINTER_VARIABLE
= 0x8000, /* Can do variable sizes */
59 CUPS_PRINTER_IMPLICIT
= 0x10000, /* Implicit class */
60 CUPS_PRINTER_DEFAULT
= 0x20000, /* Default printer on network */
61 CUPS_PRINTER_OPTIONS
= 0xfffc /* ~(CLASS | REMOTE | IMPLICIT) */
63 /* End insert from cups/cups.h */
65 typedef enum _cups_state
{
71 static const value_string cups_state_values
[] = {
72 { CUPS_IDLE
, "idle" },
73 { CUPS_PROCESSING
, "processing" },
74 { CUPS_STOPPED
, "stopped" },
78 static const true_false_string tfs_implicit_explicit
= { "Implicit class", "Explicit class" };
79 static const true_false_string tfs_printer_class
= { "Printer class", "Single printer" };
81 static int proto_cups
= -1;
82 static int hf_cups_ptype
= -1;
83 static int hf_cups_ptype_default
= -1;
84 static int hf_cups_ptype_implicit
= -1;
85 static int hf_cups_ptype_variable
= -1;
86 static int hf_cups_ptype_large
= -1;
87 static int hf_cups_ptype_medium
= -1;
88 static int hf_cups_ptype_small
= -1;
89 static int hf_cups_ptype_sort
= -1;
90 static int hf_cups_ptype_bind
= -1;
91 static int hf_cups_ptype_cover
= -1;
92 static int hf_cups_ptype_punch
= -1;
93 static int hf_cups_ptype_collate
= -1;
94 static int hf_cups_ptype_copies
= -1;
95 static int hf_cups_ptype_staple
= -1;
96 static int hf_cups_ptype_duplex
= -1;
97 static int hf_cups_ptype_color
= -1;
98 static int hf_cups_ptype_bw
= -1;
99 static int hf_cups_ptype_remote
= -1;
100 static int hf_cups_ptype_class
= -1;
101 static int hf_cups_state
= -1;
103 static gint ett_cups
= -1;
104 static gint ett_cups_ptype
= -1;
106 /* This protocol is heavily related to IPP, but it is CUPS-specific
108 #define UDP_PORT_CUPS 631
109 #define PROTO_TAG_CUPS "CUPS"
111 static guint
get_hex_uint(tvbuff_t
*tvb
, gint offset
, gint
*next_offset
);
112 static gboolean
skip_space(tvbuff_t
*tvb
, gint offset
, gint
*next_offset
);
113 static const guint8
* get_quoted_string(tvbuff_t
*tvb
, gint offset
,
114 gint
*next_offset
, guint
*len
);
115 static const guint8
* get_unquoted_string(tvbuff_t
*tvb
, gint offset
,
116 gint
*next_offset
, guint
*len
);
118 /**********************************************************************/
121 dissect_cups(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
123 proto_tree
*cups_tree
= NULL
;
124 proto_tree
*ptype_subtree
= NULL
;
125 proto_item
*ti
= NULL
;
133 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_TAG_CUPS
);
134 col_clear(pinfo
->cinfo
, COL_INFO
);
136 ti
= proto_tree_add_item(tree
, proto_cups
, tvb
, offset
, -1, ENC_NA
);
137 cups_tree
= proto_item_add_subtree(ti
, ett_cups
);
139 /* Format (1450 bytes max.): */
140 /* type state uri ["location" ["info" ["make-and-model"]]]\n */
142 ptype
= get_hex_uint(tvb
, offset
, &next_offset
);
143 len
= next_offset
- offset
;
145 ti
= proto_tree_add_uint(cups_tree
, hf_cups_ptype
, tvb
, offset
, len
, ptype
);
146 ptype_subtree
= proto_item_add_subtree(ti
, ett_cups_ptype
);
147 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_default
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
148 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_implicit
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
149 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_variable
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
150 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_large
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
151 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_medium
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
152 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_small
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
153 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_sort
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
154 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_bind
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
155 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_cover
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
156 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_punch
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
157 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_collate
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
158 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_copies
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
159 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_staple
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
160 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_duplex
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
161 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_color
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
162 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_bw
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
163 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_remote
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
164 proto_tree_add_item(ptype_subtree
, hf_cups_ptype_class
, tvb
, offset
, len
, ENC_BIG_ENDIAN
);
166 offset
= next_offset
;
168 if (!skip_space(tvb
, offset
, &next_offset
))
169 return; /* end of packet */
170 offset
= next_offset
;
172 state
= get_hex_uint(tvb
, offset
, &next_offset
);
173 len
= next_offset
- offset
;
175 proto_tree_add_uint(cups_tree
, hf_cups_state
, tvb
, offset
, len
, state
);
177 offset
= next_offset
;
179 if (!skip_space(tvb
, offset
, &next_offset
))
180 return; /* end of packet */
181 offset
= next_offset
;
183 str
= get_unquoted_string(tvb
, offset
, &next_offset
, &len
);
185 return; /* separator/terminator not found */
187 proto_tree_add_text(cups_tree
, tvb
, offset
, len
,
188 "URI: %.*s", (guint16
) len
, str
);
189 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%.*s (%s)",
190 (guint16
) len
, str
, val_to_str(state
, cups_state_values
, "0x%x"));
191 offset
= next_offset
;
196 if (!skip_space(tvb
, offset
, &next_offset
))
197 return; /* end of packet */
198 offset
= next_offset
;
200 str
= get_quoted_string(tvb
, offset
, &next_offset
, &len
);
202 return; /* separator/terminator not found */
203 proto_tree_add_text(cups_tree
, tvb
, offset
+1, len
,
204 "Location: \"%.*s\"", (guint16
) len
, str
);
205 offset
= next_offset
;
207 if (!skip_space(tvb
, offset
, &next_offset
))
208 return; /* end of packet */
209 offset
= next_offset
;
211 str
= get_quoted_string(tvb
, offset
, &next_offset
, &len
);
213 return; /* separator/terminator not found */
214 proto_tree_add_text(cups_tree
, tvb
, offset
+1, len
,
215 "Information: \"%.*s\"", (guint16
) len
, str
);
216 offset
= next_offset
;
218 if (!skip_space(tvb
, offset
, &next_offset
))
219 return; /* end of packet */
220 offset
= next_offset
;
222 str
= get_quoted_string(tvb
, offset
, &next_offset
, &len
);
224 return; /* separator/terminator not found */
225 proto_tree_add_text(cups_tree
, tvb
, offset
+1, len
,
226 "Make and model: \"%.*s\"", (guint16
) len
, str
);
230 get_hex_uint(tvbuff_t
*tvb
, gint offset
, gint
*next_offset
)
235 while (isxdigit(c
= tvb_get_guint8(tvb
, offset
))) {
243 c
= 0; /* This should not happen. */
250 *next_offset
= offset
;
256 skip_space(tvbuff_t
*tvb
, gint offset
, gint
*next_offset
)
260 while ((c
= tvb_get_guint8(tvb
, offset
)) == ' ')
262 if (c
== '\r' || c
== '\n')
263 return FALSE
; /* end of packet */
265 *next_offset
= offset
;
271 get_quoted_string(tvbuff_t
*tvb
, gint offset
, gint
*next_offset
, guint
*len
)
274 const guint8
* s
= NULL
;
278 c
= tvb_get_guint8(tvb
, offset
);
280 o
= tvb_find_guint8(tvb
, offset
+1, -1, '"');
284 s
= tvb_get_ptr(tvb
, offset
, l
);
289 *next_offset
= offset
;
296 get_unquoted_string(tvbuff_t
*tvb
, gint offset
, gint
*next_offset
, guint
*len
)
298 const guint8
* s
= NULL
;
302 o
= tvb_pbrk_guint8(tvb
, offset
, -1, " \t\r\n", NULL
);
305 s
= tvb_get_ptr(tvb
, offset
, l
);
309 *next_offset
= offset
;
315 /**********************************************************************/
318 proto_register_cups(void)
320 static hf_register_info hf
[] = {
322 { "Type", "cups.ptype", FT_UINT32
, BASE_HEX
,
323 NULL
, 0x0, NULL
, HFILL
}},
324 { &hf_cups_ptype_default
,
325 { "Default printer on network", "cups.ptype.default", FT_BOOLEAN
, 32,
326 TFS(&tfs_yes_no
), CUPS_PRINTER_DEFAULT
, NULL
, HFILL
}},
327 { &hf_cups_ptype_implicit
,
328 { "Class", "cups.ptype.implicit", FT_BOOLEAN
, 32,
329 TFS(&tfs_implicit_explicit
), CUPS_PRINTER_IMPLICIT
, NULL
, HFILL
}},
330 { &hf_cups_ptype_variable
,
331 { "Can print variable sizes", "cups.ptype.variable", FT_BOOLEAN
, 32,
332 TFS(&tfs_yes_no
), CUPS_PRINTER_VARIABLE
, NULL
, HFILL
}},
333 { &hf_cups_ptype_large
,
334 { "Can print up to 36x48 inches", "cups.ptype.large", FT_BOOLEAN
, 32,
335 TFS(&tfs_yes_no
), CUPS_PRINTER_LARGE
, NULL
, HFILL
}},
336 { &hf_cups_ptype_medium
,
337 { "Can print up to 18x24 inches", "cups.ptype.medium", FT_BOOLEAN
, 32,
338 TFS(&tfs_yes_no
), CUPS_PRINTER_MEDIUM
, NULL
, HFILL
}},
339 { &hf_cups_ptype_small
,
340 { "Can print up to 9x14 inches", "cups.ptype.small", FT_BOOLEAN
, 32,
341 TFS(&tfs_yes_no
), CUPS_PRINTER_SMALL
, NULL
, HFILL
}},
342 { &hf_cups_ptype_sort
,
343 { "Can sort", "cups.ptype.sort", FT_BOOLEAN
, 32,
344 TFS(&tfs_yes_no
), CUPS_PRINTER_SORT
, NULL
, HFILL
}},
345 { &hf_cups_ptype_bind
,
346 { "Can bind", "cups.ptype.bind", FT_BOOLEAN
, 32,
347 TFS(&tfs_yes_no
), CUPS_PRINTER_BIND
, NULL
, HFILL
}},
348 { &hf_cups_ptype_cover
,
349 { "Can cover", "cups.ptype.cover", FT_BOOLEAN
, 32,
350 TFS(&tfs_yes_no
), CUPS_PRINTER_COVER
, NULL
, HFILL
}},
351 { &hf_cups_ptype_punch
,
352 { "Can punch holes", "cups.ptype.punch", FT_BOOLEAN
, 32,
353 TFS(&tfs_yes_no
), CUPS_PRINTER_PUNCH
, NULL
, HFILL
}},
354 { &hf_cups_ptype_collate
,
355 { "Can do fast collating", "cups.ptype.collate", FT_BOOLEAN
, 32,
356 TFS(&tfs_yes_no
), CUPS_PRINTER_COLLATE
, NULL
, HFILL
}},
357 { &hf_cups_ptype_copies
,
358 { "Can do fast copies", "cups.ptype.copies", FT_BOOLEAN
, 32,
359 TFS(&tfs_yes_no
), CUPS_PRINTER_COPIES
, NULL
, HFILL
}},
360 { &hf_cups_ptype_staple
,
361 { "Can staple", "cups.ptype.staple", FT_BOOLEAN
, 32,
362 TFS(&tfs_yes_no
), CUPS_PRINTER_STAPLE
, NULL
, HFILL
}},
363 { &hf_cups_ptype_duplex
,
364 { "Can duplex", "cups.ptype.duplex", FT_BOOLEAN
, 32,
365 TFS(&tfs_yes_no
), CUPS_PRINTER_DUPLEX
, NULL
, HFILL
}},
366 { &hf_cups_ptype_color
,
367 { "Can print color", "cups.ptype.color", FT_BOOLEAN
, 32,
368 TFS(&tfs_yes_no
), CUPS_PRINTER_COLOR
, NULL
, HFILL
}},
370 { "Can print black", "cups.ptype.bw", FT_BOOLEAN
, 32,
371 TFS(&tfs_yes_no
), CUPS_PRINTER_BW
, NULL
, HFILL
}},
372 { &hf_cups_ptype_remote
,
373 { "Remote", "cups.ptype.remote", FT_BOOLEAN
, 32,
374 TFS(&tfs_yes_no
), CUPS_PRINTER_REMOTE
, NULL
, HFILL
}},
375 { &hf_cups_ptype_class
,
376 { "Class", "cups.ptype.class", FT_BOOLEAN
, 32,
377 TFS(&tfs_printer_class
), CUPS_PRINTER_CLASS
, NULL
, HFILL
}},
379 { "State", "cups.state", FT_UINT8
, BASE_HEX
,
380 VALS(cups_state_values
), 0x0, NULL
, HFILL
}}
383 static gint
*ett
[] = {
388 proto_cups
= proto_register_protocol(
389 "Common Unix Printing System (CUPS) Browsing Protocol",
391 proto_register_field_array(proto_cups
, hf
, array_length(hf
));
392 proto_register_subtree_array(ett
, array_length(ett
));
396 proto_reg_handoff_cups(void)
398 dissector_handle_t cups_handle
;
400 cups_handle
= create_dissector_handle(dissect_cups
, proto_cups
);
401 dissector_add_uint("udp.port", UDP_PORT_CUPS
, cups_handle
);
405 * Editor modelines - http://www.wireshark.org/tools/modelines.html
410 * indent-tabs-mode: nil
413 * vi: set shiftwidth=4 tabstop=8 expandtab:
414 * :indentSize=4:tabSize=8:noTabs=true: