Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-sane.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-sane.c
2
 * Routines for SANE dissection
3
 * Copyright 2024, James Ring <sjr@jdns.org>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/**
13
 * A dissector for the SANE protocol (https://sane-project.gitlab.io/standard/net.html).
14
 *
15
 * This dissector works only for the control protocol (typically between a
16
 * client on some ephemeral port and a server on port 6566). The data transfer
17
 * of scanned images is done on a separate connection. Future versions of this
18
 * dissector might provide dissected image information.
19
 *
20
 * SANE is a protocol layered on top of TCP. The main dissect_sane function
21
 * relies on tcp_dissect_pdus to reassemble large messages. The protocol has no
22
 * meta-information (e.g. length of packet, type of message), the only way you
23
 * can know the format of a response is to see the corresponding request. The
24
 * only way you can know the length of a PDU is to read and understand various
25
 * fields in the request/response.
26
 *
27
 * For these reasons, the get_sane_pdu_len function has to pretty much do all
28
 * the work of the dissector itself. There is probably a more elegant way to do
29
 * this without the duplication that exists between get_sane_pdu_len and
30
 * dissect_sane_pdu.
31
 */
32
33
/* TODO
34
 * - Setup proper request / response tracking, with
35
 *   - references to related packets,
36
 *   - response time indications.
37
 */
38
39
#include "config.h"
40
41
#include <wireshark.h>
42
#include <epan/packet.h>
43
#include <epan/proto_data.h>
44
#include <epan/prefs.h>
45
46
#include "packet-tcp.h"
47
48
14.6k
#define SANE_WORD_LENGTH 4
49
28
#define SANE_MODULE_NAME "sane"
50
14
#define SANE_PORT "6566"
51
52
static range_t *sane_server_ports;
53
54
static dissector_handle_t sane_handle;
55
56
static int hf_sane_opcode;
57
static int hf_sane_version;
58
static int hf_sane_version_major;
59
static int hf_sane_version_minor;
60
static int hf_sane_version_build;
61
static int hf_sane_username;
62
static int hf_sane_password;
63
static int hf_sane_string;
64
static int hf_sane_string_length;
65
static int hf_sane_array_length;
66
static int hf_sane_device_descriptor;
67
static int hf_sane_device_name;
68
static int hf_sane_device_vendor;
69
static int hf_sane_device_model;
70
static int hf_sane_device_type;
71
static int hf_sane_resource_name;
72
static int hf_sane_device_handle;
73
static int hf_sane_option_descriptor;
74
static int hf_sane_option_index;
75
static int hf_sane_option_control_action;
76
static int hf_sane_option_value_type;
77
static int hf_sane_option_length;
78
static int hf_sane_option_count;
79
static int hf_sane_option_name;
80
static int hf_sane_option_value;
81
static int hf_sane_option_string_value;
82
static int hf_sane_option_numeric_value;
83
static int hf_sane_option_boolean_value;
84
static int hf_sane_option_title;
85
static int hf_sane_option_description;
86
static int hf_sane_option_unit;
87
static int hf_sane_option_size;
88
static int hf_sane_option_capabilities;
89
static int hf_sane_option_constraints;
90
static int hf_sane_option_constraint_type;
91
static int hf_sane_option_possible_string_value;
92
static int hf_sane_option_possible_word_value;
93
static int hf_sane_option_range_min;
94
static int hf_sane_option_range_max;
95
static int hf_sane_option_range_quant;
96
static int hf_sane_status;
97
static int hf_sane_data_port;
98
static int hf_sane_byte_order;
99
static int hf_sane_pointer_value;
100
static int hf_sane_frame_format;
101
static int hf_sane_scan_line_count;
102
static int hf_sane_scan_pixel_depth;
103
static int hf_sane_scan_pixels_per_line;
104
static int hf_sane_scan_bytes_per_line;
105
static int hf_sane_scan_is_last_frame;
106
static int hf_sane_dummy_value;
107
108
#define SANE_CAP_NONE 0x00000000
109
14
#define SANE_CAP_SOFT_SELECT 0x00000001
110
14
#define SANE_CAP_HARD_SELECT 0x00000002
111
14
#define SANE_CAP_SOFT_DETECT 0x00000004
112
14
#define SANE_CAP_EMULATED 0x00000008
113
14
#define SANE_CAP_AUTOMATIC 0x00000010
114
14
#define SANE_CAP_INACTIVE 0x00000020
115
14
#define SANE_CAP_ADVANCED 0x00000040
116
117
static int hf_sane_option_capability_soft_select;
118
static int hf_sane_option_capability_hard_select;
119
static int hf_sane_option_capability_soft_detect;
120
static int hf_sane_option_capability_emulated;
121
static int hf_sane_option_capability_automatic;
122
static int hf_sane_option_capability_inactive;
123
static int hf_sane_option_capability_advanced;
124
125
14
#define SANE_INFO_INEXACT 0x00000001
126
14
#define SANE_INFO_RELOAD_OPTIONS 0x00000002
127
14
#define SANE_INFO_RELOAD_PARAMS 0x00000004
128
129
static int hf_sane_control_option_info;
130
static int hf_sane_control_option_inexact;
131
static int hf_sane_control_option_reload_options;
132
static int hf_sane_control_option_reload_params;
133
134
static int* const sane_cap_bits[] = {
135
    &hf_sane_option_capability_soft_select,
136
    &hf_sane_option_capability_hard_select,
137
    &hf_sane_option_capability_soft_detect,
138
    &hf_sane_option_capability_emulated,
139
    &hf_sane_option_capability_automatic,
140
    &hf_sane_option_capability_inactive,
141
    &hf_sane_option_capability_advanced,
142
    NULL,
143
};
144
145
static int* const sane_control_option_info_bits[] = {
146
    &hf_sane_control_option_inexact,
147
    &hf_sane_control_option_reload_options,
148
    &hf_sane_control_option_reload_params,
149
    NULL,
150
};
151
152
static int proto_sane;
153
static int ett_sane;
154
static int ett_sane_version;
155
static int ett_sane_string;
156
static int ett_sane_option;
157
static int ett_sane_option_value;
158
static int ett_sane_option_capabilities;
159
static int ett_sane_option_constraints;
160
static int ett_sane_control_option_info;
161
static int ett_sane_device_descriptor;
162
163
typedef enum {
164
    SANE_NET_UNKNOWN = -1,
165
    SANE_NET_INIT = 0,
166
    SANE_NET_GET_DEVICES = 1,
167
    SANE_NET_OPEN = 2,
168
    SANE_NET_CLOSE = 3,
169
    SANE_NET_GET_OPTION_DESCRIPTORS = 4,
170
    SANE_NET_CONTROL_OPTION = 5,
171
    SANE_NET_GET_PARAMETERS = 6,
172
    SANE_NET_START = 7,
173
    SANE_NET_CANCEL = 8,
174
    SANE_NET_AUTHORIZE = 9,
175
    SANE_NET_EXIT = 10,
176
} sane_rpc_code;
177
178
static const value_string opcode_vals[] = {
179
    {SANE_NET_INIT,                   "SANE_NET_INIT"},
180
    {SANE_NET_GET_DEVICES,            "SANE_NET_GET_DEVICES"},
181
    {SANE_NET_OPEN,                   "SANE_NET_OPEN"},
182
    {SANE_NET_CLOSE,                  "SANE_NET_CLOSE"},
183
    {SANE_NET_GET_OPTION_DESCRIPTORS, "SANE_NET_GET_OPTION_DESCRIPTORS"},
184
    {SANE_NET_CONTROL_OPTION,         "SANE_NET_CONTROL_OPTION"},
185
    {SANE_NET_GET_PARAMETERS,         "SANE_NET_GET_PARAMETERS"},
186
    {SANE_NET_START,                  "SANE_NET_START"},
187
    {SANE_NET_CANCEL,                 "SANE_NET_CANCEL"},
188
    {SANE_NET_AUTHORIZE,              "SANE_NET_AUTHORIZE"},
189
    {SANE_NET_EXIT,                   "SANE_NET_EXIT"},
190
    {0, NULL},
191
};
192
193
typedef enum {
194
    SANE_NO_CONSTRAINT = 0,
195
    SANE_CONSTRAINT_RANGE = 1,
196
    SANE_CONSTRAINT_WORD_LIST = 2,
197
    SANE_CONSTRAINT_STRING_LIST = 3,
198
} sane_constraint_type;
199
200
static const value_string sane_constraint_type_names[] = {
201
    {SANE_NO_CONSTRAINT,          "SANE_NO_CONSTRAINT"},
202
    {SANE_CONSTRAINT_RANGE,       "SANE_CONSTRAINT_RANGE"},
203
    {SANE_CONSTRAINT_WORD_LIST,   "SANE_CONSTRAINT_WORD_LIST"},
204
    {SANE_CONSTRAINT_STRING_LIST, "SANE_CONSTRAINT_STRING_LIST"},
205
    {0, NULL},
206
};
207
208
typedef enum {
209
    SANE_TYPE_BOOL = 0,
210
    SANE_TYPE_INT = 1,
211
    SANE_TYPE_FIXED = 2,
212
    SANE_TYPE_STRING = 3,
213
    SANE_TYPE_BUTTON = 4,
214
    SANE_TYPE_GROUP = 5,
215
} sane_value_type;
216
217
static const value_string sane_value_types[] = {
218
    {SANE_TYPE_BOOL,   "SANE_TYPE_BOOL"},
219
    {SANE_TYPE_INT,    "SANE_TYPE_INT"},
220
    {SANE_TYPE_FIXED,  "SANE_TYPE_FIXED"},
221
    {SANE_TYPE_STRING, "SANE_TYPE_STRING"},
222
    {SANE_TYPE_BUTTON, "SANE_TYPE_BUTTON"},
223
    {SANE_TYPE_GROUP,  "SANE_TYPE_GROUP"},
224
    {0, NULL},
225
};
226
227
static const value_string control_types[] = {
228
    {0, "SANE_ACTION_GET_VALUE"},
229
    {1, "SANE_ACTION_SET_VALUE"},
230
    {2, "SANE_ACTION_SET_AUTO"},
231
    {0, NULL},
232
};
233
234
typedef enum {
235
    SANE_UNIT_NONE = 0,
236
    SANE_UNIT_PIXEL = 1,
237
    SANE_UNIT_BIT = 2,
238
    SANE_UNIT_MM = 3,
239
    SANE_UNIT_DPI = 4,
240
    SANE_UNIT_PERCENT = 5,
241
    SANE_UNIT_MICROSECOND = 6,
242
} sane_option_unit;
243
244
static const value_string sane_option_units[] = {
245
    {SANE_UNIT_NONE,        "SANE_UNIT_NONE"},
246
    {SANE_UNIT_PIXEL,       "SANE_UNIT_PIXEL"},
247
    {SANE_UNIT_BIT,         "SANE_UNIT_BIT"},
248
    {SANE_UNIT_MM,          "SANE_UNIT_MM"},
249
    {SANE_UNIT_DPI,         "SANE_UNIT_DPI"},
250
    {SANE_UNIT_PERCENT,     "SANE_UNIT_PERCENT"},
251
    {SANE_UNIT_MICROSECOND, "SANE_UNIT_MICROSECOND"},
252
    {0, NULL},
253
};
254
255
static const value_string sane_option_unit_suffixes[] = {
256
    {1, "px"},
257
    {2, "bits"},
258
    {3, "mm"},
259
    {4, "dpi"},
260
    {5, "%"},
261
    {6, "ms"},
262
    {0, NULL},
263
};
264
265
typedef enum {
266
    SANE_STATUS_UNKNOWN = -1,
267
    SANE_STATUS_OK = 0,
268
} sane_status;
269
270
static const value_string status_values[] = {
271
    {0,  "SANE_STATUS_GOOD"},
272
    {1,  "SANE_STATUS_UNSUPPORTED"},
273
    {2,  "SANE_STATUS_CANCELLED"},
274
    {3,  "SANE_STATUS_DEVICE_BUSY"},
275
    {4,  "SANE_STATUS_INVAL"},
276
    {5,  "SANE_STATUS_EOF"},
277
    {6,  "SANE_STATUS_JAMMED"},
278
    {7,  "SANE_STATUS_NO_DOCS"},
279
    {8,  "SANE_STATUS_COVER_OPEN"},
280
    {9,  "SANE_STATUS_IO_ERROR"},
281
    {10, "SANE_STATUS_NO_MEM"},
282
    {11, "SANE_STATUS_ACCESS_DENIED"},
283
    {0, NULL},
284
};
285
286
static const value_string sane_frame_format_names[] = {
287
    {0, "SANE_FRAME_GRAY"},
288
    {1, "SANE_FRAME_RGB"},
289
    {2, "SANE_FRAME_RED"},
290
    {3, "SANE_FRAME_GREEN"},
291
    {4, "SANE_FRAME_BLUE"},
292
    {0, NULL},
293
};
294
295
typedef struct {
296
    bool is_request;
297
    sane_rpc_code opcode;
298
    uint32_t packet_num;
299
} sane_pdu;
300
301
/* Keep track of current request status during first pass.
302
   N.B. opcode is stored in per-frame data and read during subsequent passes.
303
   Could if necessary be expanded to include frame numbers and timestamps for
304
   more complete request/response tracking.
305
*/
306
typedef struct {
307
    bool     seen_request;
308
    sane_pdu last_request;
309
    bool     auth;
310
} sane_session;
311
312
313
typedef struct {
314
    tvbuff_t *tvb;
315
    int offset;
316
    int bytes_read;
317
} tvb_sane_reader;
318
319
320
static int
321
3.19k
tvb_read_sane_word(tvb_sane_reader *r, uint32_t *dest) {
322
3.19k
    if (tvb_captured_length_remaining(r->tvb, r->offset) < SANE_WORD_LENGTH) {
323
39
        return 0;
324
39
    }
325
326
3.16k
    if (dest) {
327
2.95k
        *dest = tvb_get_ntohl(r->tvb, r->offset);
328
2.95k
    }
329
3.16k
    r->offset += SANE_WORD_LENGTH;
330
3.16k
    r->bytes_read += SANE_WORD_LENGTH;
331
3.16k
    return SANE_WORD_LENGTH;
332
3.19k
}
333
334
#define WORD_OR_RETURN(r, var) \
335
1.73k
    do { if (tvb_read_sane_word((r), (var)) == 0) { return 0; } } while(0)
