2 * Routines for LPR and LPRng packet disassembly
3 * Gilbert Ramirez <gram@alumni.rice.edu>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
16 void proto_register_lpd(void);
17 void proto_reg_handoff_lpd(void);
19 static dissector_handle_t lpd_handle
;
21 #define TCP_PORT_PRINTER 515
24 static int hf_lpd_response
;
25 static int hf_lpd_request
;
26 static int hf_lpd_client_code
;
27 static int hf_lpd_printer_option
;
28 static int hf_lpd_response_code
;
32 enum lpr_type
{ request
, response
, unknown
};
34 static int find_printer_string(tvbuff_t
*tvb
, int offset
);
36 /* This information comes from the LPRng HOWTO, which also describes
37 RFC 1179. http://www.astart.com/lprng/LPRng-HOWTO.html */
38 static const value_string lpd_client_code
[] = {
39 { 1, "LPC: start print / jobcmd: abort" },
40 { 2, "LPR: transfer a printer job / jobcmd: receive control file" },
41 { 3, "LPQ: print short form of queue status / jobcmd: receive data file" },
42 { 4, "LPQ: print long form of queue status" },
43 { 5, "LPRM: remove jobs" },
44 { 6, "LPRng lpc: do control operation" },
45 { 7, "LPRng lpr: transfer a block format print job" },
46 { 8, "LPRng lpc: secure command transfer" },
47 { 9, "LPRng lpq: verbose status information" },
50 static const value_string lpd_server_code
[] = {
51 { 0, "Success: accepted, proceed" },
52 { 1, "Queue not accepting jobs" },
53 { 2, "Queue temporarily full, retry later" },
54 { 3, "Bad job format, do not retry" },
59 dissect_lpd(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
62 proto_item
*ti
, *hidden_item
;
63 enum lpr_type lpr_packet_type
;
67 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LPD");
68 col_clear(pinfo
->cinfo
, COL_INFO
);
70 /* rfc1179 states that all responses are 1 byte long */
71 code
= tvb_get_uint8(tvb
, 0);
72 if (tvb_reported_length(tvb
) == 1) {
73 lpr_packet_type
= response
;
76 lpr_packet_type
= request
;
79 lpr_packet_type
= unknown
;
82 if (lpr_packet_type
== request
&& code
!=0) {
83 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(code
, lpd_client_code
, "Unknown client code: %u"));
85 else if (lpr_packet_type
== response
) {
86 col_set_str(pinfo
->cinfo
, COL_INFO
, "LPD response");
89 col_set_str(pinfo
->cinfo
, COL_INFO
, "LPD continuation");
92 ti
= proto_tree_add_item(tree
, proto_lpd
, tvb
, 0, -1, ENC_NA
);
93 lpd_tree
= proto_item_add_subtree(ti
, ett_lpd
);
95 if (lpr_packet_type
== response
) {
96 hidden_item
= proto_tree_add_boolean(lpd_tree
, hf_lpd_response
,
99 hidden_item
= proto_tree_add_boolean(lpd_tree
, hf_lpd_request
,
102 proto_item_set_hidden(hidden_item
);
104 if (lpr_packet_type
== request
) {
105 printer_len
= find_printer_string(tvb
, 1);
107 if (code
<= 9 && printer_len
!= -1) {
108 proto_tree_add_uint_format(lpd_tree
, hf_lpd_client_code
, tvb
, 0, 1, code
,
109 "%s", val_to_str(code
, lpd_client_code
, "Unknown client code: %u"));
110 proto_tree_add_item(lpd_tree
, hf_lpd_printer_option
, tvb
, 1, printer_len
, ENC_ASCII
);
113 call_data_dissector(tvb
, pinfo
, lpd_tree
);
116 else if (lpr_packet_type
== response
) {
118 proto_tree_add_item(lpd_tree
, hf_lpd_response_code
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
121 call_data_dissector(tvb
, pinfo
, lpd_tree
);
125 call_data_dissector(tvb
, pinfo
, lpd_tree
);
128 return tvb_captured_length(tvb
);
133 find_printer_string(tvbuff_t
*tvb
, int offset
)
137 /* try to find end of string, either '\n' or '\0' */
138 i
= tvb_find_uint8(tvb
, offset
, -1, '\0');
140 i
= tvb_find_uint8(tvb
, offset
, -1, '\n');
143 return i
- offset
; /* length of string */
148 proto_register_lpd(void)
150 static hf_register_info hf
[] = {
152 { "Response", "lpd.response",
153 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
154 "true if LPD response", HFILL
}},
157 { "Request", "lpd.request",
158 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
159 "true if LPD request", HFILL
}},
161 { &hf_lpd_client_code
,
162 { "Client code", "lpd.client_code",
163 FT_UINT8
, BASE_DEC
, VALS(lpd_client_code
), 0x0,
166 { &hf_lpd_printer_option
,
167 { "Printer/options", "lpd.printer_option",
168 FT_STRING
, BASE_NONE
, NULL
, 0x0,
171 { &hf_lpd_response_code
,
172 { "Response", "lpd.response_code",
173 FT_UINT8
, BASE_DEC
, VALS(lpd_server_code
), 0x0,
176 static int *ett
[] = {
180 proto_lpd
= proto_register_protocol("Line Printer Daemon Protocol", "LPD", "lpd");
181 lpd_handle
= register_dissector("lpd", dissect_lpd
, proto_lpd
);
182 proto_register_field_array(proto_lpd
, hf
, array_length(hf
));
183 proto_register_subtree_array(ett
, array_length(ett
));
187 proto_reg_handoff_lpd(void)
189 dissector_add_uint_with_preference("tcp.port", TCP_PORT_PRINTER
, lpd_handle
);
193 * Editor modelines - https://www.wireshark.org/tools/modelines.html
198 * indent-tabs-mode: t
201 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
202 * :indentSize=8:tabSize=8:noTabs=false: