Coverage Report

Created: 2026-06-30 07:22

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