336
337
338
static int
339
196
tvb_read_sane_string(tvb_sane_reader *r, wmem_allocator_t *alloc, char **dest) {
340
196
    int str_len;
341
196
    WORD_OR_RETURN(r, &str_len);
342
343
171
    if (tvb_captured_length_remaining(r->tvb, r->offset) < str_len) {
344
14
        return 0;
345
14
    }
346
347
157
    if (dest) {
348
61
        *dest = tvb_get_string_enc(alloc, r->tvb, r->offset, str_len, ENC_ASCII | ENC_NA);
349
61
    }
350
351
157
    r->offset += str_len;
352
157
    r->bytes_read += str_len;
353
157
    return SANE_WORD_LENGTH + str_len;
354
171
}
355
356
#define STRING_OR_RETURN(r) \
357
111
    do { if (tvb_read_sane_string((r), NULL, NULL) == 0) { return 0; } } while(0)
358
359
static int
360
9
tvb_skip_bytes(tvb_sane_reader *r, int len) {
361
9
    if (tvb_captured_length_remaining(r->tvb, r->offset) < len) {
362
1
        return 0;
363
1
    }
364
365
8
    r->offset += len;
366
8
    r->bytes_read += len;
367
8
    return len;
368
9
}
369
370
/**
371
 * Returns the expected response type for the (presumed) response in `pinfo`.
372
 * This usually returns the opcode of the last request seen in the conversation,
373
 * except for special handling of the authorization flow, for example:
374
 *
375
 * Client: SANE_NET_OPEN request (1)
376
 * Server: SANE_NET_OPEN response, authentication resource set (2)
377
 * Client: SANE_NET_AUTHORIZE request, username+password sent (3)
378
 * Server: SANE_NET_AUTHORIZE response sent, success (4)
379
 * Server: SANE_NET_OPEN response immediately sent (5)
380
 *
381
 * In this case, if the expected response type of PDU 5 is SANE_NET_OPEN,
382
 * because the server is responding to the request sent in PDU 2.
383
 */
384
static sane_rpc_code
385
0
get_sane_expected_response_type(sane_session *sess, packet_info *pinfo) {
386
387
    /* Look up any previous result. N.B. as called for length *and* dissecting,
388
       there may already be a value stored on first pass! */
389
0
    if (PINFO_FD_VISITED(pinfo) || p_get_proto_data(wmem_file_scope(), pinfo, proto_sane, 0)) {
390
0
        return (sane_rpc_code)GPOINTER_TO_UINT(p_get_proto_data(wmem_file_scope(), pinfo, proto_sane, 0));
391
0
    }
392
393
    /* First pass. Will be response to last_request if set, or AUTH request if flag set. */
394
0
    sane_rpc_code code = SANE_NET_UNKNOWN;
395
0
    if (sess->seen_request) {
396
0
        if (sess->auth) {
397
0
            code = SANE_NET_AUTHORIZE;
398
0
            sess->auth = false;
399
0
        }
400
0
        else {
401
0
            code = sess->last_request.opcode;
402
0
        }
403
0
    }
404
405
    /* Remember this code for later queries. */
406
0
    p_add_proto_data(wmem_file_scope(), pinfo, proto_sane, 0, GUINT_TO_POINTER(code));
407
408
0
    return code;
409
0
}
410
411
static proto_item *
412
1.47k
dissect_sane_word(tvb_sane_reader *r, proto_tree *tree, int hfindex, int *word) {
413
1.47k
    proto_item *item = proto_tree_add_item(tree, hfindex, r->tvb, r->offset, SANE_WORD_LENGTH,
414
1.47k
                        ENC_BIG_ENDIAN);
415
    // safe to ignore the return value here, we're guaranteed to have enough bytes to
416
    // read a word.
417
1.47k
    (void)tvb_read_sane_word(r, word);
418
1.47k
    return item;
419
1.47k
}
420
421
/**
422
 * Dissects and returns a SANE-encoded string from `r`.
423
 *
424
 * Also creates a proto_item representing the string. The `format` string should
425
 * contain a string format specifier (i.e. "%s"), which will be replaced with the
426
 * consumed string in the proto_item's text.
427
 */
