home *** CD-ROM | disk | FTP | other *** search
/ PC Press: Internet / PC_PRESS.ISO / software / dos / misc / inar-100.exe / SRC / PCROUTE / IP.INC < prev    next >
Encoding:
Text File  |  1995-05-21  |  34.7 KB  |  1,128 lines

  1. ;;************************************************************************* 
  2. ;;                         ip.inc       ip.inc
  3. ;;*************************************************************************
  4. ;;
  5. ;;  Copyright (C) 1989 Northwestern University, Vance Morrison
  6. ;;
  7. ;;
  8. ;; Permission to view, compile, and modify for LOCAL (intra-organization) 
  9. ;; USE ONLY is hereby granted, provided that this copyright and permission 
  10. ;; notice appear on all copies.  Any other use by permission only.
  11. ;;
  12. ;; Northwestern University makes no representations about the suitability 
  13. ;; of this software for any purpose.  It is provided "as is" without expressed 
  14. ;; or implied warranty.  See the copywrite notice file for complete details.
  15. ;;
  16. ;;*****************************************************************************
  17. ;;
  18. ;; Routines provided by this module
  19. ;;
  20. ;;   IP_DECLARE name, router, dls, icmp
  21. ;;   IP_DEFINE name
  22. ;;   IP_R_READ name, proto, code_label
  23. ;;   IP_R_RETURN name
  24. ;;   IP_R_SRC_in_ES_out_AX_BX_const_CX_DX_BP_SI_DI_ES name
  25. ;;   IP_R_DST_in_ES_out_AX_BX_const_CX_DX_BP_SI_DI_ES name
  26. ;;   IP_R_BROAD_const_AX_BX_CX_DX_BP_SI_DI_ES name, broadcast
  27. ;;   IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
  28. ;;   IP_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES name
  29. ;;   IP_W_WRITE_in_CX name
  30. ;;   IP_COMP_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES
  31. ;;   IP_SET_SRC_in_AX_BX_const_AX_BX_CX_DX_BP_SI_DI_ES name
  32. ;;
  33. ;;  Variables Provided by this Module (READ ONLY!!!)
  34. ;;
  35. ;;  ip_&name&_dls           ;; 1..dls are the names of the IP_DL objects
  36. ;;
  37. ;;*****************************************************************************
  38.  
  39. ;; IP packet header def
  40.  
  41. ;; masks for the Flag field
  42. IP_DONT_FRAG    = 4000H
  43. IP_MORE_FRAG    = 2000H
  44. SWAPPED_IP_DONT_FRAG    = 40H
  45. SWAPPED_IP_MORE_FRAG    = 20H
  46. SWAPPED_IP_IS_FRAG      = 0FF3FH
  47. SWAPPED_IP_FRAG_OFFSET  = 0FF1FH
  48.  
  49. ip      STRUC               ;; and IP packet
  50.     ip_ver_size     DB ?
  51.     ip_tos          DB ?
  52.     ip_length       DW ?
  53.     ip_id           DW ?
  54.     ip_frag         DW ?
  55.     ip_ttl          DB ?
  56.     ip_proto        DB ?
  57.     ip_check        DW ?
  58.     ip_src          DD ?
  59.     ip_dst          DD ?
  60. ip  ENDS
  61.  
  62.  
  63. ip_data  STRUC
  64.     ip_write_dst    DD ?
  65.     ip_write_src    DD ?
  66.     ip_write_off    DW ?
  67.     ip_write_seg    DW ?
  68.     ip_write_gate   DD ?
  69.     ip_write_proto  DB ?
  70.     ip_write_dl     DB ?
  71.     ip_write_id     DW ?
  72.     ip_packet       DW (dl_ip_max_mtu/2 + 16) dup (0)
  73.     ip_header       DW 32 dup (0)
  74.  
  75.     ip_broadcast    DB ?
  76.     ip_read_head    DW ?
  77.     ip_read_jmp     DW 32 dup (0)
  78. ip_data  ENDS
  79.  
  80.  
  81. ;;******************************************************************************
  82. ;;   IP_DECLARE   name, dls 
  83. ;;      IP_DECLARE declares a network ojbect that will route packets
  84. ;;      using 'router' as its routing table to the Data Link objects
  85. ;;      1..dls.  
  86. ;;
  87. IP_DECLARE MACRO name, router, dls, icmp
  88.  
  89.     .DATA
  90.     ip_&name&_dls = dls
  91.     ip_&name&_router = router
  92.     ip_&name&_icmp = icmp
  93.     global ip_&name&_data:ip_data
  94.  
  95.     .CODE
  96.     IRP idx, <1,2,3,4,5,6,7,8>
  97.     if idx le ip_&name&_dls
  98.         IP_DECLARE_HELPER name, idx
  99.     endif
  100.     endm
  101.  
  102.     global ip_&name&_read_packet:near
  103.     global ip_&name&_prot_unreach:near
  104.     global ip_&name&_w_access:near
  105.     global ip_&name&_w_write:near
  106.     global ip_&name&_real_define:near
  107.     global route_&name&_real_find:near
  108. ENDM
  109.  
  110. IP_DECLARE_HELPER MACRO name, dl
  111.     global ip_&name&_dl_&dl&_read_start:near
  112. ENDM
  113.  
  114.  
  115. ;;*****************************************************************************
  116. ;;   IP_DEFINE name
  117. ;;       IP_DEFINE defines all of the data structures needed by IP and
  118. ;;       initializes them.
  119. ;;
  120. IP_DEFINE MACRO name
  121.     call ip_&name&_real_define
  122. ENDM
  123.  
  124. IFDEF IP_REAL_DEFINE_NEEDED
  125. IP_REAL_DEFINE MACRO name
  126.     local around, skip
  127.     .errb <name>
  128.  
  129. ifdef ip_&name&_dls
  130.  
  131.     .DATA
  132. ip_&name&_data   ip_data  <>
  133.  
  134.     .CODE
  135.     ip_&name&_real_define:
  136.     jmp around                  ;; declare the 'this node' IP packet processor
  137.         ip_&name&_read_packet:
  138.             IP_PACKET_in_BX_CX_ES name
  139.             RET 
  140.  
  141.         ip_&name&_prot_unreach:
  142.             IP_R_BROAD_const_AX_BX_CX_DX_BP_SI_DI_ES name, skip
  143.             IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
  144.             ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_UNREACHABLE, ICMP_UNREACH_PROTO, name
  145.             skip:
  146.             RET
  147.  
  148.         ip_&name&_w_access:
  149.             IP_REAL_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES name
  150.             RET
  151.  
  152.         ip_&name&_w_write:
  153.             IP_REAL_W_WRITE_in_CX name, %ip_&name&_w_write
  154.             RET
  155.  
  156.         route_&name&_real_find:
  157.             ROUTE_REAL_FIND_in_AX_BX_SI_DI_out_AX_BX_DX_DI_const_CX_BP_ES name
  158.             RET
  159.     around:
  160.         ;; initialize the jump table
  161.     mov AX, DS                              ;; initialize jump table
  162.     mov ES, AX
  163.     mov DI, offset ip_&name&_data.ip_read_jmp
  164.     mov AX, offset ip_&name&_prot_unreach
  165.     mov CX, 32
  166.     rep
  167.     stosw
  168.  
  169.         ;; do all per DL initilization
  170.     IRP idx, <1,2,3,4,5,6,7,8>
  171.     if idx le ip_&name&_dls
  172.         IP_INIT_DL name, idx
  173.     endif
  174.     endm
  175.  
  176.     RET
  177. endif
  178. ENDM
  179. ENDIF ; IP_REAL_DEFINE_NEEDED
  180.  
  181.  
  182. ;;*****************************************************************************
  183. ;; IP_R_READ name, proto, code_label
  184. ;;      IP_READ declares that the code starting at 'code_label' should
  185. ;;      be called when a IP packet with protocol 'proto' is read in
  186. ;;      The data in the IP packet is passed to the object in BX:ES the 
  187. ;;      protocol type in AX and the length of the data in CX. 
  188. ;;      When the code is done it should execute a RET instruction
  189. ;;      If the source address is requires IP_R_SRC should be called
  190. ;;
  191. IP_R_READ MACRO name, proto, code_label
  192.    .errb <code_label>
  193.  
  194.     if proto ge 32
  195.         .err
  196.         %out IP protocol out of range
  197.     endif
  198.     mov word ptr ip_&name&_data.ip_read_jmp+2*(proto), offset code_label
  199. ENDM
  200.  
  201. ;;*****************************************************************************
  202. ;; IP_R_SRC_in_ES_out_AX_BX name
  203. ;;      IP_R_SRC returns the source of the IP data packet in segment ES
  204. ;;      that was given to the IP_R_READ routine.  The IP address is put in
  205. ;;      AX,BX
  206. ;;
  207. IP_R_SRC_in_ES_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO name
  208.    .errb <name>
  209.  
  210.    push SI
  211.    IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
  212.    add SI, ip_src
  213.    mov AX, word ptr ES:[SI]
  214.    mov BX, word ptr ES:[SI+2]
  215.    pop SI
  216. ENDM
  217.  
  218. ;;*****************************************************************************
  219. ;; IP_R_DST_in_ES_out_AX_BX name
  220. ;;      IP_R_DST returns the destination of the IP data packet in segment
  221. ;;      ES that was given to the IP_R_READ routine.  The IP address is
  222. ;;      put in AX,BX.
  223. ;;
  224. IP_R_DST_in_ES_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO name
  225.    .errb <name>
  226.  
  227.    push SI
  228.    IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
  229.    add SI, ip_dst
  230.    mov AX, word ptr ES:[SI]
  231.    mov BX, word ptr ES:[SI+2]
  232.    pop SI
  233. ENDM
  234.  
  235. ;;*****************************************************************************
  236. ;; IP_R_BROAD name, broadcast
  237. ;;      IP_R_BROAD jumps to 'broadcast' if the current IP packet is a
  238. ;;      broadcast.  
  239. ;;
  240. IP_R_BROAD_const_AX_BX_CX_DX_BP_SI_DI_ES MACRO name, broadcast
  241.    .errb <name>
  242.  
  243.     cmp ip_&name&_data.ip_broadcast, 0
  244.     jnz broadcast
  245. ENDM
  246.  
  247. ;;*****************************************************************************
  248. ;;   IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
  249. ;; IP_R_HEADER_in_SI_ES_out_DI returns the IP header for the packet pointed
  250. ;; to by SI:ES.  This routine must only be called in the routine specified
  251. ;; in R_READ.  (this is meant so that you can send ICMP packets)
  252. ;;
  253. IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES MACRO name
  254.    .errb <name>
  255.  
  256.     mov SI, word ptr ip_&name&_data.ip_read_head        ;; save header pointer
  257. ENDM
  258.  
  259.  
  260.  
  261. ;;*****************************************************************************
  262. ;; IP_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES name
  263. ;;      IP_W_ACCESS retrieves a buffer to write the data for an IP packet.  
  264. ;;      AX,BX holds the destination IP address of the packet and DL holds
  265. ;;      the protocol number of the packet.   The output buffer is returned
  266. ;;      in DI:ES.  This routine might fail if CX exceeds the MTU of the
  267. ;;      interface.  Thus it is only guarenteed to succeed when 
  268. ;;      CX <= dl_ip_min_mtu.  AX is 0 if everything was successful.
  269. ;;
  270. IP_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES MACRO name
  271.     local call_OK
  272.  
  273.     CALL ip_&name&_w_access
  274. ENDM
  275.  
  276. ;;*****************************************************************************
  277. ;; IP_REAL_W_ACCESS is the real provider of the W_ACCESS service.  
  278. ;;
  279. IFDEF IP_REAL_DEFINE_NEEDED
  280. IP_REAL_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES MACRO name
  281.     local done, jmp_table, fail, return, forme
  282.     .errb <name>
  283.  
  284.     .DATA                                   ;; declare the jump table 
  285. jmp_table  dw   done                        ;; dl 0 is undefined
  286.     IRP idx, <1,2,3,4,5,6,7,8>
  287.     if idx le ip_&name&_dls 
  288.         IP_INIT_DL_JMP_TAB name, idx, write_access
  289.     endif
  290.     endm
  291.  
  292.     .CODE
  293.     mov word ptr ip_&name&_data.ip_write_dst, AX            ;; save address 
  294.     mov word ptr ip_&name&_data.ip_write_dst+2, BX
  295.     mov byte ptr ip_&name&_data.ip_write_proto, DL
  296.  
  297.     xor SI, SI
  298.     mov DI, SI
  299.     ROUTE_FIND_in_AX_BX_SI_DI_out_AX_BX_DX_const_CX_BP_ES name, forme, fail, fail
  300.     mov byte ptr ip_&name&_data.ip_write_dl, DL
  301.     mov word ptr ip_&name&_data.ip_write_gate, AX
  302.     mov word ptr ip_&name&_data.ip_write_gate+2, BX
  303.  
  304.     xor DH, DH                              ;; set up jump to proper DL
  305.     shl DX, 1
  306.     mov DI, offset jmp_table
  307.     add DI, DX
  308.     jmp [DI]
  309.  
  310.     forme:
  311.     fail:
  312.         xor AX, AX
  313.         dec AX
  314.         jmp return
  315.  
  316.         ;; the above jump goes to one of the code fragments below
  317.     IRP idx, <1,2,3,4,5,6,7,8>
  318.     if idx le ip_&name&_dls 
  319.         IP_INIT_DL_LABEL name, idx, write_access
  320.         IP_SAVE_SRC name, idx
  321.         cmp CX, dl_ip_min_mtu           ;; enforce length restriction
  322.         ja  fail
  323.         DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP idx, fail
  324.         jmp done
  325.     endif
  326.     endm
  327.         ;; the above code does NOT fall through
  328.     done:
  329.     mov word ptr ip_&name&_data.ip_write_off, DI
  330.     mov word ptr ip_&name&_data.ip_write_seg, ES
  331.     add DI, size ip
  332.     xor AX, AX
  333.     return:
  334. ENDM
  335.  
  336. IP_SAVE_SRC MACRO name, dl
  337.     mov AX, word ptr dl_ip_&dl&_ip
  338.     mov word ptr ip_&name&_data.ip_write_src, AX
  339.     mov AX, word ptr dl_ip_&dl&_ip+2
  340.     mov word ptr ip_&name&_data.ip_write_src+2, AX
  341. ENDM
  342. ENDIF ; IP_REAL_DEFINE_NEEDED
  343.  
  344. ;;*****************************************************************************
  345. ;; IP_SET_SRC_in_AX_BX_const_AX_BX_CX_DX_BP_SI_DI_ES name
  346. ;;      IP_SET_SRC sets the IP source address to the value contained in
  347. ;;      AX:BX (overrides the address set by IP_W_ACCESS).
  348. ;;
  349. IP_SET_SRC_in_AX_BX_const_AX_BX_CX_DX_BP_SI_DI_ES MACRO name
  350.     mov word ptr ip_&name&_data.ip_write_src, AX
  351.     mov word ptr ip_&name&_data.ip_write_src+2, BX
  352. ENDM
  353.  
  354. ;;*****************************************************************************
  355. ;; IP_GET_SRC_out_AX_BX_const_CX_DX_BP_SI_DI_ES name
  356. ;;      IP_GET_SRC returns the IP source address in AX:BX.
  357. ;;
  358. IP_GET_SRC_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO name
  359.     mov AX, word ptr ip_&name&_data.ip_write_src
  360.     mov BX, word ptr ip_&name&_data.ip_write_src+2
  361. ENDM
  362.  
  363. ;;*****************************************************************************
  364. ;; IP_GET_DST_out_AX_BX_const_CX_DX_BP_SI_DI_ES name
  365. ;;      IP_GET_DST returns the IP destination address in AX:BX.
  366. ;;
  367. IP_GET_DST_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO name
  368.     mov AX, word ptr ip_&name&_data.ip_write_dst
  369.     mov BX, word ptr ip_&name&_data.ip_write_dst+2
  370. ENDM
  371.  
  372.  
  373. ;;*****************************************************************************
  374. ;; IP_W_WRITE_in_CX name
  375. ;;      IP_W_WRITE tells the IP interface to send the PACKET that is been
  376. ;;      loaded into the buffer DI:ES.  The length of the packet is in CX
  377. ;;      note that this IP level does NOT support fragmentation, so CX better
  378. ;;      be less than the dl_ip_min_mtu
  379. ;;
  380. IP_W_WRITE_in_CX MACRO name
  381.     .errb <name>
  382.  
  383.     CALL ip_&name&_w_write
  384. ENDM
  385.  
  386. ;;*****************************************************************************
  387. ;;
  388. ;;      IP_REAL_W_WRITE_in_CX is the real provider of the W_WRITE service.
  389. ;;      it is identical in function to IP_W_WRITE.
  390. ;;
  391. IFDEF IP_REAL_DEFINE_NEEDED
  392. IP_REAL_W_WRITE_in_CX MACRO name
  393.     local done, jmp_table
  394.     .errb <name>
  395.  
  396.     .DATA                                   ;; declare the jump table 
  397. jmp_table  dw   done                        ;; dl 0 is undefined
  398.     IRP idx, <1,2,3,4,5,6,7,8>
  399.     if idx le ip_&name&_dls 
  400.         IP_INIT_DL_JMP_TAB name, idx, write_it
  401.     endif
  402.     endm
  403.  
  404.     .CODE
  405.     les DI, dword ptr ip_&name&_data.ip_write_off
  406.     mov AX, 0045H               ;; byte swapped length = 5 version = 4 tos = 0
  407.     mov BX, AX
  408.     stosw
  409.     add CX, size ip
  410.     mov AX, CX                  ;; the length
  411.     xchg AL, AH
  412.     add BX, AX
  413.     stosw
  414.     mov AX, word ptr ip_&name&_data.ip_write_id 
  415.     adc BX, AX
  416.     stosw
  417.     inc AX
  418.     mov word ptr ip_&name&_data.ip_write_id, AX
  419.     mov AX, 0
  420.     stosw
  421.     mov AL, 100                 ;; the time to live
  422.     mov AH, byte ptr ip_&name&_data.ip_write_proto
  423.     adc BX, AX
  424.     stosw
  425.     inc DI 
  426.     inc DI                      ;; skip checksum
  427.     mov SI, offset ip_&name&_data.ip_write_src
  428.     lodsw
  429.     adc BX, AX
  430.     stosw
  431.     lodsw
  432.     adc BX, AX
  433.     stosw
  434.     mov SI, offset ip_&name&_data.ip_write_dst
  435.     lodsw
  436.     adc BX, AX
  437.     stosw
  438.     lodsw
  439.     adc BX, AX
  440.     adc BX, 0
  441.     stosw
  442.  
  443.     sub DI, 10
  444.     not BX
  445.     mov AX, BX
  446.     stosw
  447.  
  448.         ;; set out the packet
  449.     mov AX, word ptr ip_&name&_data.ip_write_gate
  450.     mov BX, word ptr ip_&name&_data.ip_write_gate+2
  451.  
  452.     xor DH, DH                              ;; set up jump to proper DL
  453.     mov DL, byte ptr ip_&name&_data.ip_write_dl
  454.     shl DX, 1
  455.     mov DI, offset jmp_table
  456.     add DI, DX
  457.     jmp [DI]
  458.  
  459.         ;; the above jump goes to one of the code fragments below
  460.     IRP idx, <1,2,3,4,5,6,7,8>
  461.     if idx le ip_&name&_dls 
  462.         IP_INIT_DL_LABEL name, idx, write_it
  463.         DL_IP_W_WRITE_in_AX_BX_CX_const_BP idx
  464.         jmp done
  465.     endif
  466.     endm
  467.         ;; the above code does NOT fall through
  468.     done:
  469. ENDM
  470. ENDIF ; IP_REAL_DEFINE_NEEDED
  471.  
  472.  
  473. ;;*****************************************************************************
  474. ;; IP_INIT_DL name, dl
  475. ;;      IP_INIT_DL initializes the data link interface 'dl' 
  476.  
  477. IP_INIT_DL MACRO name, dl
  478.     local around, not_silent, dont_drop, dont_split
  479.     .errb <dl>
  480.  
  481.     jmp around
  482.     ;;  This stuff can be compiled seperately
  483.     ;   IP_DL_PACKET_in_BX_ES name, dl
  484.     ;   DL_IP_R_RETURN dl
  485.             ;; This does NOT fall through
  486.  
  487.     around:
  488.     mov AX, DS          ;; add the route for each directly connected interface
  489.     mov ES, AX
  490.     xor CX, CX
  491.     test word ptr dl_ip_&dl&_flags, IF_ROUTE_SILENT
  492.     jz not_silent
  493.     or CH, ROUTE_SILENT
  494. not_silent:
  495.     test word ptr dl_ip_&dl&_flags, IF_ROUTE_DROP
  496.     jz dont_drop
  497.     or CH, ROUTE_DROP
  498. dont_drop:
  499.     test word ptr dl_ip_&dl&_flags, IF_ROUTE_SPLIT
  500.     jz dont_split
  501.     or CH, ROUTE_SPLIT
  502. dont_split:
  503.     mov SI, offset dl_ip_&dl&_net
  504.     mov DI, SI
  505.     mov DX, offset dl_ip_&dl&_mask
  506.     mov AX, word ptr dl_ip_&dl&_id
  507.     ROUTE_ADD_in_AX_CX_DX_SI_DI_ES_const_DI_ES %ip_&name&_router
  508.  
  509.     DL_IP_R_READ dl, ip_&name&_dl_&dl&_read_start   ;; schedule the read
  510. ENDM
  511.  
  512.  
  513. ;;*****************************************************************************
  514. ;; IP_DL_PACKET_in_BX_ES name, read_dl
  515. ;;      IP_DL_PACKET_in_BX_ES does the proessing of a packet that came from
  516. ;;      a data link interface BX:ES points to the begining of the IP packet. 
  517. ;;      this is the routine that does the routing and if it for this node
  518. ;;      calls IP_PACKET_in_BX_CX_ES
  519. ;;
  520. IFDEF IP_DL_PACKET_NEEDED
  521. IP_DL_PACKET_in_BX_ES MACRO name, read_dl
  522.     local forme, jmp_table, drop, ip_write_sav, ip_write_gate, ip_write_size
  523.     local ip_write_sav_seg, fromme, src_is_me
  524.     local drop_ttl, drop_route, broad_forme, redirect, continue_forme, ip_ok
  525.     local src_ok, src_ok1, do_check, net_unreach
  526.     local find_route, find_sroute
  527.     .errb <read_dl>
  528.     
  529.     .DATA                                   ;; declare the jump table 
  530. jmp_table  dw   drop                        ;; dl 0 is undefined
  531.     IRP idx, <1,2,3,4,5,6,7,8>
  532.     if idx le ip_&name&_dls 
  533.         IP_INIT_DL_JMP_TAB name, idx, read_dl&_write_start
  534.     endif
  535.     endm
  536.  
  537. ip_write_size    DW  ?
  538. ip_write_sav     DW  ?
  539. ip_write_sav_seg DW  ?
  540. ip_write_gate    DD  ?
  541. src_is_me        DB  ?
  542.  
  543.     .CODE
  544.     ip_&name&_dl_&read_dl&_read_start:
  545.     mov ip_write_sav, BX
  546.     mov BP, BX                                      ;; save BX
  547.  
  548.     mov DX, word ptr ES:[BX+ip_check]       ;; prepare for checksum calculation
  549.     mov word ptr ES:[BX+ip_check], 0
  550.     mov SI, BX
  551.     IP_COMPUTE_CHECK_in_SI_ES_out_BX_const_DX_BP_DI_ES
  552.     cmp DX, BX
  553.     jne drop
  554.     mov BX, BP
  555.     mov word ptr ES:[BX+ip_check], DX       ;; restore checksum
  556.  
  557.     mov CX, word ptr ES:[BX+ip_length]      ;; make sure length reasonable
  558.     xchg CH, CL                             ;; byte swap
  559.  
  560.     cmp CX, dl_ip_&read_dl&_mtu
  561.     ja drop
  562.     mov ip_write_size, CX
  563.  
  564.     mov AL, byte ptr ES:[BX+ip_dst]
  565.     or AL, AL                               ;; check for invalid addresses
  566.     jz drop_route
  567.     cmp AL, 127                             ;; local loopback net
  568.     je drop_route
  569.  
  570.         ;; source address check
  571.     mov AX, word ptr ES:[BX+ip_src]
  572.     mov BX, word ptr ES:[BX+ip_src+2]
  573.     or AX, AX
  574.     jnz do_check
  575.     or BX, BX
  576.     jz src_ok
  577.   do_check:
  578.     or AL, AL                               ;; check for invalid addresses
  579.     jz drop_route
  580.     cmp AL, 127                             ;; local loopback net
  581.     je drop_route
  582.     cmp AX, 0ffffh                          ;; local broadcast address
  583.     jne find_sroute
  584.     cmp BX, 0ffffh
  585.     je drop_route
  586.   find_sroute:
  587.     mov SI, word ptr ES:[BP+ip_dst]
  588.     mov DI, word ptr ES:[BP+ip_dst+2]
  589.     ROUTE_FIND_in_AX_BX_SI_DI_out_AX_BX_DX_const_CX_BP_ES name, fromme, drop_route, drop_route
  590.     test word ptr dl_ip_&read_dl&_flags, NO_REVERSE_CHECK
  591.     jnz src_ok
  592.     cmp DL, read_dl                         ;; would be routed to same dl?
  593.     jne drop_route
  594.     jmp src_ok
  595.   fromme:
  596.     mov BL, 1
  597.     cmp byte ptr ES:[BP+ip_proto], UDP_PROTO ;; allow UDP from my device drivers
  598.     je src_ok1
  599.     jmp drop
  600.   src_ok:
  601.     xor BL, BL
  602.   src_ok1:
  603.     mov byte ptr src_is_me, BL
  604.     mov BX, BP
  605.     DL_IP_IS_BROADCAST_in_BX_ES_const_AX_BX_CX_DX_BP_DI_ES read_dl
  606.     jnz broad_forme 
  607.  
  608.     mov AX, word ptr ES:[BX+ip_dst]
  609.     mov BX, word ptr ES:[BX+ip_dst+2]
  610.     cmp AX, 0ffffh                          ;; local broadcast address
  611.     jne find_route
  612.     cmp BX, 0ffffh
  613.     je drop_route
  614.   find_route:
  615.     mov SI, word ptr ES:[BP+ip_src]
  616.     mov DI, word ptr ES:[BP+ip_src+2]
  617.     ROUTE_FIND_in_AX_BX_SI_DI_out_AX_BX_DX_const_CX_BP_ES name, forme, drop_route, drop_route
  618.     mov word ptr ip_write_gate, AX
  619.     mov word ptr ip_write_gate+2, BX
  620.  
  621.     mov SI, BP                                      ;; restore pointer
  622.     IP_DEC_TTL_in_SI_ES_const_BX_CX_DX_BP_SI_DI_ES drop_ttl
  623.  
  624.     xor DH, DH                              ;; set up jump to proper DL
  625.     shl DX, 1
  626.     mov DI, offset jmp_table
  627.     add DI, DX
  628.  
  629.     jmp [DI]                                ;; jump to proper DL
  630.  
  631.         ;; the above jump goes to one of the code fragments below
  632.     IRP idx, <1,2,3,4,5,6,7,8>
  633.     if idx le ip_&name&_dls 
  634.         IP_INIT_DL_LABEL name, idx, read_dl&_write_start
  635.  
  636.         if idx eq read_dl
  637.             mov word ptr ip_write_sav_seg, ES
  638.         endif
  639.  
  640.         mov BP, word ptr ip_write_sav
  641.         IP_DL_TEST_BROAD_in_BP_ES_const_CX_DX_BP_SI_DI_ES idx, drop
  642.         IP_SEND_PACKET_in_BP_ES name, read_dl, idx, ip_write_gate
  643.  
  644.         if idx eq read_dl
  645.             IP_DL_TEST_FLAGS idx, NO_REDIRECT
  646.             jnz drop
  647.  
  648.             mov SI, word ptr ip_write_sav
  649.             mov ES, word ptr ip_write_sav_seg
  650.  
  651.             mov AX, word ptr ip_write_gate
  652.             mov BX, word ptr ip_write_gate+2
  653.             jmp redirect
  654.         else
  655.             jmp drop
  656.         endif
  657.     endif
  658.     endm
  659.         ;; the above code does NOT fall through
  660.  
  661.     drop_route:
  662.         mov SI, BP
  663.         mov AX, word ptr ES:[SI+ip_src]
  664.         mov BX, word ptr ES:[SI+ip_src+2]
  665.         IP_COMP_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES
  666.         push BX
  667.         push AX
  668.         mov AX, word ptr ES:[SI+ip_dst]
  669.         mov BX, word ptr ES:[SI+ip_dst+2]
  670.         IP_COMP_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES
  671.         pop CX
  672.         cmp AX, CX
  673.         pop CX
  674.         jne net_unreach
  675.         cmp BX, CX
  676.         jne net_unreach
  677.         ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_UNREACHABLE, ICMP_UNREACH_HOST, name
  678.         jmp drop
  679.     net_unreach:
  680.         ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_UNREACHABLE, ICMP_UNREACH_NET, name
  681.         jmp drop
  682.     redirect:
  683.         ICMP_REDIRECT_in_AX_BX_SI_ES %ip_&name&_icmp, ICMP_REDIRECT_HOST, name
  684.         jmp drop
  685.     drop_ttl:
  686.         ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_TIME, ICMP_TIME_TTL, name
  687.         jmp drop
  688.     broad_forme:
  689.         cmp byte ptr src_is_me, 0
  690.         jne drop         ;; don't accept packets that are apparently from me
  691.     IP_DL_ROUTE_BROADCAST_in_BX_ES name, read_dl
  692.         mov ip_&name&_data.ip_broadcast, 1
  693.         jmp continue_forme
  694.     forme:
  695.         cmp byte ptr src_is_me, 0
  696.         jne drop         ;; don't accept packets that are apparently from me
  697.         mov ip_&name&_data.ip_broadcast, 0
  698.     continue_forme:
  699.         mov BX, ip_write_sav
  700.         mov CX, ip_write_size
  701.         DL_IP_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES read_dl, ip_ok
  702.             mov SI, BX
  703.             mov DI, offset ip_&name&_data.ip_packet
  704.             mov DX, DS
  705.             mov ES, DX
  706.             mov DS, ip_write_sav_seg
  707.             DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
  708.             mov DX, ES
  709.             mov DS, DX
  710.             mov BX, offset ip_&name&_data.ip_packet
  711.             mov CX, ip_write_size
  712.         ip_ok:
  713.         CALL ip_&name&_read_packet
  714.     drop:
  715. ENDM
  716.  
  717. IP_DL_ROUTE_BROADCAST_in_BX_ES MACRO name, read_dl
  718.     local done
  719.  
  720.     mov DX, word ptr ES:[BX+ip_dst+2]
  721.     cmp DX, word ptr dl_ip_&read_dl&_gbroad+2
  722.     jne done
  723.     mov AX, word ptr ES:[BX+ip_dst]
  724.     cmp AX, word ptr dl_ip_&read_dl&_gbroad
  725.     jne done
  726.     IRP idx, <1,2,3,4,5,6,7,8>
  727.     if idx le ip_&name&_dls
  728.         if idx ne read_dl
  729.         IP_DL_ROUTE_ONE_BROADCAST_in_BX_ES name, read_dl, idx
  730.         endif
  731.     endif
  732.     endm
  733.   done:
  734. ENDM
  735.  
  736. IP_DL_ROUTE_ONE_BROADCAST_in_BX_ES MACRO name, read_dl, write_dl
  737.     local do_global_broadcast, send_broadcast, done
  738.     local ip_write_gate
  739.  
  740.     .DATA
  741.   ip_write_gate    DD ?
  742.     .CODE
  743.  
  744.     test word ptr dl_ip_&write_dl&_flags, ROUTE_BROADCASTS
  745.     jz done
  746.     mov DX, word ptr dl_ip_&write_dl&_gbroad+2  ; route broadcasts only
  747.     cmp DX, word ptr dl_ip_&read_dl&_gbroad+2   ; between subnets of the
  748.     jne done                                    ; same net
  749.     mov AX, word ptr dl_ip_&write_dl&_gbroad
  750.     cmp AX, word ptr dl_ip_&read_dl&_gbroad
  751.     jne done
  752.     test word ptr dl_ip_&write_dl&_flags, GLOBAL_BROADCAST
  753.     jnz send_broadcast
  754.         mov AX, word ptr dl_ip_&write_dl&_broad     ; Send to local broadcast
  755.         mov DX, word ptr dl_ip_&write_dl&_broad+2   ;   address
  756.     send_broadcast:
  757. ifdef arp_&write_dl&_declared
  758.     xchg BX, DX
  759.     ARP_TAB_GET_FIXED_in_AX_BX_out_SI_const_AX_BX_CX_DX_BP_DI_ES %arp_&write_dl&_arptab
  760.     xchg DX, BX
  761.     or SI, SI
  762.     jz done                ; No ARP entry for broadcast address
  763. endif
  764.     mov BP, word ptr ES:[BX+ip_dst]    ; Save broadcast address received
  765.     push BP
  766.     mov BP, word ptr ES:[BX+ip_dst+2]
  767.     push BP
  768.     mov word ptr ES:[BX+ip_dst], AX    ; Set desired broadcast address
  769.     mov word ptr ES:[BX+ip_dst+2], DX
  770.     mov BP, BX
  771.     mov word ptr ip_write_gate, AX
  772.     mov word ptr ip_write_gate+2, DX
  773.     push BX
  774.     push ES
  775.     IP_SEND_PACKET_in_BP_ES name, read_dl, write_dl, ip_write_gate
  776.     pop ES
  777.     pop BX
  778.     pop BP                ; Restore broadcast address received
  779.     mov word ptr ES:[BX+ip_dst+2], BP
  780.     pop BP
  781.     mov word ptr ES:[BX+ip_dst], BP
  782.   done:
  783. ENDM
  784.  
  785. ;; this macro tests if the flag bit 'mybit' of the DL_IP 'name' is set
  786. IP_DL_TEST_FLAGS MACRO name, mybit
  787.     test dl_ip_&name&_flags, mybit
  788. ENDM
  789.  
  790. ;; This macro tests if the packet pointed to by BP:ES should be dropped
  791. ;; because it is a broadcast
  792. IP_DL_TEST_BROAD_in_BP_ES_const_CX_DX_BP_SI_DI_ES MACRO name, drop
  793.     local forward, test_flag, test_global
  794.  
  795.     mov AX, word ptr ES:[BP+ip_dst]
  796.     mov BX, word ptr ES:[BP+ip_dst+2]
  797.     cmp BX, word ptr dl_ip_&name&_broad+2
  798.     jne test_global
  799.     cmp AX, word ptr dl_ip_&name&_broad
  800.     je test_flag
  801.   test_global:
  802.     cmp BX, word ptr dl_ip_&name&_gbroad+2
  803.     jne forward
  804.     cmp AX, word ptr dl_ip_&name&_gbroad
  805.     jne forward
  806.   test_flag:
  807.     test word ptr dl_ip_&name&_flags, NO_DIR_BROAD
  808.     jnz drop
  809.   forward:
  810. ENDM
  811. ENDIF ; IP_DL_PACKET_NEEDED
  812.  
  813. ;;*****************************************************************************
  814. ;;  IP_INIT_DL_LABEL generates a code lable for use in a jump table for
  815. ;;  'name', 'dl'.  'suffix' is a unique suffix
  816. ;;
  817. IP_INIT_DL_LABEL MACRO name, dl, suffix
  818.     ip_&name&_dl_&dl&_&suffix:
  819. ENDM
  820.  
  821. ;;*****************************************************************************
  822. ;;  IP_INIT_DL_JMP_TAB generates the table entry for the entry 'name', 'dl'
  823. ;;  'suffix' is a unique suffix.
  824. ;;  This is meant for use in a .DATA section 
  825. ;;
  826. IP_INIT_DL_JMP_TAB MACRO name, dl, suffix
  827.     dw ip_&name&_dl_&dl&_&suffix
  828. ENDM
  829.  
  830.  
  831. ;;****************************************************************************
  832. ;; IP_SEND_PACKET sends the packet pointed to by BP:ES of from the
  833. ;; DL 'read_dl' to the dl 'write_dl'.  'gate' is an address that contains
  834. ;; the last two bytes of the IP address.  This is the routine that handles 
  835. ;; IP fragmentation
  836. ;;
  837. IFDEF IP_DL_PACKET_NEEDED
  838. IP_SEND_PACKET_in_BP_ES MACRO name, read_dl, write_dl, gate
  839.     local done, frag_loop, size_ok, fragment, ip_head_len, ip_save_seg, skip
  840.  
  841.     .DATA
  842.     ip_head_len     DW ?
  843.     ip_save_seg     DW ?
  844.  
  845.     .CODE
  846.     mov word ptr ip_save_seg, ES
  847.     mov CX, ES:[BP+ip_length]
  848.     xchg CH, CL
  849.     if dl_ip_&read_dl&_mtu gt dl_ip_&write_dl&_mtu  ;;is fragmenting EVER needed
  850.     cmp CX, dl_ip_&write_dl&_mtu
  851.     ja fragment
  852.     endif
  853.         DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP write_dl, done
  854.         mov SI, BP                      ;; restore SI
  855.         mov BX, CX                      ;; save CX
  856.         push DS
  857.         mov DS, word ptr ip_save_seg
  858.         DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
  859.         pop DS
  860.         mov CX, BX                      ;; restore CX
  861.  
  862.         mov AX, word ptr gate
  863.     mov BX, word ptr gate+2
  864.         DL_IP_W_WRITE_in_AX_BX_CX_const_BP write_dl
  865.  
  866.     if dl_ip_&read_dl&_mtu gt dl_ip_&write_dl&_mtu  ;;is fragmenting EVER needed
  867.         jmp done
  868.     fragment:
  869.         test byte ptr ES:[BP+ip_frag], SWAPPED_IP_DONT_FRAG   ;; OK to fragment?
  870.         jz skip
  871.         mov SI, BP
  872.         ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_UNREACHABLE, ICMP_CANT_FRAGMENT, name
  873.         jmp done
  874.  
  875.     skip:
  876.             ;; compute the header size
  877.         xor CX, CX          ;; make CX hold the size of the IP header
  878.         mov CL, byte ptr ES:[BP+ip_ver_size]
  879.         and CL, 0FH
  880.         shl CL, 1
  881.         shl CL, 1           
  882.         mov word ptr ip_head_len, CX
  883.  
  884.         mov AX, DS          ;; copy the header
  885.         mov ES, AX
  886.         mov SI, BP
  887.         mov DI, offset ip_&name&_data.ip_header
  888.         push DS
  889.         mov DS, word ptr ip_save_seg
  890.         DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
  891.         pop DS
  892.         mov BP, SI          ;; save SI
  893.  
  894.             ;; fix checksum so it is correct when ip_frag = ip_len = 0
  895.         mov AX, word ptr ip_&name&_data.ip_header.ip_check      
  896.         add AX, word ptr ip_&name&_data.ip_header.ip_frag
  897.         adc AX, word ptr ip_&name&_data.ip_header.ip_length
  898.         adc AX, 0
  899.         mov word ptr ip_&name&_data.ip_header.ip_check, AX
  900.  
  901.         frag_loop:
  902.             mov CX, dl_ip_&write_dl&_mtu            ;; ask for biggest buffer
  903.             DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP write_dl, done
  904.             mov DX, word ptr ip_head_len        ;; copy the header
  905.             mov CX, DX
  906.             mov SI, offset ip_&name&_data.ip_header
  907.             shr CX, 1
  908.             rep
  909.             movsw
  910.             sub DI, DX              ;; make DI point to begining of the packet 
  911.  
  912.             mov AX, word ptr ES:[DI+ip_frag]
  913.             xchg AH, AL
  914.             mov CX, word ptr ES:[DI+ip_length]
  915.             xchg CH, CL
  916.             cmp CX, dl_ip_&write_dl&_mtu                    ;; can we send it
  917.             jbe size_ok
  918.                 mov CX, dl_ip_&write_dl&_mtu
  919.                 sub CX, DX              ;; subtract the IP header length
  920.                 and CX, 0FFF8H          ;; make multiple of 8
  921.                 add CX, DX              ;; add the IP header length
  922.                 or AX,  IP_MORE_FRAG    ;; indicate not the last
  923.             size_ok:
  924.             xchg CH, CL
  925.             mov word ptr ES:[DI+ip_length], CX
  926.             xchg AH, AL
  927.             mov word ptr ES:[DI+ip_frag], AX
  928.  
  929.             mov BX, word ptr ES:[DI+ip_check]       ;; fix up checksum
  930.             sub BX, CX
  931.             sbb BX, AX
  932.             sbb BX, 0
  933.             mov word ptr ES:[DI+ip_check], BX
  934.  
  935.                 ;; set up stuff for next round
  936.             xchg CH, CL
  937.             sub CX, DX                  ;; subtract the IP header length
  938.             mov BX, CX
  939.             shr BX, 1
  940.             shr BX, 1
  941.             shr BX, 1
  942.             mov AX, word ptr ip_&name&_data.ip_header.ip_frag
  943.             xchg AH, AL
  944.             add AX, BX
  945.             xchg AH, AL
  946.             mov word ptr ip_&name&_data.ip_header.ip_frag, AX
  947.  
  948.             mov BX, word ptr ip_&name&_data.ip_header.ip_length
  949.             xchg BH, BL
  950.             sub BX, CX
  951.             xchg BH, BL
  952.             mov word ptr ip_&name&_data.ip_header.ip_length, BX
  953.  
  954.             mov SI, BP                      ;; restore SI
  955.             add DI, DX                      ;; restore DI
  956.             mov BX, CX
  957.             add BX, DX                      ;; BX holds total Lenght
  958.             push DS
  959.             mov DS, word ptr ip_save_seg
  960.             DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
  961.             pop DS
  962.             mov BP, SI                      ;; save SI
  963.  
  964.             mov AX, word ptr gate
  965.             mov CX, BX
  966.         mov BX, word ptr gate+2
  967.             DL_IP_W_WRITE_in_AX_BX_CX_const_BP write_dl
  968.  
  969.             mov BX, word ptr ip_&name&_data.ip_header.ip_length
  970.             xchg BH, BL
  971.             cmp BX, word ptr ip_head_len
  972.         ja frag_loop
  973.     endif
  974.     done:
  975. ENDM
  976.  
  977.  
  978. ;;******************************************************************************
  979. ;; IP_DEC_TTL_in_BX_ES
  980. ;;      IP_DEC_TTL  decrements the TTL of the IP packet pointed to by SI:ES
  981. ;;      and jumps to 'drop' if the TTL has expired.
  982. ;;
  983. IP_DEC_TTL_in_SI_ES_const_BX_CX_DX_BP_SI_DI_ES MACRO drop
  984.     mov AL, byte ptr ES:[SI+ip_ttl]             ;; decrement ttl
  985.     sub AL, 01                                  ;; can't use dec (need carry)
  986.     jbe drop
  987.     mov byte ptr ES:[SI+ip_ttl], AL
  988.     mov AX, word ptr ES:[SI+ip_check]           ;; fix up checksum
  989.     add AX, 1                                   ;; add 1 in 1's complement
  990.     adc AX, 0 
  991.     mov word ptr ES:[SI+ip_check], AX
  992. ENDM
  993. ENDIF ; IP_DL_PACKET_NEEDED
  994.  
  995.  
  996. ;;******************************************************************************
  997. ;;    IP_COMP_NET
  998. ;;      IP_COMP_NET takes an IP address in AX,BX and computes the network
  999. ;;      part of the IP address based on the class of the IP address and
  1000. ;;      returns it in AX,BX.  
  1001. ;;
  1002. IP_COMP_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO
  1003.     local class_A, class_B, class_C 
  1004.  
  1005.     test AL, 80h        ;; normal IP network interpretation
  1006.     jz class_A
  1007.     test AL, 40h
  1008.     jz class_B
  1009.     jmp class_C
  1010.  
  1011.     class_A:
  1012.         xor AH, AH
  1013.     class_B:
  1014.         xor BL, BL
  1015.     class_C:
  1016.         xor BH, BH
  1017. ENDM
  1018.  
  1019.  
  1020. ;;*****************************************************************************
  1021. ;; IP_PACKET_in_BX_CX_ES name
  1022. ;;      IP_PACKET_in_BX_CX_ES does all the proessing of a packet that is
  1023. ;;      destined for this node.  BX:ES points to the begining of the IP packet. 
  1024. ;;      CX holds the length of the packet.
  1025. ;;      Basicly this routine just dispatches it to the proper READ routine
  1026. ;;
  1027. IFDEF IP_REAL_DEFINE_NEEDED
  1028. IP_PACKET_in_BX_CX_ES MACRO name
  1029.     local drop
  1030.     .errb <name>
  1031.  
  1032.     test word ptr ES:[BX+ip_frag], SWAPPED_IP_IS_FRAG   ;; if fragmented
  1033.     jnz drop
  1034.  
  1035.     xor AH, AH
  1036.     mov AL, byte ptr ES:[BX+ip_proto]                   ;; load protocol
  1037.     mov word ptr ip_&name&_data.ip_read_head, BX        ;; save header pointer
  1038.     xor DH, DH                              ;; compute the size of the header
  1039.     mov DL, byte ptr ES:[BX+ip_ver_size]
  1040.     and DL, 0FH
  1041.     shl DX, 1
  1042.     shl DX, 1
  1043.     sub CX, DX
  1044.     add BX, DX
  1045.  
  1046.     mov DX, AX                              ;; jump to proper routine
  1047.     and DL, 1FH
  1048.     cmp DL, AL
  1049.     jne ip_&name&_prot_unreach
  1050.     shl DX, 1
  1051.     mov SI, offset ip_&name&_data.ip_read_jmp
  1052.     add SI, DX
  1053.     jmp [SI]                                ;; note this is NOT a call,
  1054.                                             ;; so when the code returns
  1055.                                             ;; it will return to the caller
  1056.                                             ;; of this routine
  1057.  
  1058.     drop:
  1059. ENDM
  1060. ENDIF ; IP_REAL_DEFINE_NEEDED
  1061.  
  1062.  
  1063. ;;*****************************************************************************
  1064. IP_COMPUTE_CHECK_in_SI_ES_out_BX_const_DX_BP_DI_ES MACRO
  1065.     local check_loop
  1066.  
  1067.     xor CX, CX              ;; make CX hold the size of the IP header
  1068.     mov CL, byte ptr ES:[SI+ip_ver_size]
  1069.     and CL, 0FH
  1070.     shl CX, 1
  1071.     xor BX, BX              ;; also clears carry
  1072.     check_loop:
  1073.         seges
  1074.         lodsw
  1075.         adc BX, AX
  1076.     loop check_loop
  1077.     adc BX, 0               ;; add in the last carry if any
  1078.     not BX
  1079. ENDM
  1080.  
  1081.  
  1082. ;;*****************************************************************************
  1083. ;; IP_ASCII_in_SI_DI_ES_out_DI converts the IP address stored at SI:DS
  1084. ;; to ASCII dot notation in the buffer ENDING at DI:ES.  DI:ES returns the 
  1085. ;; begining of the string generated.
  1086. ;;
  1087. IP_ASCII_in_SI_DI_ES_out_DI_const_BX_BP_ES MACRO 
  1088.     local ip_loop, ip_loop_done
  1089.  
  1090.     std                                     ;; count down
  1091.     mov CX, 4
  1092.     add SI, 3
  1093.     dec DI
  1094.     ip_loop:
  1095.         lodsb 
  1096.         TO_ASCII_in_AL_DI_ES_out_DI_const_BX_CX_BP_SI_ES 
  1097.         dec CX
  1098.         jz ip_loop_done
  1099.         mov AL, '.'
  1100.         stosb
  1101.     jmp ip_loop
  1102.     ip_loop_done:
  1103.     inc DI
  1104.     cld                                     ;; count up again
  1105. ENDM
  1106.  
  1107.  
  1108. ;;*****************************************************************************
  1109. ;; TO_ASCII converts the number in AL to ascii (decimal) and puts the resulting
  1110. ;; string in the buffer whose END is pointed to by DI:ES.  DI points to the 
  1111. ;; BEGINING of the string when it is done.  THIS ROUTINE ASSUMES THE DIRECTION
  1112. ;; FLAG IS COUNTING DOWN
  1113. ;;
  1114. TO_ASCII_in_AL_DI_ES_out_DI_const_BX_CX_BP_SI_ES MACRO
  1115.     local loop_write
  1116.  
  1117.     mov DL, 10
  1118.     loop_write:            ;; write in the number
  1119.         xor AH, AH
  1120.         idiv DL            ;; AH = AL % 10      AL = AL / 10
  1121.         xchg AL, AH
  1122.         add AL, 48          ;; add ascii '0'
  1123.         stosb
  1124.         mov AL, AH
  1125.         and AL, AL
  1126.     jnz loop_write
  1127. ENDM
  1128.