summaryrefslogtreecommitdiff
path: root/doc/rfc/rfc963.txt
blob: d4316fa1cac6309b7f8d9ac3913d2b63267b78e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
Network Working Group                                 Deepinder P. Sidhu
Request for Comments: 963                          Iowa State University
                                                           November 1985

              SOME PROBLEMS WITH THE SPECIFICATION OF THE
                  MILITARY STANDARD INTERNET PROTOCOL


STATUS OF THIS MEMO

   The purpose of this RFC is to provide helpful information on the
   Military Standard Internet Protocol (MIL-STD-1777) so that one can
   obtain a reliable implementation of this protocol standard.
   Distribution of this note is unlimited.

ABSTRACT

   This paper points out several significant problems in the
   specification of the Military Standard Internet Protocol
   (MIL-STD-1777, dated August 1983 [MILS83a]).  These results are based
   on an initial investigation of this protocol standard.  The problems
   are: (1) a failure to reassemble fragmented messages completely; (2)
   a missing state transition; (3) errors in testing for reassembly
   completion; (4) errors in computing fragment sizes; (5) minor errors
   in message reassembly; (6) incorrectly computed length for certain
   datagrams.  This note also proposes solutions to these problems.

1.  Introduction

   In recent years, much progress has been made in creating an
   integrated set of tools for developing reliable communication
   protocols.  These tools provide assistance in the specification,
   verification, implementation and testing of protocols.  Several
   protocols have been analyzed and developed using such tools.
   Examples of automated verification and implementation of several real
   world protocols are discussed in [BLUT82] [BLUT83] [SIDD83] [SIDD84].

   We are currently working on the automatic implementation of the
   Military Standard Internet Protocol (IP).  This analysis will be
   based on the published specification [MILS83a] of IP dated 12 August
   1983.

   While studying the MIL Standard IP specification, we have noticed
   numerous errors in the specification of this protocol.  One
   consequence of these errors is that the protocol will never deliver
   fragmented incoming datagrams; if this error is corrected, such
   datagrams will be missing some data and their lengths will be
   incorrectly reported.  In addition, outgoing datagrams that are
   divided into fragments will be missing some data.  The proof of these
   statements follows from the specification of IP [MILS83a] as
   discussed below.


Sidhu                                                           [Page 1]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


2.  Internet Protocol

   The Internet Protocol (IP) is a network layer protocol in the DoD
   protocol hierarchy which provides communication across interconnected
   packet-switched networks in an internetwork environment.  IP provides
   a pure datagram service with no mechanism for reliability, flow
   control, sequencing, etc.  Instead, these features are provided by a
   connection-oriented protocol, DoD Transmission Control Protocol (TCP)
   [MILS83b], which is implemented in the layer above IP.  TCP is
   designed to operate successfully over channels that are inherently
   unreliable, i.e., which can lose, damage, duplicate, and reorder
   packets.

   Over the years, DARPA has supported specifications of several
   versions of IP; the last one appeared in [POSJ81].  A few years ago,
   the Defense Communications Agency decided to standardize IP for use
   in DoD networks.  For this purpose, the DCA supported formal
   specification of this protocol, following the design discussed in
   [POSJ81] and the technique and organization defined in [SDC82].  A
   detailed specification of this protocol, given in [MILS83a], has been
   adopted as the DoD standard for the Internet Protocol.

   The specification of IP state transitions is organized into decision
   tables; the decision functions and action procedures are specified in
   a subset of Ada[1], and may employ a set of machine-specific data
   structures.  Decision tables are supplied for the pairs <state name,
   interface event> as follows: <inactive, send from upper layer>,
   <inactive, receive from lower layer>, and <reassembling, receive from
   lower layer>.  To provide an error indication in the case that some
   fragments of a datagram are received but some are missing, a decision
   table is also supplied for the pair <reassembling, reassembly time
   limit elapsed>.  (The event names are English descriptions and not
   the names employed by [MILS83a].)

3.  Problems with MIL Standard IP

   One of the major functions of IP is the fragmentation of datagrams
   that cannot be transmitted over a subnetwork in one piece, and their
   subsequent reassembly.  The specification has several problems in
   this area.  One of the most significant is the failure to insert the
   last fragment of an incoming datagram; this would cause datagrams to
   be delivered to the upper-level protocol (ULP) with some data
   missing. Another error in this area is that an incorrect value of the
   data length for reassembled datagrams is passed to the ULP, with
   unpredictable consequences.

   As the specification [MILS83a] is now written, these errors are of


Sidhu                                                           [Page 2]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


   little consequence, since the test for reassembly completion will
   always fail, with the result that reassembled datagrams would never
   be delivered at all.

   In addition, a missing row in one of the decision tables creates the
   problem that network control (ICMP) messages that arrive in fragments
   will never be processed.  Among the other errors are the possibility
   that a few bytes will be discarded from each fragment transmitted and
   certain statements that will create run-time exceptions instead of
   performing their intended functions.

   A general problem with this specification is that the program
   language and action table portions of the specification were clearly
   not checked by any automatic syntax checking process.  Variable and
   procedure names are occasionally misspelled, and the syntax of the
   action statements is often incorrect.  We have enumerated some of
   these problems below as a set of cautionary notes to implementors,
   but we do not claim to have listed them all.  In particular, syntax
   errors are only discussed when they occur in conjunction with other
   problems.

   The following section discusses some of the serious errors that we
   have discovered with the MIL standard IP [MIL83a] during our initial
   study of this protocol.  We also propose corrections to each of these
   problems.

4.  Detailed Discussion of the Problems

   Problem 1: Failure to Insert Last Fragment

      This problem occurs in the decision table corresponding to the
      state reassembling and the input "receive from lower layer"
      [MILS83a, sec 9.4.6.1.3].  The problem occurs in the following row
      of this table:[2]

      ________________________________________________________
      check-    SNP      TTL    where    a     reass    ICMP
       sum     params   valid    to     frag   done    check-
      valid?   valid?     ?       ?      ?       ?      sum?
      __________________________________________________________________
      YES      YES      YES     ULP    YES     YES      d      reass_
                                                               delivery;
                                                               state :=
                                                                INACTIVE
      __________________________________________________________________

      The reass_done function, as will be seen below, returns YES if the


Sidhu                                                           [Page 3]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      fragment just received is the last fragment needed to assemble a
      complete datagram and NO otherwise.  The action procedure
      reass_delivery simply delivers a completely reassembled datagram
      to the upper-level protocol.  It is the action procedure
      reassemble that inserts an incoming fragment into the datagram
      being assembled.  Since this row does not call reassemble, the
      result will be that every incoming fragmented datagram will be
      delivered to the upper layer with one fragment missing.  The
      solution is to rewrite this row of the table as follows:

      ________________________________________________________
      check-    SNP      TTL    where    a     reass    ICMP
       sum     params   valid    to     frag   done    check-
      valid?   valid?     ?       ?      ?       ?      sum?
      __________________________________________________________________
      YES      YES      YES     ULP    YES     YES      d    reassemble;
                                                               reass_
                                                               delivery;
                                                               state :=
                                                                INACTIVE
      __________________________________________________________________

      Incidentally, the mnemonic value of the name of the reass_done
      function is questionable, since at the moment this function is
      called datagram reassembly cannot possibly have been completed.  A
      better name for this function might be last_fragment.

   Problem 2: Missing State Transition

      This problem is the omission of a row of the same decision table
      [MILS83a, sec 9.4.6.1.3].  Incoming packets may be directed to an
      upper-level protocol (ULP), or they may be network control
      messages, which are marked ICMP (Internet Control Message
      Protocol).  When control messages have been completely assembled,
      they are processed by an IP procedure called analyze.  The
      decision table contains the row

      ________________________________________________________
      check-    SNP      TTL    where    a     reass    ICMP
       sum     params   valid    to     frag   done    check-
      valid?   valid?     ?       ?      ?       ?      sum?
      __________________________________________________________________
      YES      YES      YES    ICMP    YES     NO       d    reassemble;
      __________________________________________________________________





Sidhu                                                           [Page 4]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      but makes no provision for the case in which where_to returns
      ICMP, a_frag returns YES, and reass_done returns YES.  An
      additional row should be inserted, which reads as follows:

      ________________________________________________________
      check-    SNP      TTL    where    a     reass    ICMP
       sum     params   valid    to     frag   done    check-
      valid?   valid?     ?       ?      ?       ?      sum?
      __________________________________________________________________
      YES      YES      YES    ICMP    YES     YES      d    reassemble;
                                                               analyze;
                                                               state :=
                                                                INACTIVE
      __________________________________________________________________

      Omitting this row means that incoming fragmented ICMP messages
      will never be analyzed, since the state machine does not have any
      action specified when the last fragment is received.

   Problem 3: Errors in reass_done

      The function reass_done, as can be seen from the above, determines
      whether the incoming subnetwork packet contains the last fragment
      needed to complete the reassembly of an IP datagram.  In order to
      understand the errors in this function, we must first understand
      how it employs its data structures.

      The reassembly of incoming fragments is accomplished by means of a
      bit map maintained separately for each state machine.  Since all
      fragments are not necessarily the same length, each bit in the map
      represents not a fragment, but a block, that is, a unit of eight
      octets.  Each fragment, with the possible exception of the "tail"
      fragment (we shall define this term below), is an integral number
      of consecutive blocks. Each fragment's offset from the beginning
      of the datagram is given, in units of blocks, by a field in the
      packet header of each incoming packet.  The total length of each
      fragment, including the fragment's header, is specified in the
      header field total_length; this length is given in octets.  The
      length of the header is specified in the field header_length; this
      length is given in words, that is, units of four octets.

      In analyzing this subroutine, we must distinguish between the
      "tail" fragment and the "last" fragment.  We define the last
      fragment as the one which is received last in time, that is, the
      fragment that permits reassembly to be completed.  The tail
      fragment is the fragment that is spatially last, that is, the
      fragment that is spatially located after any other fragment.  The


Sidhu                                                           [Page 5]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      length and offset of the tail fragment make it possible to compute
      the length of the entire datagram.  This computation is actually
      done in the action procedure reassembly, and the result is saved
      in the state vector field total_data_length; if the tail fragment
      has not been received, this value is assumed to be zero.

      It is the task of the reass_done function [MILS83a, sec 9.4.6.2.6]
      to determine whether the incoming fragment is the last fragment.
      This determination is made as follows:

         1) If the tail fragment has not been received previously and
         the incoming fragment is not the tail fragment, then return NO.

         2) Otherwise, if the tail fragment has not been received, but
         the incoming fragment is the tail fragment, determine whether
         all fragments spatially preceding the tail fragment have also
         been received.

         3) Otherwise, if the tail fragment has been received earlier,
         determine whether the incoming fragment is the last one needed
         to complete reassembly.

      The evaluation of case (2) is accomplished by the following
      statment:

         if (state_vector.reassembly_map from 0 to
           (((from_SNP.dtgm.total_length -
               (from_SNP.dtgm.header_length * 4) + 7) / 8)
           + 7) / 8 is set)
         then return YES;

      The double occurrence of the subexpression " + 7 ) / 8" is
      apparently a misprint.  The function f(x) = (x + 7) / 8 will
      convert x from octets to blocks, rounding any remainder upward.
      There is no need for this function to be performed twice.  The
      second problem is that the fragment_offset field of the incoming
      packet is ignored.  The tail fragment specifies only its own
      length, not the length of the entire datagram; to determine the
      latter, the tail fragment's offset must be added to the tail
      fragment's own length.  The third problem hinges on the meaning of
      the English "... from ... to ..." phrase.  If this phrase has the
      same meaning as the ".." range indication in Ada [ADA83, sec 3.6],
      that is, includes both the upper and lower bounds, then it is
      necessary to subtract 1 from the final expression.

      The expression following the word to, above, should thus be
      changed to read