428
static char *
429
85
dissect_sane_string(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree, int hfindex, const char *format) {
430
85
    int offset = r->offset;
431
85
    char *str = "";
432
85
    int len = tvb_read_sane_string(r, pinfo->pool, &str);
433
434
85
    proto_item *str_item = proto_tree_add_item(tree, hf_sane_string, r->tvb, offset, len, ENC_NA);
435
85
    proto_tree *str_tree = proto_item_add_subtree(str_item, ett_sane_string);
436
437
85
    proto_item_set_text(str_item, format, str);
438
85
    proto_tree_add_item(str_tree, hf_sane_string_length, r->tvb, offset, SANE_WORD_LENGTH, ENC_BIG_ENDIAN);
439
85
    proto_tree_add_item(str_tree, hfindex, r->tvb, offset + SANE_WORD_LENGTH, len - SANE_WORD_LENGTH, ENC_NA);
440
85
    return str;
441
85
}
442
443
static void
444
79
dissect_sane_net_init_request(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
445
79
    int version = 0;
446
79
    int offset = r->offset;
447
79
    proto_item *version_item = dissect_sane_word(r, tree, hf_sane_version, &version);
448
79
    proto_item *version_tree = proto_item_add_subtree(version_item, ett_sane_version);
449
450
79
    proto_item_append_text(version_item, " (major: %d, minor: %d, build: %d)", version >> 24,
451
79
                           (version >> 16) & 0xff, version & 0xffff);
452
453
79
    proto_tree_add_item(version_tree, hf_sane_version_major, r->tvb, offset, 1, ENC_NA);
454
79
    proto_tree_add_item(version_tree, hf_sane_version_minor, r->tvb, offset + 1, 1, ENC_NA);
455
79
    proto_tree_add_item(version_tree, hf_sane_version_build, r->tvb, offset + 2, 2, ENC_BIG_ENDIAN);
456
457
79
    dissect_sane_string(r, pinfo, tree, hf_sane_username, "Username: %s");
458
79
}
459
460
static void
461
2
dissect_sane_net_open_request(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
462
2
    dissect_sane_string(r, pinfo, tree, hf_sane_device_name, "Device name: %s");
463
2
}
464
465
static void
466
8
dissect_control_option_value(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
467
8
    int value_type = 0;
468
8
    dissect_sane_word(r, tree, hf_sane_option_value_type, &value_type);
469
470
8
    proto_item *value_item = proto_tree_add_item(tree, hf_sane_option_value, r->tvb, r->offset, -1, ENC_NA);
471
8
    proto_tree *value_tree = proto_item_add_subtree(value_item, ett_sane_option_value);
472
473
8
    int array_length = 0;
474
8
    proto_item *length_item = dissect_sane_word(r, value_tree, hf_sane_option_length, &array_length);
475
476
8
    if (value_type == SANE_TYPE_STRING) {
477
0
        dissect_sane_string(r, pinfo, value_tree, hf_sane_option_string_value, "Option value: '%s'");
478
8
    } else {
479
8
        proto_item_append_text(length_item, " (vector of length %d)", array_length / SANE_WORD_LENGTH);
480
8
        dissect_sane_word(r, value_tree, hf_sane_array_length, &array_length);
481
482
894k
        for (int i = 0; i < array_length; i++) {
483
894k
            if (value_type == SANE_TYPE_FIXED) {
484
0
                int value = 0;
485
0
                proto_item *numeric_value = dissect_sane_word(r, value_tree, hf_sane_option_numeric_value, &value);
486
0
                proto_item_append_text(numeric_value, " (%f)", ((double) value) / (1 << 16));
487
894k
            } else if (value_type == SANE_TYPE_INT) {
488
0
                int value = 0;
489
0
                proto_item *numeric_value = dissect_sane_word(r, value_tree, hf_sane_option_numeric_value, &value);
490
0
                proto_item_append_text(numeric_value, " (%d)", value);
491
894k
            } else if (value_type == SANE_TYPE_BOOL) {
492
0
                dissect_sane_word(r, value_tree, hf_sane_option_boolean_value, NULL);
493
0
            }
494
894k
        }
495
8
    }
496
8
}
497
498
static void
499
8
dissect_sane_net_control_option_request(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
500
8
    dissect_sane_word(r, tree, hf_sane_device_handle, NULL);
501
8
    dissect_sane_word(r, tree, hf_sane_option_index, NULL);
502
8
    dissect_sane_word(r, tree, hf_sane_option_control_action, NULL);
503
8
    dissect_control_option_value(r, pinfo, tree);
504
8
}
505
506
static void
507
2
dissect_sane_net_authorize_request(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
508
2
    dissect_sane_string(r, pinfo, tree, hf_sane_resource_name, "Authentication resource: %s");
509
2
    dissect_sane_string(r, pinfo, tree, hf_sane_username, "Username: %s");
510
2
    dissect_sane_string(r, pinfo, tree, hf_sane_password, "Password: %s");
511
2
}
512
513
/** Dissects a message whose only payload is a device handle. */
514
static void
515
19
dissect_sane_device_handle_request(tvb_sane_reader *r, proto_tree *tree) {
516
19
    dissect_sane_word(r, tree, hf_sane_device_handle, NULL);
517
19
}
518
519
static int
520
1.32k
dissect_sane_request(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
521
1.32k
    unsigned opcode = SANE_NET_UNKNOWN;
522
1.32k
    dissect_sane_word(r, tree, hf_sane_opcode, &opcode);
523
1.32k
    proto_item_append_text(tree, ": %s request", val_to_str(opcode, opcode_vals, "Unknown opcode (%u)"));
524
1.32k
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s request", val_to_str(opcode, opcode_vals, "Unknown opcode (%u)"));
525
526
1.32k
    switch (opcode) {
527
79
        case SANE_NET_INIT:
528
79
            dissect_sane_net_init_request(r, pinfo, tree);
529
79
            break;
530
8
        case SANE_NET_GET_DEVICES:
531
            // no additional payload here
532
8
            break;
533
2
        case SANE_NET_OPEN:
534
2
            dissect_sane_net_open_request(r, pinfo, tree);
535
2
            break;
536
8
        case SANE_NET_CONTROL_OPTION:
537
8
            dissect_sane_net_control_option_request(r, pinfo, tree);
538
8
            break;
539
8
        case SANE_NET_CLOSE:
540
8
        case SANE_NET_START:
541
14
        case SANE_NET_CANCEL:
542
15
        case SANE_NET_GET_PARAMETERS:
543
19
        case SANE_NET_GET_OPTION_DESCRIPTORS:
544
19
            dissect_sane_device_handle_request(r, tree);
545
19
            break;
546
2
        case SANE_NET_AUTHORIZE:
547
2
            dissect_sane_net_authorize_request(r, pinfo, tree);
548
2
            break;
549
1.32k
    }
550
551
1.29k
    return r->bytes_read;
552
1.32k
}
553
554
static proto_item *
555
0
dissect_sane_status(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree, unsigned *status_ptr) {
556
0
    int offset = r->offset;
557
0
    unsigned status = SANE_STATUS_UNKNOWN;
558
559
    // Safe to ignore the return value here, we're guaranteed to have enough bytes to
560
    // read a word.
561
0
    (void)tvb_read_sane_word(r, &status);
562
563
0
    proto_item_append_text(tree, " (%s)", val_to_str(status, status_values, "Unknown status (%u)"));
564
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", val_to_str(status, status_values, "Unknown (%u)"));
565
566
0
    proto_item *status_item = proto_tree_add_item(tree, hf_sane_status, r->tvb, offset, SANE_WORD_LENGTH, ENC_BIG_ENDIAN);
567
0
    proto_item_append_text(status_item, " (%s)", val_to_str(status, status_values, "Unknown (%u)"));
568
569
0
    if (status_ptr) {
570
0
        *status_ptr = status;
571
0
    }
572
573
0
    return status_item;
574
0
}
575
576
static void
577
0
dissect_sane_net_init_response(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
578
0
    unsigned status;
579
0
    dissect_sane_status(r, pinfo, tree, &status);
580
581
0
    int version = 0;
582
0
    proto_item *version_item = dissect_sane_word(r, tree, hf_sane_version, &version);
583
0
    proto_item *version_tree = proto_item_add_subtree(version_item, ett_sane_version);
584
585
0
    proto_item_append_text(version_item, " (major: %d, minor: %d, build: %d)", version >> 24,
586
0
                           (version >> 16) & 0xff, version & 0xffff);
587
588
0
    proto_tree_add_item(version_tree, hf_sane_version_major, r->tvb, SANE_WORD_LENGTH, 1, ENC_NA);
589
0
    proto_tree_add_item(version_tree, hf_sane_version_minor, r->tvb, SANE_WORD_LENGTH + 1, 1, ENC_NA);
590
0
    proto_tree_add_item(version_tree, hf_sane_version_build, r->tvb, SANE_WORD_LENGTH + 2, 2, ENC_BIG_ENDIAN);
591
0
}
592
593
static void
594
0
dissect_sane_net_open_response(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
595
0
    unsigned status = SANE_STATUS_UNKNOWN;
596
0
    dissect_sane_status(r, pinfo, tree, &status);
597
0
    dissect_sane_word(r, tree, hf_sane_device_handle, NULL);
598
0
    dissect_sane_string(r, pinfo, tree, hf_sane_resource_name, "Authentication resource: '%s'");
599
0
}
600
601
static void
602
0
append_option_value(proto_item *item, int value, unsigned units, unsigned type) {
603
0
    switch (type) {
604
0
        case SANE_TYPE_INT:
605
0
            if (units) {
606
0
                proto_item_append_text(item, " (%d %s)", value,
607
0
                                    val_to_str_const(units, sane_option_unit_suffixes, "(unknown unit)"));
608
0
            } else {
609
0
                proto_item_append_text(item, " (%d)", value);
610
0
            }
611
0
            break;
612
0
        case SANE_TYPE_FIXED: {
613
0
            double fixed_val = ((double) value) / (1 << 16);
614
0
            if (units) {
615
0
                proto_item_append_text(item, " (%f %s)", fixed_val,
616
0
                                    val_to_str_const(units, sane_option_unit_suffixes, "(unknown unit)"));
617
0
            } else {
618
0
                proto_item_append_text(item, " (%f)", fixed_val);
619
0
            }
620
0
            break;
621
0
        }
622
0
        case SANE_TYPE_BOOL:
623
0
            proto_item_append_text(item, " (%s)", (value == 1) ? "True" : ((value == 0) ? "False" : "Invalid"));
624
0
            break;
625
0
        default:
626
0
            break;
627
0
    }
628
0
}
629
630
static void
631
0
dissect_sane_net_get_option_descriptors_response(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
632
0
    int option_count = 0;
633
0
    dissect_sane_word(r, tree, hf_sane_option_count, &option_count);
634
635
0
    for (int i = 0; i < option_count; i++) {
636
0
        int unit = 0;
637
0
        int type = 0;
638
0
        int start_offset = r->offset;
639
0
        proto_item *option_item = proto_tree_add_item(tree, hf_sane_option_descriptor, r->tvb, start_offset, 0, ENC_NA);
640
0
        proto_tree *option_tree = proto_item_add_subtree(option_item, ett_sane_option);
641
0
        proto_item_set_text(option_item, "Option descriptor %d", i);
642
643
0
        dissect_sane_word(r, option_tree, hf_sane_pointer_value, NULL);
644
0
        char *option_name = dissect_sane_string(r, pinfo, option_tree, hf_sane_option_name, "Option name: %s");
645
0
        if (option_name && *option_name) {
646
0
            proto_item_append_text(option_item, " (%s)", option_name);
647
0
        }
648
0
        char *option_title = dissect_sane_string(r, pinfo, option_tree, hf_sane_option_title, "Option title: %s");
649
0
        if (!(option_name && *option_name) && (option_title && *option_title)) {
650
0
            proto_item_append_text(option_item, " (%s)", option_title);
651
0
        }
652
0
        dissect_sane_string(r, pinfo, option_tree, hf_sane_option_description, "Option description: %s");
653
0
        dissect_sane_word(r, option_tree, hf_sane_option_value_type, &type);
654
0
        dissect_sane_word(r, option_tree, hf_sane_option_unit, &unit);
655
0
        dissect_sane_word(r, option_tree, hf_sane_option_size, NULL);
656
657
0
        proto_tree_add_bitmask(option_tree, r->tvb, r->offset, hf_sane_option_capabilities,
658
0
                               ett_sane_option_capabilities,
659
0
                               sane_cap_bits, ENC_BIG_ENDIAN);
660
        /* XXX - Add consistency checks (expert items):
661
         * SANE_CAP_SOFT_SELECT set and SANE_CAP_HARD_SELECT set
662
         * SANE_CAP_SOFT_SELECT set and SANE_CAP_SOFT_DETECT not set
663
         */
664
0
        tvb_skip_bytes(r, SANE_WORD_LENGTH);
665
666
0
        int constraint_start = r->offset;
667
0
        proto_item *constraint_item = proto_tree_add_item(option_tree, hf_sane_option_constraints, r->tvb, constraint_start, 0, ENC_NA);
668
0
        proto_tree *constraint_tree = proto_item_add_subtree(constraint_item, ett_sane_option_constraints);
669
670
0
        int constraint_type = SANE_NO_CONSTRAINT;
671
0
        dissect_sane_word(r, constraint_tree, hf_sane_option_constraint_type, &constraint_type);
672
0
        proto_item_set_text(constraint_item, "Constraint type: %s",
673
0
                            val_to_str(constraint_type, sane_constraint_type_names, "Unknown (%u)"));
674
675
0
        int array_length = 0;
676
0
        int min = 0;
677
0
        int max = 0;
678
0
        int quant = 0;
679
0
        switch (constraint_type) {
680
0
            case SANE_CONSTRAINT_STRING_LIST:
681
0
                dissect_sane_word(r, constraint_tree, hf_sane_array_length, &array_length);
682
683
0
                for (int j = 0; j < array_length; j++) {
684
0
                    dissect_sane_string(r, pinfo, constraint_tree, hf_sane_option_possible_string_value, "Possible value: %s");
685
0
                }
686
0
                break;
687
0
            case SANE_CONSTRAINT_WORD_LIST:
688
0
                dissect_sane_word(r, constraint_tree, hf_sane_array_length, &array_length);
689
690
0
                for (int j = 0; j < array_length; j++) {
691
0
                    int value = 0;
692
0
                    proto_item *value_item = dissect_sane_word(r, constraint_tree, hf_sane_option_possible_word_value,
693
0
                                                               &value);
694
0
                    append_option_value(value_item, value, unit, type);
695
0
                }
696
0
                break;
697
0
            case SANE_CONSTRAINT_RANGE:
698
0
                dissect_sane_word(r, constraint_tree, hf_sane_pointer_value, NULL);
699
700
0
                proto_item *min_item = dissect_sane_word(r, constraint_tree, hf_sane_option_range_min, &min);
701
0
                append_option_value(min_item, min, unit, type);
702
0
                proto_item *max_item = dissect_sane_word(r, constraint_tree, hf_sane_option_range_max, &max);
703
0
                append_option_value(max_item, max, unit, type);
704
0
                proto_item *quant_item = dissect_sane_word(r, constraint_tree, hf_sane_option_range_quant, &quant);
705
0
                append_option_value(quant_item, quant, unit, type);
706
0
                break;
707
0
        }
708
709
0
        proto_item_set_len(constraint_item, r->offset - constraint_start);
710
0
        proto_item_set_len(option_item, r->offset - start_offset);
711
0
    }
712
0
}
713
714
static void
715
0
dissect_sane_net_start_response(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
716
0
    dissect_sane_status(r, pinfo, tree, NULL);
717
0
    dissect_sane_word(r, tree, hf_sane_data_port, NULL);
718
0
    dissect_sane_word(r, tree, hf_sane_byte_order, NULL);
719
0
    dissect_sane_string(r, pinfo, tree, hf_sane_resource_name, "Authentication resource: %s");
720
0
}
721
722
static void
723
0
dissect_sane_net_get_parameters_response(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
724
0
    dissect_sane_status(r, pinfo, tree, NULL);
725
0
    dissect_sane_word(r, tree, hf_sane_frame_format, NULL);
726
0
    dissect_sane_word(r, tree, hf_sane_scan_is_last_frame, NULL);
727
0
    dissect_sane_word(r, tree, hf_sane_scan_bytes_per_line, NULL);
728
0
    dissect_sane_word(r, tree, hf_sane_scan_pixels_per_line, NULL);
729
0
    dissect_sane_word(r, tree, hf_sane_scan_line_count, NULL);
730
0
    dissect_sane_word(r, tree, hf_sane_scan_pixel_depth, NULL);
731
0
}
732
733
static void
734
0
dissect_sane_net_control_option_response(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
735
0
    dissect_sane_status(r, pinfo, tree, NULL);
736
0
    proto_tree_add_bitmask(tree, r->tvb, r->offset, hf_sane_control_option_info,
737
0
                           ett_sane_control_option_info,
738
0
                           sane_control_option_info_bits, ENC_BIG_ENDIAN);
739
0
    tvb_skip_bytes(r, SANE_WORD_LENGTH);
740
0
    dissect_control_option_value(r, pinfo, tree);
741
0
    dissect_sane_string(r, pinfo, tree, hf_sane_resource_name, "Authentication resource: %s");
742
0
}
743
744
static void
745
0
dissect_sane_dummy_response(tvb_sane_reader *r, proto_tree *tree) {
746
0
    dissect_sane_word(r, tree, hf_sane_dummy_value, NULL);
747
0
}
748
749
static void
750
0
dissect_sane_net_get_devices_response(tvb_sane_reader *r, packet_info *pinfo, proto_tree *tree) {
751
0
    dissect_sane_status(r, pinfo, tree, NULL);
752
753
0
    int array_len = 0;
754
0
    dissect_sane_word(r, tree, hf_sane_array_length, &array_len);
755
0
    for (int i = 0; i < array_len - 1; i++) {
756
0
        int offset = r->offset;
757
0
        proto_item *device_item = proto_tree_add_item(tree, hf_sane_device_descriptor, r->tvb, r->offset, -1, ENC_NA);
758
0
        proto_tree *device_tree = proto_item_add_subtree(device_item, ett_sane_device_descriptor);
759
0
        proto_item_set_text(device_item, "Device[%d] descriptor", i);
760
761
0
        dissect_sane_word(r, device_tree, hf_sane_pointer_value, NULL);
762
0
        dissect_sane_string(r, pinfo, device_tree, hf_sane_device_name, "Device name: %s");
763
0
        dissect_sane_string(r, pinfo, device_tree, hf_sane_device_vendor, "Device vendor: %s");
764
0
        dissect_sane_string(r, pinfo, device_tree, hf_sane_device_model, "Device model: %s");
765
0
        dissect_sane_string(r, pinfo, device_tree, hf_sane_device_type, "Device type: %s");
766
0
        proto_item_set_len(device_item, r->offset - offset);
767
0
    }
768
769
0
    dissect_sane_word(r, tree, hf_sane_pointer_value, NULL);
770
0
}
771
772
static void
773
0
dissect_sane_response(tvb_sane_reader *r, sane_session *sess, packet_info *pinfo, proto_tree *tree) {
774
0
    sane_rpc_code opcode = get_sane_expected_response_type(sess, pinfo);
775
776
0
    proto_item_append_text(tree, ": %s response", val_to_str(opcode, opcode_vals, "Unknown opcode (%u)"));
777
0
    col_append_fstr(pinfo->cinfo, COL_INFO, "%s response", val_to_str(opcode, opcode_vals, "Unknown opcode (%u)"));
778
779
0
    switch (opcode) {
780
0
        case SANE_NET_INIT:
781
0
            dissect_sane_net_init_response(r, pinfo, tree);
782
0
            break;
783
0
        case SANE_NET_OPEN:
784
0
            dissect_sane_net_open_response(r, pinfo, tree);
785
0
            break;
786
0
        case SANE_NET_GET_OPTION_DESCRIPTORS:
787
0
            dissect_sane_net_get_option_descriptors_response(r, pinfo, tree);
788
0
            break;
789
0
        case SANE_NET_START:
790
0
            dissect_sane_net_start_response(r, pinfo, tree);
791
0
            break;
792
0
        case SANE_NET_GET_PARAMETERS:
793
0
            dissect_sane_net_get_parameters_response(r, pinfo, tree);
794
0
            break;
795
0
        case SANE_NET_CONTROL_OPTION:
796
0
            dissect_sane_net_control_option_response(r, pinfo, tree);
797
0
            break;
798
0
        case SANE_NET_GET_DEVICES:
799
0
            dissect_sane_net_get_devices_response(r, pinfo, tree);
800
0
            break;
801
0
        case SANE_NET_CLOSE:
802
0
        case SANE_NET_CANCEL:
803
0
        case SANE_NET_AUTHORIZE:
804
0
            dissect_sane_dummy_response(r, tree);
805
0
            break;
806
0
        default:
807
0
            break;
808
0
    }
809
0
}
810
811
static int
812
1.32k
dissect_sane_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
813
1.32k
    tvb_sane_reader r = {.tvb = tvb, .bytes_read = 0, .offset = 0};
