Skip to content

Commit ea5cced

Browse files
committed
add c-move and c-get
1 parent a5061e4 commit ea5cced

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

scapy/contrib/dicom.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
"""
1010
DICOM (Digital Imaging and Communications in Medicine) Protocol
11+
Reference: DICOM PS3.8 - Network Communication Support for Message Exchange
12+
https://dicom.nema.org/medical/dicom/current/output/html/part08.html
1113
"""
1214

1315
import logging

test/contrib/dicom.uts

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,26 @@ assert C_ECHO_RSP is not None
3131
assert C_STORE_RQ is not None
3232
assert C_STORE_RSP is not None
3333
assert C_FIND_RQ is not None
34+
assert C_FIND_RSP is not None
35+
assert C_MOVE_RQ is not None
36+
assert C_MOVE_RSP is not None
37+
assert C_GET_RQ is not None
38+
assert C_GET_RSP is not None
3439

3540
= Verify constants are exported
3641
assert DICOM_PORT == 104
3742
assert APP_CONTEXT_UID == "1.2.840.10008.3.1.1.1"
3843
assert DEFAULT_TRANSFER_SYNTAX_UID == "1.2.840.10008.1.2"
3944
assert VERIFICATION_SOP_CLASS_UID == "1.2.840.10008.1.1"
4045

46+
= Verify Query/Retrieve SOP Class UIDs are exported
47+
assert PATIENT_ROOT_QR_FIND_SOP_CLASS_UID == "1.2.840.10008.5.1.4.1.2.1.1"
48+
assert PATIENT_ROOT_QR_MOVE_SOP_CLASS_UID == "1.2.840.10008.5.1.4.1.2.1.2"
49+
assert PATIENT_ROOT_QR_GET_SOP_CLASS_UID == "1.2.840.10008.5.1.4.1.2.1.3"
50+
assert STUDY_ROOT_QR_FIND_SOP_CLASS_UID == "1.2.840.10008.5.1.4.1.2.2.1"
51+
assert STUDY_ROOT_QR_MOVE_SOP_CLASS_UID == "1.2.840.10008.5.1.4.1.2.2.2"
52+
assert STUDY_ROOT_QR_GET_SOP_CLASS_UID == "1.2.840.10008.5.1.4.1.2.2.3"
53+
4154
############
4255
############
4356
+ PDU header tests
@@ -158,7 +171,6 @@ raw = struct.pack("!BBH", 0xFF, 0, 4) + b"test"
158171
parsed = DICOMVariableItem(raw)
159172
assert parsed.item_type == 0xFF
160173
assert parsed.length == 4
161-
# Fallback handled by guess_payload_class returning DICOMGenericItem
162174
assert parsed.payload is not None
163175

164176
############
@@ -267,7 +279,6 @@ pdv1 = PresentationDataValueItem(context_id=1, data=b'\xDE\xAD', is_command=1, i
267279
pdv2 = PresentationDataValueItem(context_id=1, data=b'\xBE\xEF', is_command=0, is_last=1)
268280
pkt = DICOM() / P_DATA_TF(pdv_items=[pdv1, pdv2])
269281
raw = bytes(pkt)
270-
# Verify PDU type and structure
271282
assert raw[0] == 0x04
272283
assert len(raw) > 6
273284

@@ -276,8 +287,7 @@ test_data = b"\x01\x02\x03\x04\x05"
276287
pdv = PresentationDataValueItem(context_id=3, data=test_data, is_command=1, is_last=1)
277288
original = DICOM() / P_DATA_TF(pdv_items=[pdv])
278289
serialized = bytes(original)
279-
# Verify structure
280-
assert serialized[0] == 0x04 # P-DATA-TF type
290+
assert serialized[0] == 0x04
281291
length = struct.unpack("!I", serialized[2:6])[0]
282292
assert length > 0
283293
assert test_data in serialized
@@ -349,14 +359,55 @@ pkt = C_FIND_RQ(message_id=55)
349359
raw = bytes(pkt)
350360
assert struct.pack("<H", 0x0020) in raw
351361

362+
= C_FIND_RSP creation
363+
pkt = C_FIND_RSP(message_id_responded=55, status=0x0000)
364+
raw = bytes(pkt)
365+
assert struct.pack("<H", 0x8020) in raw
366+
assert struct.pack("<H", 0x0000) in raw
367+
368+
= C_MOVE_RQ creation with move_destination
369+
pkt = C_MOVE_RQ(message_id=100, move_destination=b"DEST_AE")
370+
raw = bytes(pkt)
371+
assert struct.pack("<H", 0x0021) in raw
372+
assert b'DEST_AE' in raw
373+
374+
= C_MOVE_RSP creation with sub-operation counters
375+
pkt = C_MOVE_RSP(
376+
message_id_responded=100,
377+
status=0xFF00,
378+
num_remaining=5,
379+
num_completed=3,
380+
num_failed=1,
381+
num_warning=0
382+
)
383+
raw = bytes(pkt)
384+
assert struct.pack("<H", 0x8021) in raw
385+
assert struct.pack("<H", 0xFF00) in raw
386+
387+
= C_GET_RQ creation
388+
pkt = C_GET_RQ(message_id=200)
389+
raw = bytes(pkt)
390+
assert struct.pack("<H", 0x0010) in raw
391+
392+
= C_GET_RSP creation with sub-operation counters
393+
pkt = C_GET_RSP(
394+
message_id_responded=200,
395+
status=0x0000,
396+
num_remaining=0,
397+
num_completed=10,
398+
num_failed=0,
399+
num_warning=0
400+
)
401+
raw = bytes(pkt)
402+
assert struct.pack("<H", 0x8010) in raw
403+
352404
= DIMSE command in P-DATA-TF - build verification
353405
dimse = C_ECHO_RQ(message_id=42)
354406
pdv = PresentationDataValueItem(context_id=1, data=bytes(dimse), is_command=1, is_last=1)
355407
pdata = DICOM() / P_DATA_TF(pdv_items=[pdv])
356408
raw = bytes(pdata)
357-
# Verify structure
358-
assert raw[0] == 0x04 # P-DATA-TF type
359-
assert b'1.2.840.10008.1.1' in raw # Verification SOP Class UID in the payload
409+
assert raw[0] == 0x04
410+
assert b'1.2.840.10008.1.1' in raw
360411

361412
############
362413
############

0 commit comments

Comments
 (0)