Sidhu                                                           [Page 6]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


         from_SNP.dtgm.fragment_offset +
             ((from_SNP.dtgm.total_length -
                 (from_SNP.dtgm.header_length * 4) + 7) / 8) - 1

      Another serious problem with this routine occurs when evaluating
      case (3).  In this case, the relevant statement is

         if (all reassembly map from 0 to
           (state_vector.total_data_length + 7)/8 is set
         then return YES

      If the tail fragment was received earlier, the code asks, in
      effect, whether all the bits in the reassembly map have been set.
      This, however, will not be the case even if the incoming fragment
      is the last fragment, since the routine reassembly, which actually
      sets these bits, has not yet been called for this fragment.  This
      statement must therefore skip the bits corresponding to the
      incoming fragment.  In specifying the range to be tested,
      allowance must be made for whether these bits fall at the
      beginning of the bit map or in the middle (the case where they
      fall at the end has already been tested). The statement must
      therefore be changed to read

         if from_SNP.dtgm.fragment_offset = 0 then
           if (all reassembly map from
             from_SNP.dtgm.fragment_offset +
               ((from_SNP.dtgm.total_length -
                 from_SNP.dtgm.header_length * 4) + 7) / 8
             to ((state_vector.total_data_length + 7) / 8 - 1) is set)
           then return YES;
           else return NO;
           end if;

           else
           if (all reassembly map from 0 to
             (from_SNP.dtgm.fragment_offset - 1) is set)
             and (all reassembly map from
               from_SNP.dtgm.fragment_offset +
                 ((from_SNP.dtgm.total_length -
                   from_SNP.dtgm.header_length * 4) + 7) / 8
               to ((state_vector.total_data_length + 7) / 8 - 1) is set)
           then return YES;
           else return NO;
           end if;
           end if;




Sidhu                                                           [Page 7]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      Note that here again it is necessary to subtract 1 from the upper
      bound.

   Problem 4: Errors in fragment_and_send

      The action procedure fragment_and_send [MILS83a, sec 9.4.6.3.7] is
      used to break up datagrams that are too large to be sent through
      the subnetwork as a single packet.  The specification requires
      [MILS83a sec 9.2.2, sec 9.4.6.3.7] each fragment, except possibly
      the "tail" fragment, to contain a whole number of 8-octet groups
      (called "blocks"); moreover, each fragment must begin at a block
      boundary.

      In the algorithm set forth in fragment_and_send, all fragments
      except the tail fragment are set to the same size; the procedure
      begins by calculating this size.  This is done by the following
      statement:

         data_per_fragment := maximum subnet transmission unit
                                - (20 + number of bytes of option data);

      Besides the failure to allow for header padding, which is
      discussed in the next section, this statement makes the serious
      error of not assuring that the result is an integral multiple of
      the block size, i.e., a multiple of eight octets.  The consequence
      of this would be that as many as seven octets per fragment would
      never be sent at all. To correct this problem, and to allow for
      header padding, this statement must be changed to

         data_per_fragment := (maximum subnet transmission unit
                  - (((20 + number of bytes of option data)+3)/4*4)/8*8;

      Another problem in this procedure is the failure to provide for
      the case in which the length of the data is an exact multiple of
      eight.  The procedure contains the statements

         number_of fragments := (from_ULP.length +
                           (data_per_fragment - 1)) / data_per_fragment;

         data_in_last_frag := from_ULP.length modulo data_per_fragment;

      (Note that in our terminology we would rename data_in_last_frag as
      data_in_tail_frag; notice, also, that the proper spelling of the
      Ada operator is mod [ADA83, sec 4.5.5].)

      If data_in_last_frag is zero, some serious difficulties arise.
      One result might be that the datagram will be broken into one more


Sidhu                                                           [Page 8]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      fragment than necessary, with the tail fragment containing no data
      bytes.  The assignment of data into the tail fragment will succeed
      even though it will now take the form

         output_data [i..i-1] := input_data [j..j-1];

      because Ada makes provision for so-called "null slices" [ADA83,
      sec 4.1.2] and will treat this assignment as a no-op [ADA83, sec
      5.2.1].

      This does, however, cause the transmission of an unnecessary
      packet, and also creates difficulties for the reassembly
      procedure, which must now be prepared to handle empty packets, for
      which not even one bit of the reassembly map should be set.
      Moreover, as the procedure is now written, even this will not
      occur.  This is because the calculation of the number of fragments
      is incorrect.

      A numerical example will clarify this point.  Suppose that the
      total datagram length is 16 bytes and that the number of bytes per
      fragment is to be 8.  Then the above statements will compute
      number_of_fragments = (16 + 7)/8 = 2 and data_in_last_frag = 16
      mod 8 = 0.  The result of the inconsistency between
      number_of_fragments and data_in_last_frag will be that instead of
      sending three fragments, of lengths 8, 8, and 0, the procedure
      will send only two fragments, of lengths 8 and 0; the last eight
      octets will never be sent.

      To avoid these difficulties, the specification should add the
      following statement, immediately after computing
      data_in_last_frag:

         if data_in_last_frag = 0 then
                                 data_in_last_frag := data_per_fragment;
         end if;

      This procedure also contains several minor errors.  In addition to
      failures to account for packet header padding, which are
      enumerated in the next section, there is a failure to convert the
      header length from words (four octets) to octets in one statement.
      This statement, which calculates the total length of the non-tail
      fragments, is

         to_SNP.dtgm.total_length := to_SNP.dtgm.header_length
                                                    + data_per_fragment;




Sidhu                                                           [Page 9]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      Since header length is expressed  in  units  of  words,  this
      statement should read

         to_SNP.dtgm.total_length := to_SNP.dtgm.header_length * 4
                                                    + data_per_fragment;

      This is apparently no more than a misprint, since the
      corresponding calculation for the tail fragment is done correctly.

   Problem 5: Errors in reassembly

      The action procedure reassembly [MILS83a, sec 9.4.6.3.9], which is
      referred to as reassemble elsewhere in the specification [MILS83a,
      sec 9.4.6.1.2, sec 9.4.6.1.3], inserts an incoming fragment into a
      datagram being reassembled.  This procedure contains several
      relatively minor errors.

      In two places in this procedure, a range is written to contain one
      more member than it ought to have.  In the first, data from the
      fragment is to be inserted into the datagram being reassembled:

         state_vector.data [from_SNP.dtgm.fragment_offset*8 ..
             from_SNP.dtgm.fragment_offset*8 + data_in_frag] :=
                     from_SNP.dtgm.data [0..data_in_frag-1];

      In this statement, the slice on the left contains one more byte
      than the slice on the right.  This will cause a run-time exception
      to be raised [ADA83, sec 5.2.1].  The statement should read

         state_vector.data [from_SNP.dtgm.fragment_offset*8 ..
             from_SNP.dtgm.fragment_offset*8 + data_in_frag - 1] :=
                     from_SNP.dtgm.data [0..data_in_frag-1];

      A similar problem occurs in the computation of the range of bits
      in the reassembly map that corresponds to the incoming fragment.
      This statement begins

         for j in (from_SNP.dtgm.fragment_offset) ..
                  ((from_SNP.dtgm.fragment_offset +
                 data_in_frag + 7)/8) loop

      Not only are the parentheses in this statement located incorrectly
      (because the function f(x) = (x + 7) / 8 should be executed only
      on the argument data_in_frag), but also this range contains one
      extra member.  The statement should read




Sidhu                                                          [Page 10]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


         for j in (from_SNP.dtgm.fragment_offset) ..
                  (from_SNP.dtgm.fragment_offset +
                 (data_in_frag + 7)/8) - 1 loop

      Note that if the statement is corrected in this manner it will
      also handle the case of a zero-length fragment, mentioned above,
      since the loop will not be executed even once [ADA83, sS 5.5].

      Another minor problem occurs when this procedure attempts to save
      the header of the leading fragment.  The relevant statement is

         state_vector.header := from_SNP.dtgm;

      This statement attempts to transfer the entire incoming fragment
      into a record that is big enough to contain only the header.  The
      result, in Ada, is not truncation, but a run-time exception
      [ADA83, sec 5.2]. The correction should be something like

         state_vector.header := from_SNP.dtgm.header;

      This correction cannot be made without also defining the header
      portion of the datagram as a subrecord in [MILS83a, sec 9.4.4.6];
      such a definition would also necessitate changing many other
      statements. For example, from_SNP.dtgm.fragment_offset would now
      have to be written as from_SNP.dtgm.header.fragment_offset.
      Another possible solution is to write the above statement as a
      series of assignments for each field in the header, in the
      following fashion:

         state_vector.header.version :=
                                                  from_SNP.dtgm.version;
         state_vector.header.header_length :=
                                            from_SNP.dtgm.header_length;
         state_vector.header.type_of_service :=
                                          from_SNP.dtgm.type_of_service;

         -- etc.

      Note also that this procedure will fail if an incoming fragment,
      other than the tail fragment, does not contain a multiple of eight
      characters.  Implementors must be careful to check for this in the
      decision function SNP_params_valid [MILS83a, sec 9.4.6.2.7].







Sidhu                                                          [Page 11]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


   Problem 6: Incorrect Data Length for Fragmented Datagrams

      The procedure reassembled_delivery [MILS83a, sec 9.4.6.3.10] does
      not deliver the proper data length to the upper-level protocol.
      This is because the assignment is

         to_ULP.length := state_vector.header.total_length
                                - state_vector.header.header_length * 4;

      The fields in state_vector.header have been filled in by the
      reassembly procedure, discussed above, by copying the header of
      the leading fragment.  The field total_length in this fragment,
      however, refers only to this particular fragment, and not to the
      entire datagram (this is not entirely clear from it definition in
      [MILS83a, sec 9.3.4], but the fragment_and_send procedure
      [MILS83a, sec 9.4.6.3.7] insures that this is the case).

      The length of the entire datagram can only be computed from the
      length and offset of the tail fragment.  This computation is
      actually done in the reassembly procedure [MILS83a, sec
      9.4.6.3.9], and the result saved in state_vector.total_data_length
      (see above).  It is impossible, however, for reassembly to fill in
      state_vector.header.total_length at this time, because
      state_vector.header.header_length is filled in from the lead
      fragment, which may not yet have been received.

      Therefore, reassembled_delivery must replace the above statement
      with

         to_ULP.length := state_vector.total_data_length;

      The consequence of leaving this error uncorrected is that the
      upper-level protocol will be informed only of the delivery of as
      many octets as there are in the lead fragment.

5.  Implementation Difficulties of MIL Standard IP

   In addition to the problems discussed above, there are several
   features of the MIL standard IP specification [MILS83a] which lead to
   difficulties for the implementor.  These difficulties, while not
   actually errors in the specification, take the form of assumptions
   which are not explicitly stated, but of which implementors must be
   aware.






Sidhu                                                          [Page 12]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


   5.1  Header Padding

      In several places, the specification makes a computation of the
      length of a packet header without explicitly allowing for padding.
      The padding is needed because the specification requires [MILS83a,
      sec 9.3.14] that each header end on a 32-bit boundary.

      One place this problem arises is in the need_to_frag decision
      function [MILS83a, sec 9.4.6.2.5].  This function is used to
      determine whether fragmentation is required for an outgoing
      datagram. It consists of the single statement

         if ((from_ULP.length + (number of bytes of option data)
               + 20) > maximum transmission unit of the local subnetwork
         then return YES
         else return NO;
         end if;

      (A minor syntax error results from not terminating the first
      return statement with a semicolon [ADA83, sec 5.1, sec 5.3, sec
      5.9].) In order to allow for padding, the expression for the
      length of the outgoing datagram should be

         (((from_ULP.length + (number of bytes of option data) + 20)
                                                             + 3)/4 * 4)

      Another place that this problem arises is in the action procedure
      build_and_send [MILS83a, sec 9.4.6.3.2], which prepares
      unfragmented datagrams for transmission.  To compute the header
      field header_length, which is expressed in words, i.e., units of
      four octets [MILS83a, sec 9.3.2], this procedure contains the
      statement

         to_SNP.dtgm.header_length := 5 +
                                     (number of bytes of option data)/4;

      In order to allow for padding, this statement should read

         to_SNP.dtgm.header_length :=
                             5 + ((number of bytes of option data)+3)/4;

      The identical statement appears in the action procedure
      fragment_and_send [MILS83a, sec 9.4.6.3.7], which prepares
      datagram fragments for transmission, and requires the same
      correction.




Sidhu                                                          [Page 13]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      The procedure fragment_and_send also has this problem in two other
      places.  In the first, the number of octets in each fragment is
      computed by

         data_per_fragment := maximum subnet transmission unit
                                - (20 + number of bytes of option data);

      In order to allow for padding, this statement should read

         data_per_fragment := maximum subnet transmission unit
                      - (((20 + number of bytes of option data)+3)/4*4);

      (Actually, this statement must be changed to

         data_per_fragment := (maximum subnet transmission unit
                  - (((20 + number of bytes of option data)+3)/4*4)/8*8;

      in order to accomplish its intended purpose, for reasons which
      have been discussed above.)

      A similar problem occurs in the statement which computes the
      header length for individual fragments:

         to_SNP.dtgm.header_length := 5 +
                                      (number of copy options octets/4);

      To allow for padding, this should be changed to

         to_SNP.dtgm.header_length := 5 +
                                    (number of copy options octets+3/4);

      Notice that all of these errors can also be corrected if the
      English phrase "number of bytes of option data", and similar
      phrases, are always understood to include any necessary padding.

   5.2  Subnetworks with Small Transmission Sizes

      When an outgoing datagram is too large to be transmitted as a
      single packet, it must be fragmented.  On certain subnetworks, the
      possibility exists that the maximum number of bytes that may be
      transmitted at a time is less than the size of an IP packet header
      for a given datagram.  In this case, the datagram cannot be sent,
      even in fragmented form.  Note that this does not necessarily mean
      that the subnetwork cannot send any datagrams at all, since the
      size of the header may be highly variable.  When this problem
      arises, it should be detected by IP.  The proper place to detect
      this situation is in the function can_frag.


Sidhu                                                          [Page 14]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


      The can_frag decision function [MILS83a, sec 9.4.6.2.2] is used to
      determine whether a particular outgoing datagram, which is too
      long to be transmitted as a single fragment, is allowed to be
      fragmented. In the current specification, this function consists
      of the single statement

         if (from_ULP.dont_fragment = TRUE)
         then return NO
         else return YES
         end if;

      (A minor syntax error is that the return statements should be
      terminated by semicolons; see [ADA83, sec 5.1, sec 5.3, sec 5.9].)

      If the above problem occurs, the procedure fragment_and_send will
      obtain negative numbers for fragment sizes, with unpredictable
      results.  This should be prevented by assuring that the subnetwork
      can send the datagram header and at least one block (eight octets)
      of data.  The can_frag function should be recoded as

         if ((8 + ((number of bytes of option data)+3)/4*4 + 20)
                    > maximum transmission unit of the local subnetwork)
         then return NO;
         elsif (from_ULP.dont_fragment = TRUE)
         then return NO
         else return YES
         end if;

      This is similar to the logic of the function need_to_frag,
      discussed above.

   5.3  Subnetwork Interface

      Provision is made for the subnetwork to report errors to IP
      [MILS83a, sec 6.3.6.2], but no provision is made for the IP entity
      to take any action when such errors occur.

      In addition, the specification [MILS83a, sec 8.2.1.1] calls for
      the subnetwork to accept type-of-service indicators (precedence,
      reliability, delay, and throughput), which may be difficult to
      implement on many local networks.








Sidhu                                                          [Page 15]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


   5.4  ULP Errors

      The IP specification [MILS83a, sec 9.4.6.3.6] states

         The format of error reports to a ULP is implementation
         dependent. However, included in the report should be a value
         indicating the type of error, and some information to identify
         the associated data or datagram.

      The most natural way to provide the latter information would be to
      return the datagram identifier to the upper-level protocol, since
      this identifier is normally supplied by the sending ULP [MILS83a,
      sec 9.3.5].  However, the to_ULP data structure makes no provision
      for this information [MILS83a, sec 9.4.4.3], probably because this
      information is irrelevant for datagrams received from the
      subnetwork. Implementors may feel a need to add this field to the
      to_ULP data structure.

   5.5  Initialization of Data Structures

      The decision function reass_done [MILS83a, sec 9.4.6.2.6] makes
      the implicit assumption that data structures within each finite
      state machine are initialized to zero when the machine is created.
      In particular, this routine will not function properly unless
      state_vector.reassembly_map and state_vector.total_data_length are
      so initialized.  Since this assumption is not stated explicitly,
      implementors should be aware of it.  There may be other
      initialization assumptions that we have not discovered.

   5.6  Locally Defined Types

      The procedures error_to_source [MILS83a, sec 9.4.6.3.5] and
      error_to_ULP [MILS83a, sec 9.4.6.3.6] define enumeration types in
      comments.  The former contains the comment

         error_param : (PARAM_PROBLEM, EXPIRED_TTL, PROTOCOL_UNREACH);

      and the latter

         error_param : (PARAM_PROBLEM, CAN'T_FRAGMENT, NET_UNREACH,
                                        PROTOCOL_UNREACH, PORT_UNREACH);

      These enumerated values are used before they are encountered
      [MILS83a, sec 9.4.6.1.1, sec 9.4.6.1.2, sec 9.4.6.1.3, et al.];
      implementors will probably wish to define some error type
      globally.



Sidhu                                                          [Page 16]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


   5.7  Miscellaneous Difficulties

      The specification contains many Ada syntax errors, some of which
      have been shown above.  We have only mentioned syntax errors
      above, however, when they occurred in conjunction with other
      problems.  One of the main syntactic difficulties that we have not
      mentioned is that the specification frequently creates unnamed
      types, by declaring records within records; such declarations are
      legal in Pascal, but not in Ada [ADA83, sec 3.7].

      Another problem is that slice assignments frequently do not
      contain the same number of elements on the left and right sides,
      which will raise a run-time exception [ADA83, sec 5.2.1].  While
      we have mentioned some of these, there are others which are not
      enumerated above.

      In particular, the procedure error_to_source [MILS83a, sec
      9.4.6.3.5] contains the statement

         to_SNP.dtgm.data [8..N+3] := from_SNP.dtgm.data [0..N-1];

      We believe that N+3 is a misprint for N+8, but even so the left
      side contains one more byte than the right.  Implementors should
      carefully check every slice assignment.

6.  An Implementation of MIL Standard IP

   In our discussion above, we have pointed out several serious problems
   with the Military Standard IP [MILS83a] specification which must be
   corrected to produce a running implementation conforming to this
   standard.  We have produced a running C implementation for the MIL
   Standard IP, after problems discussed above were fixed in the IP
   specification.  An important feature of this implementation is that
   it was generated semi-automatically from the IP specification with
   the help of a protocol development system [BLUT82] [BLUT83] [SIDD83].
   Since this implementation was derived directly from the IP
   specification with the help of tools, it conforms to the IP standard
   better that any handed-coded IP implementation can do.

   The problems pointed out in this paper with the current specification
   of the MIL Standard IP [MILS83a] are based on an initial
   investigation of the protocol.







Sidhu                                                          [Page 17]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


NOTES

   [1] Ada is a registered trademark of the U.S. Government - Ada Joint
   Program Office.

   [2] d indicates a "don't care" condition.

ACKNOWLEDGEMENTS

   The author extends his gratitude to Tom Blumer Michael Breslin, Bob
   Pollack and Mark J. Vincenzes, for many helpful discussions.  Thanks
   are also due to B. Simon and M. Bernstein for bringing to author's
   attention a specification of the DoD Internet Protocol during 1981-82
   when a detailed study of this protocol began.  The author is also
   grateful to Jon Postel and Carl Sunshine for several informative
   discussions about DoD IP/TCP during the last few years.

REFERENCES

   [ADA83]   Military Standard Ada(R) Programming Language, United
             States Department of Defense, ANSI/MIL-STD-1815A-1983, 22
             January 1983

   [BLUT83]  Blumer, T. P., and Sidhu, D. P., "Mechanical Verification
             and Automatic Implementation of Communication Protocols,"
             to appear in IEEE Trans. Softw. Eng.

   [BLUT82]  Blumer, T. P., and Tenney, R. L., "A Formal Specification
             Technique and Implementation Method for Protocols,"
             Computer Networks, Vol. 6, No. 3, July 1982, pp. 201-217.

   [MILS83a] "Military Standard Internet Protocol," United States
             Department of Defense, MIL-STD-1777, 12 August 1983.

   [MILS83b] "Military Standard Transmission Control Protocol," United
             States Department of Defense, MIL-STD-1778, 12 August 1983.

   [POSJ81]  Postel, J. (ed.), "DoD Standard Internet Protocol," Defense
             Advanced Research Projects Agency, Information Processing
             Techniques Office, RFC-791, September 1981.

   [SDC82]   DCEC Protocol Standardization Program: Protocol
             Specification Report, System Development Corporation,
             TM-7172/301/00, 29 March 1982

   [SIDD83]  Sidhu, D. P., and Blumer, T. P., "Verification of NBS Class
             4 Transport Protocol," to appear in IEEE Trans. Comm.


Sidhu                                                          [Page 18]
^L


RFC 963                                                    November 1985
Some Problems with MIL-STD IP


   [SIDD84]  Sidhu, D. P., and Blumer, T. P., "Some Problems with the
             Specification of the Military Standard Transmission Control
             Protocol," in Protocol Specification, Testing and
             Verification IV, (ed.) Y. Yemini et al (1984).













































Sidhu                                                          [Page 19]
^L