814
815
1.32k
    conversation_t *conv = find_or_create_conversation(pinfo);
816
1.32k
    if (!conv) {
817
0
        return 0;
818
0
    }
819
820
1.32k
    sane_session *sess = conversation_get_proto_data(conv, proto_sane);
821
1.32k
    DISSECTOR_ASSERT_HINT(sess, "no session found");
822
823
1.32k
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SANE");
824
1.32k
    col_clear(pinfo->cinfo, COL_INFO);
825
826
1.32k
    proto_item *sane_item = proto_tree_add_item(tree, proto_sane, r.tvb, 0, -1, ENC_NA);
827
1.32k
    proto_tree *sane_tree = proto_item_add_subtree(sane_item, ett_sane);
828
829
1.32k
    if (value_is_in_range(sane_server_ports, pinfo->destport)) {
830
1.32k
        dissect_sane_request(&r, pinfo, sane_tree);
831
1.32k
    } else {
832
0
        dissect_sane_response(&r, sess, pinfo, sane_tree);
833
0
    }
834
835
1.32k
    proto_item_set_len(sane_item, r.bytes_read);
836
1.32k
    return r.bytes_read;
837
1.32k
}
838
839
/**
840
 * Returns the length, in bytes, of the SANE PDU beginning at the given offset
841
 * within the buffer. If the PDU appears to be a response from a client and its
842
 * type cannot be determined (e.g. because Wireshark never saw the request),
843
 * or if the PDU appears to be truncated and its length cannot be determined,
844
 * this function returns 0.
845
 */
846
static unsigned
847
1.36k
get_sane_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset, void *data _U_) {
848
1.36k
    tvb_sane_reader r = {.tvb = tvb, .offset = offset, .bytes_read = 0};
849
850
1.36k
    conversation_t *conv = find_or_create_conversation(pinfo);
851
1.36k
    if (!conv) {
852
0
        return 0;
853
0
    }
854
855
1.36k
    sane_session *sess = conversation_get_proto_data(conv, proto_sane);
856
857
1.36k
    if (!sess) {
858
7
        sess = wmem_new0(wmem_file_scope(), sane_session);
859
7
        conversation_add_proto_data(conv, proto_sane, sess);
860
7
    }
861
862
1.36k
    if (value_is_in_range(sane_server_ports, pinfo->destport)) {
863
        /* REQUEST */
864
1.36k
        unsigned opcode;
865
1.36k
        WORD_OR_RETURN(&r, &opcode);
866
867
1.35k
        sane_pdu pdu = {
868
1.35k
            .is_request = true,
869
1.35k
            .opcode = opcode,
870
1.35k
            .packet_num = pinfo->num
871
1.35k
        };
872
873
1.35k
        if (!PINFO_FD_VISITED(pinfo)) {
874
1.35k
            sess->seen_request = true;
875
1.35k
            if (opcode == SANE_NET_AUTHORIZE) {
876
                /* Just set this flag, so can remember op being authorised */
877
5
                sess->auth = true;
878
5
            }
879
1.34k
            else {
880
                /* Remember normal request */
881
1.34k
                sess->last_request = pdu;
882
1.34k
                sess->auth = false;
883
1.34k
            }
884
1.35k
        }
885
886
1.35k
        switch (opcode) {
887
96
            case SANE_NET_INIT:
888
96
                WORD_OR_RETURN(&r, NULL);
889
96
                STRING_OR_RETURN(&r);
890
85
                break;
891
85
            case SANE_NET_GET_DEVICES:
892
8
            case SANE_NET_EXIT:
893
8
                break;
894
3
            case SANE_NET_OPEN:
895
3
                STRING_OR_RETURN(&r);
896
2
                break;
897
8
            case SANE_NET_CLOSE:
898
12
            case SANE_NET_GET_OPTION_DESCRIPTORS:
899
13
            case SANE_NET_GET_PARAMETERS:
900
13
            case SANE_NET_START:
901
19
            case SANE_NET_CANCEL:
902
19
                WORD_OR_RETURN(&r, NULL);
903
19
                break;
904
19
            case SANE_NET_CONTROL_OPTION:
905
57
                for (int i = 0; i < 4; i++) {
906
47
                    WORD_OR_RETURN(&r, NULL);
907
47
                }
908
10
                unsigned value_size;
909
10
                WORD_OR_RETURN(&r, &value_size);
910
911
                // Pointer to void, contains an extra word for whether the pointer is NULL
912
9
                if (tvb_skip_bytes(&r, SANE_WORD_LENGTH + value_size) == 0) {
913
1
                    return 0;
914
1
                }
915
916
8
                break;
917
8
            case SANE_NET_AUTHORIZE:
918
5
                STRING_OR_RETURN(&r);
919
4
                STRING_OR_RETURN(&r);
920
3
                STRING_OR_RETURN(&r);
921
2
                break;
922
1.35k
        }
923
1.35k
    } else {
924
        /* RESPONSE */
925
0
        sane_rpc_code opcode = get_sane_expected_response_type(sess, pinfo);
926
0
        unsigned array_len;
927
928
0
        switch (opcode) {
929
0
            case SANE_NET_INIT:
930
0
                for (int i = 0; i < 2; i++) {
931
0
                    WORD_OR_RETURN(&r, NULL);
932
0
                }
933
0
                break;
934
0
            case SANE_NET_OPEN:
935
                // Status word
936
0
                WORD_OR_RETURN(&r, NULL);
937
                // Device handle
938
0
                WORD_OR_RETURN(&r, NULL);
939
                // Authentication resource name
940
0
                STRING_OR_RETURN(&r);
941
0
                break;
942
943
0
            case SANE_NET_GET_OPTION_DESCRIPTORS:
944
0
                WORD_OR_RETURN(&r, &array_len);
945
946
0
                for (unsigned i = 0; i < array_len; i++) {
947
0
                    WORD_OR_RETURN(&r, NULL);
948
949
                    // read name, title and description
950
0
                    for (int j = 0; j < 3; j++) {
951
0
                        STRING_OR_RETURN(&r);
952
0
                    }
953
954
0
                    for (int j = 0; j < 4; j++) {
955
0
                        WORD_OR_RETURN(&r, NULL);
956
0
                    }
957
958
                    // constraint type
959
0
                    unsigned constraint_type;
960
0
                    WORD_OR_RETURN(&r, &constraint_type);
961
962
0
                    unsigned string_count;
963
0
                    unsigned value_list_length;
964
0
                    switch (constraint_type) {
965
0
                        case SANE_CONSTRAINT_STRING_LIST:
966
0
                            WORD_OR_RETURN(&r, &string_count);
967
968
0
                            for (unsigned j = 0; j < string_count; j++) {
969
0
                                STRING_OR_RETURN(&r);
970
0
                            }
971
0
                            break;
972
0
                        case SANE_CONSTRAINT_WORD_LIST:
973
0
                            WORD_OR_RETURN(&r, &value_list_length);
974
975
0
                            for (unsigned j = 0; j < value_list_length; j++) {
976
0
                                WORD_OR_RETURN(&r, NULL);
977
0
                            }
978
0
                            break;
979
0
                        case SANE_CONSTRAINT_RANGE:
980
                            // Pointer to range, then min, max, quantization
981
0
                            for (unsigned j = 0; j < 4; j++) {
982
0
                                WORD_OR_RETURN(&r, NULL);
983
0
                            }
984
0
                            break;
985
0
                    }
986
0
                }
987
0
                break;
988
0
            case SANE_NET_CONTROL_OPTION:
989
                // Expected record format:
990
                // SANE_Status status
991
                // SANE_Word info
992
                // SANE_Word value_type
993
                // SANE_Word value_size
994
                // void *value
995
                // SANE_String *resource
996
                // See http://sane-project.org/html/doc017.html#s5.2.6.
997
0
                for (int i = 0; i < 3; i++) {
998
0
                    WORD_OR_RETURN(&r, NULL);
999
0
                }
1000
1001
0
                unsigned value_len;
1002
0
                WORD_OR_RETURN(&r, &value_len);
1003
1004
0
                if (tvb_skip_bytes(&r, value_len + SANE_WORD_LENGTH) == 0) {
1005
0
                    return 0;
1006
0
                }
1007
1008
0
                STRING_OR_RETURN(&r);
1009
0
                break;
1010
0
            case SANE_NET_GET_DEVICES:
1011
0
                WORD_OR_RETURN(&r, NULL);
1012
1013
0
                unsigned device_count;
1014
0
                WORD_OR_RETURN(&r, &device_count);
1015
0
                for (unsigned i = 0; i < device_count - 1; i++) {
1016
0
                    WORD_OR_RETURN(&r, NULL);
1017
0
                    STRING_OR_RETURN(&r);
1018
0
                    STRING_OR_RETURN(&r);
1019
0
                    STRING_OR_RETURN(&r);
1020
0
                    STRING_OR_RETURN(&r);
1021
0
                }
1022
0
                WORD_OR_RETURN(&r, NULL);
1023
0
                break;
1024
0
            case SANE_NET_CLOSE:
1025
0
                WORD_OR_RETURN(&r, NULL);
1026
0
                break;
1027
0
            case SANE_NET_START:
1028
0
                for (int i = 0; i < 3; i++) {
1029
0
                    WORD_OR_RETURN(&r, NULL);
1030
0
                }
1031
0
                STRING_OR_RETURN(&r);
1032
0
                break;
1033
0
            case SANE_NET_GET_PARAMETERS:
1034
0
                for (int i = 0; i < 7; i++) {
1035
0
                    WORD_OR_RETURN(&r, NULL);
1036
0
                }
1037
0
                break;
1038
0
            case SANE_NET_CANCEL:
1039
0
            case SANE_NET_AUTHORIZE:
1040
0
                WORD_OR_RETURN(&r, NULL);
1041
0
                break;
1042
0
            default:
1043
0
                break;
1044
0
        }
1045
0
    }
1046
1047
1.33k
    return r.bytes_read;
1048
1.36k
}
1049
1050
static int
1051
42
dissect_sane(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
1052
42
    tcp_dissect_pdus(tvb, pinfo, tree, true, SANE_WORD_LENGTH, get_sane_pdu_len, dissect_sane_pdu, data);
1053
42
    return (int) tvb_reported_length(tvb);
1054
42
}
1055
1056
static void
1057
14
apply_sane_prefs(void) {
1058
14
    sane_server_ports = prefs_get_range_value(SANE_MODULE_NAME, "tcp.port");
1059
14
}
1060
1061
14
void proto_register_sane(void) {
1062
14
    static hf_register_info hf[] = {
1063
14
            {&hf_sane_opcode,
1064
14
                    {
1065
14
                            "Opcode",
1066
14
                            "sane.opcode",
1067
14
                            FT_UINT32,
1068
14
                            BASE_DEC,
1069
14
                            VALS(opcode_vals),
1070
14
                            0,
1071
14
                            "RPC request type",
1072
14
                            HFILL,
1073
14
                    }},
1074
14
            {&hf_sane_version,
1075
14
                    {
1076
14
                            "Version",
1077
14
                            "sane.version",
1078
14
                            FT_UINT32,
1079
14
                            BASE_HEX,
1080
14
                            NULL,
1081
14
                            0,
1082
14
                            "Protocol version",
1083
14
                            HFILL,
1084
14
                    }},
1085
14
            {&hf_sane_version_major,
1086
14
                    {
1087
14
                            "Version Major Number",
1088
14
                            "sane.version.major",
1089
14
                            FT_UINT8,
1090
14
                            BASE_HEX,
1091
14
                            NULL,
1092
14
                            0,
1093
14
                            NULL,
1094
14
                            HFILL,
1095
14
                    }},
1096
14
            {&hf_sane_version_minor,
1097
14
                    {
1098
14
                            "Version Minor Number",
1099
14
                            "sane.version.minor",
1100
14
                            FT_UINT8,
1101
14
                            BASE_HEX,
1102
14
                            NULL,
1103
14
                            0,
1104
14
                            NULL,
1105
14
                            HFILL,
1106
14
                    }},
1107
14
            {&hf_sane_version_build,
1108
14
                    {
1109
14
                            "Version Build Number",
1110
14
                            "sane.version.build",
1111
14
                            FT_UINT16,
1112
14
                            BASE_HEX,
1113
14
                            NULL,
1114
14
                            0,
1115
14
                            NULL,
1116
14
                            HFILL,
1117
14
                    }},
1118
14
            {&hf_sane_username,
1119
14
                    {
1120
14
                            "Username",
1121
14
                            "sane.username",
1122
14
                            FT_STRING,
1123
14
                            BASE_NONE,
1124
14
                            NULL,
1125
14
                            0,
1126
14
                            NULL,
1127
14
                            HFILL,
1128
14
                    }},
1129
14
            {&hf_sane_password,
1130
14
                    {
1131
14
                            "Password",
1132
14
                            "sane.password",
1133
14
                            FT_STRING,
1134
14
                            BASE_NONE,
1135
14
                            NULL,
1136
14
                            0,
1137
14
                            NULL,
1138
14
                            HFILL,
1139
14
                    }},
1140
14
            {&hf_sane_string,
1141
14
                    {
1142
14
                            "String",
1143
14
                            "sane.string",
1144
14
                            FT_NONE,
1145
14
                            BASE_NONE,
1146
14
                            NULL,
1147
14
                            0,
1148
14
                            NULL,
1149
14
                            HFILL,
1150
14
                    }},
1151
14
            {&hf_sane_string_length,
1152
14
                    {
1153
14
                            "String length",
1154
14
                            "sane.string.length",
1155
14
                            FT_UINT32,
1156
14
                            BASE_DEC,
1157
14
                            NULL,
1158
14
                            0,
1159
14
                            NULL,
1160
14
                            HFILL,
1161
14
                    }},
1162
14
            {&hf_sane_array_length,
1163
14
                    {
1164
14
                            "Array length",
1165
14
                            "sane.array.length",
1166
14
                            FT_UINT32,
1167
14
                            BASE_DEC,
1168
14
                            NULL,
1169
14
                            0,
1170
14
                            NULL,
1171
14
                            HFILL,
1172
14
                    }},
1173
14
            {&hf_sane_device_descriptor,
1174
14
                    {
1175
14
                            "Device descriptor",
1176
14
                            "sane.device.descriptor",
1177
14
                            FT_NONE,
1178
14
                            BASE_NONE,
1179
14
                            NULL,
1180
14
                            0,
1181
14
                            NULL,
1182
14
                            HFILL,
1183
14
                    }},
1184
14
            {&hf_sane_device_name,
1185
14
                    {
1186
14
                            "Device name",
1187
14
                            "sane.device.name",
1188
14
                            FT_STRING,
1189
14
                            BASE_NONE,
1190
14
                            NULL,
1191
14
                            0,
1192
14
                            NULL,
1193
14
                            HFILL,
1194
14
                    }},
1195
14
            {&hf_sane_device_vendor,
1196
14
                    {
1197
14
                            "Device vendor",
1198
14
                            "sane.device.vendor",
1199
14
                            FT_STRING,
1200
14
                            BASE_NONE,
1201
14
                            NULL,
1202
14
                            0,
1203
14
                            NULL,
1204
14
                            HFILL,
1205
14
                    }},
1206
14
            {&hf_sane_device_model,
1207
14
                    {
1208
14
                            "Device model",
1209
14
                            "sane.device.model",
1210
14
                            FT_STRING,
1211
14
                            BASE_NONE,
1212
14
                            NULL,
1213
14
                            0,
1214
14
                            NULL,
1215
14
                            HFILL,
1216
14
                    }},
1217
14
            {&hf_sane_device_type,
1218
14
                    {
1219
14
                            "Device type",
1220
14
                            "sane.device.type",
1221
14
                            FT_STRING,
1222
14
                            BASE_NONE,
1223
14
                            NULL,
1224
14
                            0,
1225
14
                            NULL,
1226
14
                            HFILL,
1227
14
                    }},
1228
14
            {&hf_sane_resource_name,
1229
14
                    {
1230
14
                            "Resource name",
1231
14
                            "sane.resource.name",
1232
14
                            FT_STRING,
1233
14
                            BASE_NONE,
1234
14
                            NULL,
1235
14
                            0,
1236
14
                            NULL,
1237
14
                            HFILL,
1238
14
                    }},
1239
14
            {&hf_sane_device_handle,
1240
14
                    {
1241
14
                            "Device handle",
1242
14
                            "sane.device.handle",
1243
14
                            FT_UINT32,
1244
14
                            BASE_DEC,
1245
14
                            NULL,
1246
14
                            0,
1247
14
                            NULL,
1248
14
                            HFILL,
1249
14
                    }},
1250
14
            {&hf_sane_option_index,
1251
14
                    {
1252
14
                            "Option index",
1253
14
                            "sane.option",
1254
14
                            FT_UINT32,
1255
14
                            BASE_DEC,
1256
14
                            NULL,
1257
14
                            0,
1258
14
                            NULL,
1259
14
                            HFILL,
1260
14
                    }},
1261
14
            {&hf_sane_option_control_action,
1262
14
                    {
1263
14
                            "Option control action",
1264
14
                            "sane.option.action",
1265
14
                            FT_UINT32,
1266
14
                            BASE_DEC,
1267
14
                            VALS(control_types),
1268
14
                            0,
1269
14
                            NULL,
1270
14
                            HFILL,
1271
14
                    }},
1272
14
            {&hf_sane_option_length,
1273
14
                    {
1274
14
                            "Option value length",
1275
14
                            "sane.option.length",
1276
14
                            FT_UINT32,
1277
14
                            BASE_DEC,
1278
14
                            NULL,
1279
14
                            0,
1280
14
                            NULL,
1281
14
                            HFILL,
1282
1283
14
                    }},
1284
14
            {&hf_sane_option_value_type,
1285
14
                    {
1286
14
                            "Option value type",
1287
14
                            "sane.option.type",
1288
14
                            FT_UINT32,
1289
14
                            BASE_DEC,
1290
14
                            VALS(sane_value_types),
1291
14
                            0,
1292
14
                            NULL,
1293
14
                            HFILL,
1294
14
                    }},
1295
14
            {&hf_sane_status,
1296
14
                    {
1297
14
                            "Status",
1298
14
                            "sane.status",
1299
14
                            FT_UINT32,
1300
14
                            BASE_DEC,
1301
14
                            NULL,
1302
14
                            0,
1303
14
                            NULL,
1304
14
                            HFILL,
1305
14
                    }},
1306
14
            {&hf_sane_option_count,
1307
14
                    {
1308
14
                            "Option count",
1309
14
                            "sane.option_count",
1310
14
                            FT_UINT32,
1311
14
                            BASE_DEC,
1312
14
                            NULL,
1313
14
                            0,
1314
14
                            NULL,
1315
14
                            HFILL,
1316
14
                    }},
1317
14
            {&hf_sane_pointer_value,
1318
14
                    {
1319
14
                            "Pointer value",
1320
14
                            "sane.pointer_value",
1321
14
                            FT_UINT32,
1322
14
                            BASE_HEX,
1323
14
                            NULL,
1324
14
                            0,
1325
14
                            NULL,
1326
14
                            HFILL,
1327
14
                    }},
1328
14
            {&hf_sane_option_name,
1329
14
                    {
1330
14
                            "Option name",
1331
14
                            "sane.option.name",
1332
14
                            FT_STRING,
1333
14
                            BASE_NONE,
1334
14
                            NULL,
1335
14
                            0,
1336
14
                            NULL,
1337
14
                            HFILL,
1338
14
                    }},
1339
14
            {&hf_sane_option_title,
1340
14
                    {
1341
14
                            "Option title",
1342
14
                            "sane.option.title",
1343
14
                            FT_STRING,
1344
14
                            BASE_NONE,
1345
14
                            NULL,
1346
14
                            0,
1347
14
                            NULL,
1348
14
                            HFILL,
1349
14
                    }},
1350
14
            {&hf_sane_option_description,
1351
14
                    {
1352
14
                            "Option description",
1353
14
                            "sane.option.description",
1354
14
                            FT_STRING,
1355
14
                            BASE_NONE,
1356
14
                            NULL,
1357
14
                            0,
1358
14
                            NULL,
1359
14
                            HFILL,
1360
14
                    }},
1361
14
            {&hf_sane_option_descriptor,
1362
14
                    {
1363
14
                            "Option descriptor",
1364
14
                            "sane.option.descriptor",
1365
14
                            FT_BYTES,
1366
14
                            BASE_NONE,
1367
14
                            NULL,
1368
14
                            0,
1369
14
                            NULL,
1370
14
                            HFILL,
1371
14
                    }},
1372
14
            {&hf_sane_option_unit,
1373
14
                    {
1374
14
                            "Option unit",
1375
14
                            "sane.option.unit",
1376
14
                            FT_UINT32,
1377
14
                            BASE_DEC,
1378
14
                            VALS(sane_option_units),
1379
14
                            0,
1380
14
                            NULL,
1381
14
                            HFILL,
1382
14
                    }},
1383
14
            {&hf_sane_option_size,
1384
14
                    {
1385
14
                            "Option size",
1386
14
                            "sane.option.size",
1387
14
                            FT_UINT32,
1388
14
                            BASE_DEC,
1389
14
                            NULL,
1390
14
                            0,
1391
14
                            NULL,
1392
14
                            HFILL,
1393
14
                    }},
1394
14
            {&hf_sane_option_capabilities,
1395
14
                    {
1396
14
                            "Option capabilities",
1397
14
                            "sane.option.capabilities",
1398
14
                            FT_UINT32,
1399
14
                            BASE_HEX,
1400
14
                            NULL,
1401
14
                            0,
1402
14
                            NULL,
1403
14
                            HFILL,
1404
1405
14
                    }},
1406
14
            {&hf_sane_option_capability_soft_select,
1407
14
                    {
1408
14
                            "Can be changed in software",
1409
14
                            "sane.option.soft_select",
1410
14
                            FT_BOOLEAN,
1411
14
                            32,
1412
14
                            NULL,
1413
14
                            SANE_CAP_SOFT_SELECT,
1414
14
                            NULL,
1415
14
                            HFILL,
1416
14
                    }},
1417
14
            {&hf_sane_option_capability_hard_select,
1418
14
                    {
1419
14
                            "Requires user intervention to change",
1420
14
                            "sane.option.hard_select",
1421
14
                            FT_BOOLEAN,
1422
14
                            32,
1423
14
                            NULL,
1424
14
                            SANE_CAP_HARD_SELECT,
1425
14
                            NULL,
1426
14
                            HFILL,
1427
14
                    }},
1428
14
            {&hf_sane_option_capability_soft_detect,
1429
14
                    {
1430
14
                            "Can be detected by software",
1431
14
                            "sane.option.soft_detect",
1432
14
                            FT_BOOLEAN,
1433
14
                            32,
1434
14
                            NULL,
1435
14
                            SANE_CAP_SOFT_DETECT,
1436
14
                            NULL,
1437
14
                            HFILL,
1438
14
                    }},
1439
14
            {&hf_sane_option_capability_emulated,
1440
14
                    {
1441
14
                            "Emulated in software",
1442
14
                            "sane.option.emulated",
1443
14
                            FT_BOOLEAN,
1444
14
                            32,
1445
14
                            NULL,
1446
14
                            SANE_CAP_EMULATED,
1447
14
                            NULL,
1448
14
                            HFILL,
1449
14
                    }},
1450
14
            {&hf_sane_option_capability_automatic,
1451
14
                    {
1452
14
                            "Can be set automatically",
1453
14
                            "sane.option.automatic",
1454
14
                            FT_BOOLEAN,
1455
14
                            32,
1456
14
                            NULL,
1457
14
                            SANE_CAP_AUTOMATIC,
1458
14
                            NULL,
1459
14
                            HFILL,
1460
14
                    }},
1461
14
            {&hf_sane_option_capability_inactive,
1462
14
                    {
1463
14
                            "Inactive",
1464
14
                            "sane.option.inactive",
1465
14
                            FT_BOOLEAN,
1466
14
                            32,
1467
14
                            NULL,
1468
14
                            SANE_CAP_INACTIVE,
1469
14
                            NULL,
1470
14
                            HFILL,
1471
14
                    }},
1472
14
            {&hf_sane_option_capability_advanced,
1473
14
                    {
1474
14
                            "Advanced option",
1475
14
                            "sane.option.advanced",
1476
14
                            FT_BOOLEAN,
1477
14
                            32,
1478
14
                            NULL,
1479
14
                            SANE_CAP_ADVANCED,
1480
14
                            NULL,
1481
14
                            HFILL,
1482
14
                    }},
1483
14
            {&hf_sane_option_value,
1484
14
                    {
1485
14
                            "Option value",
1486
14
                            "sane.option.value",
1487
14
                            FT_NONE,
1488
14
                            BASE_NONE,
1489
14
                            NULL,
1490
14
                            0,
1491
14
                            NULL,
1492
14
                            HFILL,
1493
14
                    }},
1494
14
            {&hf_sane_option_string_value,
1495
14
                    {
1496
14
                            "Option string value",
1497
14
                            "sane.option.value.string",
1498
14
                            FT_STRING,
1499
14
                            BASE_NONE,
1500
14
                            NULL,
1501
14
                            0,
1502
14
                            NULL,
1503
14
                            HFILL,
1504
14
                    }},
1505
14
            {&hf_sane_option_numeric_value,
1506
14
                    {
1507
14
                            "Option numeric value",
1508
14
                            "sane.option.value.numeric",
1509
14
                            FT_UINT32,
1510
14
                            BASE_HEX,
1511
14
                            NULL,
1512
14
                            0,
1513
14
                            NULL,
1514
14
                            HFILL,
1515
14
                    }},
1516
14
            {&hf_sane_option_boolean_value,
1517
14
                    {
1518
14
                            "Option boolean value",
1519
14
                            "sane.option.value.boolean",
1520
14
                            FT_BOOLEAN,
1521
14
                            BASE_NONE,
1522
14
                            NULL,
1523
14
                            0,
1524
14
                            NULL,
1525
14
                            HFILL,
1526
14
                    }},
1527
14
            {&hf_sane_option_constraints,
1528
14
                    {
1529
14
                            "Option constraints",
1530
14
                            "sane.option.constraints",
1531
14
                            FT_BYTES,
1532
14
                            BASE_NONE,
1533
14
                            NULL,
1534
14
                            0,
1535
14
                            NULL,
1536
14
                            HFILL,
1537
14
                    }},
1538
14
            {&hf_sane_option_constraint_type,
1539
14
                    {
1540
14
                            "Option constraint type",
1541
14
                            "sane.option.constraint_type",
1542
14
                            FT_UINT32,
1543
14
                            BASE_DEC,
1544
14
                            VALS(sane_constraint_type_names),
1545
14
                            0,
1546
14
                            NULL,
1547
14
                            HFILL,
1548
14
                    }},
1549
14
            {&hf_sane_option_possible_string_value,
1550
14
                    {
1551
14
                            "Possible option string value",
1552
14
                            "sane.option.possible_string_value",
1553
14
                            FT_STRING,
1554
14
                            BASE_NONE,
1555
14
                            NULL,
1556
14
                            0,
1557
14
                            NULL,
1558
14
                            HFILL,
1559
14
                    }},
1560
14
            {&hf_sane_option_possible_word_value,
1561
14
                    {
1562
14
                            "Possible option word value",
1563
14
                            "sane.option.possible_word_value",
1564
14
                            FT_UINT32,
1565
14
                            BASE_HEX,
1566
14
                            NULL,
1567
14
                            0,
1568
14
                            NULL,
1569
14
                            HFILL,
1570
14
                    }},
1571
14
            {&hf_sane_option_range_min,
1572
14
                    {
1573
14
                            "Option minimum value",
1574
14
                            "sane.option.min_value",
1575
14
                            FT_UINT32,
1576
14
                            BASE_HEX,
1577
14
                            NULL,
1578
14
                            0,
1579
14
                            NULL,
1580
14
                            HFILL,
1581
14
                    }},
1582
14
            {&hf_sane_option_range_max,
1583
14
                    {
1584
14
                            "Option maximum value",
1585
14
                            "sane.option.max_value",
1586
14
                            FT_UINT32,
1587
14
                            BASE_HEX,
1588
14
                            NULL,
1589
14
                            0,
1590
14
                            NULL,
1591
14
                            HFILL,
1592
14
                    }},
1593
14
            {&hf_sane_option_range_quant,
1594
14
                    {
1595
14
                            "Option value quantization",
1596
14
                            "sane.option.quant",
1597
14
                            FT_UINT32,
1598
14
                            BASE_HEX,
1599
14
                            NULL,
1600
14
                            0,
1601
14
                            NULL,
1602
14
                            HFILL,
1603
14
                    }},
1604
14
            {&hf_sane_data_port,
1605
14
                    {
1606
14
                            "Image data port number",
1607
14
                            "sane.data_port",
1608
14
                            FT_UINT32,
1609
14
                            BASE_DEC,
1610
14
                            NULL,
1611
14
                            0,
1612
14
                            NULL,
1613
14
                            HFILL,
1614
14
                    }},
1615
14
            {&hf_sane_byte_order,
1616
14
                    {
1617
14
                            "Image data byte order",
1618
14
                            "sane.byte_order",
1619
14
                            FT_UINT32,
1620
14
                            BASE_HEX,
1621
14
                            NULL,
1622
14
                            0,
1623
14
                            NULL,
1624
14
                            HFILL,
1625
14
                    }},
1626
14
            {&hf_sane_frame_format,
1627
14
                    {
1628
14
                            "Image data frame format",
1629
14
                            "sane.scan.frame_format",
1630
14
                            FT_UINT32,
1631
14
                            BASE_DEC,
1632
14
                            VALS(sane_frame_format_names),
1633
14
                            0,
1634
14
                            NULL,
1635
14
                            HFILL,
1636
14
                    }},
1637
14
            {&hf_sane_scan_line_count,
1638
14
                    {
1639
14
                            "Image data line count",
1640
14
                            "sane.scan.line_count",
1641
14
                            FT_UINT32,
1642
14
                            BASE_DEC,
1643
14
                            NULL,
1644
14
                            0,
1645
14
                            NULL,
1646
14
                            HFILL,
1647
14
                    }},
1648
14
            {&hf_sane_scan_pixel_depth,
1649
14
                    {
1650
14
                            "Image data pixel depth",
1651
14
                            "sane.scan.pixel_depth",
1652
14
                            FT_UINT32,
1653
14
                            BASE_DEC,
1654
14
                            NULL,
1655
14
                            0,
1656
14
                            NULL,
1657
14
                            HFILL,
1658
14
                    }},
1659
14
            {&hf_sane_scan_pixels_per_line,
1660
14
                    {
1661
14
                            "Image data pixels per line",
1662
14
                            "sane.scan.pixels_per_line",
1663
14
                            FT_UINT32,
1664
14
                            BASE_DEC,
1665
14
                            NULL,
1666
14
                            0,
1667
14
                            NULL,
1668
14
                            HFILL,
1669
14
                    }},
1670
14
            {&hf_sane_scan_bytes_per_line,
1671
14
                    {
1672
14
                            "Image data bytes per line",
1673
14
                            "sane.scan.bytes_per_line",
1674
14
                            FT_UINT32,
1675
14
                            BASE_DEC,
1676
14
                            NULL,
1677
14
                            0,
1678
14
                            NULL,
1679
14
                            HFILL,
1680
14
                    }},
1681
14
            {&hf_sane_scan_is_last_frame,
1682
14
                    {
1683
14
                            "Is last image data frame",
1684
14
                            "sane.scan.last_frame",
1685
14
                            FT_BOOLEAN,
1686
14
                            BASE_NONE,
1687
14
                            NULL,
1688
14
                            0,
1689
14
                            NULL,
1690
14
                            HFILL,
1691
14
                    }},
1692
14
            {&hf_sane_dummy_value,
1693
14
                    {
1694
14
                            "Dummy value",
1695
14
                            "sane.dummy_value",
1696
14
                            FT_UINT32,
1697
14
                            BASE_DEC,
1698
14
                            NULL,
1699
14
                            0,
1700
14
                            NULL,
1701
14
                            HFILL,
1702
14
                    }},
1703
14
            {&hf_sane_control_option_info,
1704
14
                    {
1705
14
                            "Control option info",
1706
14
                            "sane.control_option.info",
1707
14
                            FT_UINT32,
1708
14
                            BASE_HEX,
1709
14
                            NULL,
1710
14
                            0,
1711
14
                            NULL,
1712
14
                            HFILL,
1713
14
                    }},
1714
14
            {&hf_sane_control_option_inexact,
1715
14
                    {
1716
14
                            "Inexact value selected",
1717
14
                            "sane.control_option.info.inexact",
1718
14
                            FT_BOOLEAN,
1719
14
                            32,
1720
14
                            NULL,
1721
14
                            SANE_INFO_INEXACT,
1722
14
                            NULL,
1723
14
                            HFILL,
1724
14
                    }},
1725
14
            {&hf_sane_control_option_reload_options,
1726
14
                    {
1727
14
                            "Client should reload options",
1728
14
                            "sane.control_option.info.reload_options",
1729
14
                            FT_BOOLEAN,
1730
14
                            32,
1731
14
                            NULL,
1732
14
                            SANE_INFO_RELOAD_OPTIONS,
1733
14
                            NULL,
1734
14
                            HFILL,
1735
14
                    }},
1736
14
            {&hf_sane_control_option_reload_params,
1737
14
                    {
1738
14
                            "Client should reload scan parameters",
1739
14
                            "sane.control_option.info.reload_params",
1740
14
                            FT_BOOLEAN,
1741
14
                            32,
1742
14
                            NULL,
1743
14
                            SANE_INFO_RELOAD_PARAMS,
1744
14
                            NULL,
1745
14
                            HFILL,
1746
14
                    }},
1747
14
    };
1748
1749
1750
14
    static int *ett[] = {
1751
14
        &ett_sane,
1752
14
        &ett_sane_version,
1753
14
        &ett_sane_string,
1754
14
        &ett_sane_option,
1755
14
        &ett_sane_option_value,
1756
14
        &ett_sane_option_capabilities,
1757
14
        &ett_sane_option_constraints,
1758
14
        &ett_sane_control_option_info,
1759
14
        &ett_sane_device_descriptor,
1760
14
    };
1761
1762
14
    module_t *sane_module;
1763
1764
14
    proto_sane = proto_register_protocol("Scanner Access Now Easy", "SANE", "sane");
1765
14
    proto_register_field_array(proto_sane, hf, array_length(hf));
1766
14
    proto_register_subtree_array(ett, array_length(ett));
1767
1768
14
    register_dissector(SANE_MODULE_NAME, dissect_sane, proto_sane);
1769
1770
    /*
1771
     * XXX - Required to be notified of server port changes,
1772
     * while no other preferences are registered.
1773
     */
1774
14
    sane_module = prefs_register_protocol(proto_sane, apply_sane_prefs);
1775
14
    (void)sane_module;
1776
14
}
1777
1778
void
1779
14
proto_reg_handoff_sane(void) {
1780
14
    sane_handle = create_dissector_handle(dissect_sane, proto_sane);
1781
14
    dissector_add_uint_range_with_preference("tcp.port", SANE_PORT, sane_handle);
1782
14
    apply_sane_prefs();
1783
14
}
1784
1785
/*
1786
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1787
 *
1788
 * Local variables:
1789
 * c-basic-offset: 4
1790
 * tab-width: 8
1791
 * indent-tabs-mode: nil
1792
 * End:
1793
 *
1794
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1795
 * :indentSize=4:tabSize=8:noTabs=true:
1796
 */