;================================================
;=== Proceso del paquete recibido: ===
;=== Comprobacion del protocolo del paquete ===
;================================================
ld hl,(IN_BUFFER+2) ;Ether-Type
;--- Comprueba si el protocolo es conocido,
; si lo es salta a la parte adecuada del codigo
ld de,#0008
call COMP
jp z,IS_IP
ld de,#0608
call COMP
jp z,IS_ARP
;--- Protocolo desconocido: lo ignoramos
jp END_GET_PACK
;==============================
;=== Paquete ARP recibido ===
;==============================
;Algoritmo segun RFC826, "Packet Reception"
IS_ARP: ;--- Comprueba el hardware y el protocolo
ld hl,(IN_BUFFER+4)
ld de,#0100
call COMP
jp nz,END_GET_PACK
ld hl,(IN_BUFFER+6)
ld de,#0008
call COMP
jp nz,END_GET_PACK
;--- Comprueba si el tamanyo de la dir HW es 0: paquete UNARP.
; En ese caso busca la entrada y la borra si no es estatica.
ld a,(IN_BUFFER+8)
cp 6
jr z,NO_UNARP
or a
jp nz,END_GET_PACK ;Si no es 0 ni 6, es incorrecto
ld de,IN_BUFFER+18 ;Busca entrada ARP...
call SRCH_ARP
jp c,END_GET_PACK
ld a,(ix)
cp 1
jp z,END_GET_PACK
ld (ix),0 ;...y si la encuentra, la borra
call END_GET_PACK ;si no es estatica.
NO_UNARP:
;--- Si la IP de origen es 0, no cachea la direccion
; (clientes DHCP comprobando la direccion que se
; les acaba de asignar pueden enviar un ARP request
; con la IP del enviador a cero)
ld a,#FF
ld (MERGE_FLAG),a
ld hl,IN_BUFFER+18
ld de,ZERO32
call COMP32
jr z,IS_ARP_2
;--- Comprueba si hay una entrada ARP para esa IP
xor a
ld (MERGE_FLAG),a
ld de,IN_BUFFER+18
call SRCH_ARP
jr c,NOTINCACHE
;* Encontrada: actualiza dir MAC
ld a,#FF
ld (MERGE_FLAG),a
ld a,(ix) ;Si es estatica, no hace nada
cp 1
jp z,NOUPTIMER
push ix
pop de
inc de
ld hl,IN_BUFFER+12
ld bc,6
ldir
NOUPTIMER:
;* Actualiza temporizador de expiracion
ld (ix),2 ;Por si estaba en resolucion
push ix
pop hl
ld bc,11
add hl,bc
ex de,hl
ld hl,ARP_TOUT
ld bc,4
ldir
NOTARPSTAT:
NOTINCACHE:
;--- Si la IP requerida no es la nuestra, terminar ya
IS_ARP_2: ld hl,IN_BUFFER+28
ld de,BUF_IPLOCAL
call COMP32
jp nz,END_GET_PACK
;--- Si la entrada no estaba en la tabla, anyadirla
ld a,(MERGE_FLAG)
or a
jr nz,OKMERGEARP
call GET_FREE_ARP
ld (ix),2 ;Entrada dinamica
push ix ;Copia la MAC y la IP de una sentada
pop de
inc de
ld hl,IN_BUFFER+12
ld bc,10
ldir
ld hl,ARP_TOUT ;Establece temp. de expiracion
ld bc,4
ldir
OKMERGEARP:
;--- Si el paquete era Request, enviar Reply
ld a,(IN_BUFFER+11)
cp 1
call z,SEND_ARP_RP
jp END_GET_PACK
MERGE_FLAG: db 0
;===============================
;=== Datagrama IP recibido ===
;===============================
IS_IP: ;
;--- Primero comprobamos que llegue al tamanyo minimo:
; Eth1 Eth2 Type Cabecera(20)
ld hl,(INBUF_SIZE)
ld de,34
call COMP
jp nc,END_GET_PACK
;--- Guardamos el tamanyo de la cabecera IP en OUT_BUFFER.
; Si es <20 bytes, ignoramos el paquete.
ld a,(IN_BUFFER+4)
and #0F
cp 5
jp c,END_GET_PACK
sla a
sla a
ld l,a
ld h,0
ld (IP_HEADER_LEN),hl
;--- Guardamos el tamanyo total del paquete en OUT_BUFFER+2.
; Si es >576 bytes, ignoramos el paquete.
ld a,(IN_BUFFER+6)
ld h,a
ld a,(IN_BUFFER+7)
ld l,a
ld de,577
call COMP
jp c,END_GET_PACK
ld (IP_TOTAL_LEN),hl
;--- Calcula el checksum de la cabecera
ld a,(CHKVECT)
and %10
jr z,IPCHKSOK
ld ix,IN_BUFFER+4
ld bc,(IP_HEADER_LEN)
call CALC_CHKSUM
ld a,d
or e
jp nz,END_GET_PACK
IPCHKSOK: ;
;--- Comprueba la direccion IP de destino,
; debe ser la nuestra o una de broadcast
;* Es nuestra IP?
ld hl,IN_BUFFER+20
ld de,BUF_IPLOCAL
call COMP32
jr z,OK_IPDEST
;* Es de broadcast? (Mascara OR dir = todo 1s?)
ld hl,SUBNET_MASK
ld de,IN_BUFFER+20
ld b,4
CHKIPBROAD2: ld a,(de)
or (hl)
inc a
jp nz,END_GET_PACK
inc hl
inc de
djnz CHKIPBROAD2
OK_IPDEST:
;--- Si el campo de version no tiene 4, ignoramos el datagrama
ld a,(IN_BUFFER+4)
and #F0
cp #40
jp nz,END_GET_PACK
;--- Si es un fragmento de datagrama, lo ignoramos
ld hl,(IN_BUFFER+10)
res 7,l ;Pone a 0 el bit no usado (previene futuras extensiones de IP)
res 6,l ;Pone a 0 el bit DF. Desde ahora HL solo tiene DF y Frag. Off.
ld a,h ;Si MF o Fragment Offset son <>0,
or l ;es un fragmento: ignorarlo
jp nz,END_GET_PACK
;--- Si el paquete contiene opciones, las descartamos
; (movemos los datos a la posicion IN_BUFFER+24)
ld hl,(IP_HEADER_LEN) ;HL = Long cabecera
ld de,20
call COMP
jr z,IPOPTOK
ld bc,IN_BUFFER+4
add hl,bc ;HL = Inicio de los datos
ld de,IN_BUFFER+24
ld bc,(IP_TOTAL_LEN)
ldir
ld hl,(IP_TOTAL_LEN) ;Cambia el tamanyo
ld de,(IP_HEADER_LEN) ;del paquete para no incluir
or a ;las opciones IP
sbc hl,de ;HL = Long. sin cabeceras
ld de,20
add hl,de ;HL = Long. con cabecera sin opciones
ld a,h
ld (IN_BUFFER+6),a
ld a,l
ld (IN_BUFFER+7),a
ld (IP_TOTAL_LEN),hl
ld (IP_HEADER_LEN),de
IPOPTOK:
;--- Sustituye el campo de tamanyo total del paquete
; por el tamanyo de los datos, y en little-endian
ld hl,(IP_TOTAL_LEN)
ld de,(IP_HEADER_LEN)
or a
sbc hl,de
ld (IN_BUFFER+6),hl
;--- Decide accion segun protocolo transportado
ld a,(IN_BUFFER+13)
cp 6
jp z,IS_TCP
cp 17
jp z,IS_UDP
cp 1
jp z,IS_ICMP
jp END_GET_PACK ;Desconocido: ignoramos
;===============================
;=== Mensaje ICMP recibido ===
;===============================
IS_ICMP: ;--- Comprueba el checksum
ld a,(CHKVECT)
and %10000
jr z,ICMPCHK_OK
ld ix,IN_BUFFER+24
ld bc,(IN_BUFFER+6)
call CALC_CHKSUM
ld a,d
or e
jp nz,END_GET_PACK
ICMPCHK_OK: ;
;--- Comprobamos el tipo
ld a,(IN_BUFFER+24)
or a ;ECHO Reply?
jr z,IS_ICMP_EREP
cp 3
jp z,IS_ICMP_HOSTUN
cp 8 ;ECHO request?
jp nz,END_GET_PACK ;Otro: lo ignoramos
;--- ICMP Echo Request: Lo respondemos si REPLYECHO<>0
IS_ICMP_EREQ: ld a,(REPLYECHO)
or a
jp z,END_GET_PACK
ld hl,IN_BUFFER+24 ;Copiamos el mensaje tal cual en la respuesta
ld de,OUT_BUFFER+24
ld bc,(IN_BUFFER+6)
push bc
inc bc ;Para que incluya el 0 de padding
ldir
xor a
ld (OUT_BUFFER+24),a ;Cambia el tipo a "Echo reply"
pop bc
ld hl,0
ld (OUT_BUFFER+26),hl ;Borra checksum antiguo
ld ix,OUT_BUFFER+24
call CALC_CHKSUM
ld (OUT_BUFFER+26),de ;Establece nuevo checksum
ld hl,(IN_BUFFER+16) ;IP destino = el originador del mensaje
ld de,(IN_BUFFER+18)
ld bc,(IN_BUFFER+6) ;Longitud
ld a,1 ;Protocolo = ICMP
jp SEND_IP
;--- ICMP Echo Reply: lo encolamos si no hay ya 4 encolados
IS_ICMP_EREP: ld a,(ICMPI_PINDEX)
ld b,a
inc b
ld ix,ICMPI_IP0-11
ld de,11
BUC_EREP1: add ix,de
djnz BUC_EREP1 ;Ahora IX apunta a la zona de datos adecuada
ld a,(ICMPI_PINDEX)
ld b,a
ld a,(ICMPI_GINDEX)
cp b
jr nz,EREP_HAYSITIO
ld a,(ix) ;Indice GET = Indice PUT:
or (ix+1) ;Hay sitio si entrada vacia (IP=0),
or (ix+2) ;si no, terminamos.
or (ix+3)
jp nz,END_GET_PACK
EREP_HAYSITIO: ;
ld hl,(IN_BUFFER+16)
ld (ix),l
ld (ix+1),h
ld hl,(IN_BUFFER+18)
ld (ix+2),l
ld (ix+3),h
ld a,(IN_BUFFER+12) ;TTL
ld (ix+4),a
ld hl,(IN_BUFFER+28) ;Identificador (guardamos en L.E.)
ld (ix+5),h
ld (ix+6),l
ld hl,(IN_BUFFER+30) ;Numero de secuencia (guardamos en L.E.)
ld (ix+7),h
ld (ix+8),l
ld hl,(IN_BUFFER+6) ;Longitud de los datos
ld bc,8 ;Resta long. cabecera ICMP
or a
sbc hl,bc
ld (ix+9),l
ld (ix+10),h
ld a,(ICMPI_PINDEX) ;Incrementa indice PUT
inc a ;saltando de 3 a 0
and %111
ld (ICMPI_PINDEX),a
jp END_GET_PACK
;--- ICMP Destination Unreachable: si esta asociado a una
; conexion TCP, la abortamos con codigo 7
;Nota: la cabecera del paquete causante de esta respuesta
;ICMP esta en IN_BUFFER+32.
IS_ICMP_HOSTUN: ld a,(IN_BUFFER+9+32)
cp 6 ;Si el paquete causante no es TCP, ignorarlo
jp nz,END_GET_PACK
ld hl,(IN_BUFFER+20+28)
ld de,(IN_BUFFER+22+28)
ld a,(IN_BUFFER+24+28)
ld iyh,a
ld a,(IN_BUFFER+25+28)
ld iyl,a
ld a,(IN_BUFFER+26+28)
ld ixh,a
ld a,(IN_BUFFER+27+28)
ld ixl,a
call SEARCH_TCP
cp #FF ;Conexion asociada inexistente: terminar
jp z,END_GET_PACK
call LOAD_TCB
xor a ;Cierra la conexion con codigo 7
ld (TCP_STATE),a
ld a,7
ld (LAST_CLOSE),a
call SAVE_TCB
jp END_GET_PACK
;==============================
;=== Paquete UDP recibido ===
;==============================
IS_UDP: ;--- Comprueba checksum, excepto si CHKVECT dice lo contrario
ld a,(CHKVECT)
and %1000
jp z,OK_UDP_CHKSUM
;* Para calcular el checksum, componemos la pseudo-cabecera
; justo antes de los datos, pisando la cabecera IP.
; Pero como el orden de los datos (palabras de 16 bits)
; no es importante para el calculo,
; aprovechamos que las direcciones IP y el campo de protocolo
; ya estan establecidos en la cabecera IP, y asi
; solo necesitamos establecer 0 donde estaba el TTL y la longitud UDP
; donde estaba el checksum IP.
xor a
ld (IN_BUFFER+12),a ;Campo TTL
ld hl,(IN_BUFFER+28) ;Long. UDP en el campo checksum IP
ld (IN_BUFFER+14),hl
ld hl,(IN_BUFFER+6)
ld bc,12 ;Para que incluya pseudo-cabecera
add hl,bc
push hl
pop bc
ld ix,IN_BUFFER+12
call CALC_CHKSUM
ld a,d
or e
jp nz,END_GET_PACK
OK_UDP_CHKSUM: ;
;--- Checksum correcto: comprobamos si es una respuesta DNS
; o un paquete DHCP, en ese caso se salta al codigo
; de procesamiento adecuado
ld a,(IN_BUFFER+26)
ld h,a
ld a,(IN_BUFFER+27)
ld l,a
ld de,DNS_PORT
call COMP
jp z,IS_DNS
ld de,68
call COMP
jp z,IS_DHCP
;--- Comprobamos que se puede almacenar el paquete
ld hl,(IN_BUFFER+6) ;Paquete demasiado grande?
ld de,548+8+1
call COMP
jp c,END_GET_PACK
ld a,(UDPI_PINDEX)
ld b,a
inc b
ld ix,UDPI_IP0-10
ld de,10
BUC_UDP1: add ix,de
djnz BUC_UDP1 ;Ahora IX apunta a la zona de datos adecuada
ld a,(UDPI_PINDEX)
ld b,a
ld a,(UDPI_GINDEX)
cp b
jr nz,UDPI_HAYSITIO
ld a,(ix) ;Indice GET = Indice PUT:
or (ix+1) ;Hay sitio si entrada vacia (IP=0),
or (ix+2) ;si no, terminamos.
or (ix+3)
jp nz,END_GET_PACK
UDPI_HAYSITIO: ;
;--- Almacenamos paquete
ld hl,(IN_BUFFER+16) ;IP origen
ld (ix),l
ld (ix+1),h
ld hl,(IN_BUFFER+18)
ld (ix+2),l
ld (ix+3),h
ld hl,(IN_BUFFER+24) ;Puerto origen (little endian)
ld (ix+4),h
ld (ix+5),l
ld hl,(IN_BUFFER+26) ;Puerto destino (little endian)
ld (ix+6),h
ld (ix+7),l
ld hl,(IN_BUFFER+6) ;Longitud datos UDP
ld bc,8
or a
sbc hl,bc
ld (ix+8),l
ld (ix+9),h
ld a,h ;Copia la parte de datos
or l ;si no tiene long 0
jr z,OK_UDPIDATA
push hl
ld hl,UDP_BUFFERS-512
ld de,512
ld a,(UDPI_PINDEX)
inc a
ld b,a
UDPLEN_LOP1: add hl,de
djnz UDPLEN_LOP1
ex de,hl
ld hl,IN_BUFFER+32
pop bc
ldir
OK_UDPIDATA: ;
ld hl,UDPI_PINDEX
call INC_UDPINDEX ;Actualiza indice para el proximo paquete
jp END_GET_PACK
;==============================
;=== Paquete DNS recibido ===
;==============================
IS_DNS: ;--- Comprueba si hay una peticion en curso
; y si coincide el ID con el ultimo enviado,
; si no, descarta el paquete
ld a,(DNS_STAT_P)
cp 1
jp nz,END_GET_PACK
ld hl,(IN_BUFFER+32)
ld de,(ID_DNS)
call COMP
jp nz,END_GET_PACK
;--- Si la respuesta esta truncada, ponemos error 21
; a no ser que podamos reintentar con el DNS secundario.
ld a,(IN_BUFFER+34)
and %00000010
jr z,DNS_NOTRUNC
call DNS_USE_SEC
jp nc,END_GET_PACK
ld a,3
ld (DNS_STAT_P),a
ld a,21
ld (DNS_STAT_S),a
jp END_GET_PACK
DNS_NOTRUNC: ;
;--- Si la respuesta contenia algun error,
; lo establecemos, a no ser que podamos reintentar
; con el DNS secundario.
ld a,(IN_BUFFER+35)
and %00001111
jr z,DNS_NOERR
call DNS_USE_SEC
jp nc,END_GET_PACK
ld a,3
ld (DNS_STAT_P),a
ld a,(IN_BUFFER+35)
and %00001111
ld (DNS_STAT_S),a
jp END_GET_PACK
DNS_NOERR: ;
;--- La respuesta no contiene error.
; Comprobamos si contiene alguna respuesta valida.
ld ix,IN_BUFFER+32 ;Apunta al ppio del paquete DNS
ld h,(ix+6)
ld l,(ix+7)
ld (ANCOUNT),hl ;Numero de respuestas
ld h,(ix+8)
ld l,(ix+9)
ld (NSCOUNT),hl ;Numero de servidores autoritativos
ld h,(ix+10)
ld l,(ix+11)
ld (ARCOUNT),hl ;Numero de secciones adicionales
ld ix,IN_BUFFER+44 ;IX=Inicio de la pregunta
SKIPQ_LOOP: ld a,(ix) ;Se salta la pregunta
inc ix ;(campo QNAME)
or a ;comprobando si hay compresion
jr z,SKIPQ_LOOP3
bit 7,a
jr z,SKIPQ_LOOP
SKIPQ_LOOP2: inc ix ;Se salta QTYPE y QCLASS
SKIPQ_LOOP3: inc ix ;(mas el segundo byte del puntero
inc ix ;si es necesario)
inc ix
inc ix ;Ahora IX apunta a las respuestas
;* Comprobamos si se nos da directamente la respuesta
SCAN_FOR_AN: ld bc,(ANCOUNT)
ld a,b
or c
jr z,SCAN_FOR_NS
call SCAN_DNS_RR
or a
jr z,SCAN_FOR_NS
ld a,2 ;Si habia una respuesta valida,
ld (DNS_STAT_P),a ;ponemos status=2 y terminamos
xor a
ld (DNS_STAT_S),a
jp END_GET_PACK
;* Si no, comprobamos si hay IPs de otros servidores
; en "Authoritative" o en "Aditional"
SCAN_FOR_NS: ld bc,(NSCOUNT)
ld a,b
or c
jr z,SCANNS_FAILED ;Seccion NS vacia?
call SCAN_DNS_RR ;Busca IPs de servidores
or a ;en "authoritative"
jp nz,CHANGE_DNS_IP
ld bc,(ARCOUNT)
ld a,b
or c
jr z,SCANNS_FAILED ;Seccion AR vacia?
call SCAN_DNS_RR ;Busca IPs de servidores
or a ;en "additional"
jp nz,CHANGE_DNS_IP
SCANNS_FAILED: ld a,3 ;Si no hay nada en NS ni AR, error 20
ld (DNS_STAT_P),a
ld a,20
ld (DNS_STAT_S),a
jp END_GET_PACK
;* Se ha encontrado la IP de otro DNS:
; Repetimos la consulta usandola
CHANGE_DNS_IP: ld hl,DNS_RESULT
ld de,DNS_IP ;Establecemos nueva direccion
ld bc,4 ;del DNS a consultar
ldir
ld hl,(ID_DNS) ;Incrementamos identificador
inc hl
ld (ID_DNS),hl
ld a,3 ;Ponemos estado secundario a 3
ld (DNS_STAT_S),a
xor a ;Inicializamos reintentos
ld (DNS_RETRY),a
inc a
ld (DNS_TOUT),a ;Para que se reenvie inmediatamente
jp END_GET_PACK
;--- Esta subrutina examina la zona a la que apunta IX
; y busca un RR del tipo "Direccion IP".
; Si lo encuentra, pone la IP en DNS_REPLY
; y DNS_RESP_FLAG a #FF (que devuelve en A).
; Al final, IX apunta a la siguiente zona.
;
; Entrada: BC = Numero de RRs en la zona.
SCAN_DNS_RR: xor a
ld (DNS_RESP_FLAG),a
DNS_AN_LOOP: push bc
SKIPQ_LOOP4: ld a,(ix) ;Se salta el nombre
inc ix ;comprobando si esta comprimido
or a
jr z,SKIPQ_LOOP6
bit 7,a
jr z,SKIPQ_LOOP4
SKIPQ_LOOP5: inc ix
SKIPQ_LOOP6: ;
ld a,(DNS_RESP_FLAG) ;Si ya hay una respuesta
or a ;valida, simplemente se salta
jr nz,DNS_AN_LOOP2 ;el RR
;* Comprueba que el tipo sea "Direccion IP"
ld h,(ix) ;IX apunta a TYPE
ld l,(ix+1)
ld de,1
call COMP
jr nz,DNS_AN_LOOP2
;* Se ha encontrado respuesta:
; se copia a DNS_RESULT
ld l,(ix+10)
ld h,(ix+11)
ld e,(ix+12)
ld d,(ix+13)
ld (DNS_RESULT),hl
ld (DNS_RESULT+2),de
ld a,#FF
ld (DNS_RESP_FLAG),a
;* Pasa al siguiente RR
DNS_AN_LOOP2: ld bc,10
add ix,bc ;Para que apunte a RDATA
ld b,(ix-2)
ld c,(ix-1) ;BC = RDLENGTH
add ix,bc
;* Si quedan RRs, vuelve a empezar
pop bc
dec bc
ld a,b
or c
jr nz,DNS_AN_LOOP
ld a,(DNS_RESP_FLAG)
ret
DNS_RESP_FLAG: db 0 ;#FF cuando se encuentra respuesta
;--- Esta subrutina es llamada cuando se recibe un paquete
; DNS erroneo o se consumen todos los reenvios.
; Lo que hace es comprobar si el DNS
; usado era el primario y hay un secundario disponible.
; Si es asi, establece DNS_IP con la direccion
; del DNS secundario, pone DNS_STAT_S a 2
; y DNS_RETRY a 0 (es decir, lo prepara todo
; para repetir la consulta usando el DNS secundario),
; y devuelve Cy=0.
; En caso contrario, devuelve Cy=1 (error).
DNS_USE_SEC: ld a,(DNS_STAT_S)
cp 1
scf
ret nz ;Si no era el primario
ld ix,BUF_IPDNS1
ld a,(ix+4)
or (ix+5)
or (ix+6)
or (ix+7)
scf
ret z ;Si era el primario pero no hay sec.
ld hl,BUF_IPDNS2 ;Establece secundario
ld de,DNS_IP ;y reinicia contador de
ld bc,4 ;reenvios
ldir
ld a,2
ld (DNS_STAT_S),a
xor a ;De paso pone Cy=0
ld (DNS_RETRY),a
inc a
ld (DNS_TOUT),a ;Para que se repita el envio inmediatamente
ret
;===============================
;=== Paquete DHCP recibido ===
;===============================
IS_DHCP: ld a,(DHCP_VECT) ;Ignorar si no usamos DHCP
or a
jp z,END_GET_PACK
ld a,(DHCP_STATE)
cp CONFIGURED
jp z,END_GET_PACK
;--- Obtiene el tipo del paquete
ld a,(IN_BUFFER+32) ;Es BOOTREPLY?
cp 2
jp nz,END_GET_PACK
ld hl,IN_BUFFER+36 ;El 'xid' coincide?
ld de,DHCP_XID
call COMP32
jp nz,END_GET_PACK
call DHCP_GET_TYPE
cp DHCPOFFER
jr z,IS_DHCP_OFFER
cp DHCPACK
jr z,IS_DHCP_ACK
cp DHCPNAK
jp z,IS_DHCP_NAK
jp END_GET_PACK ;Otros tipos son ignorados
;--- Paquete DHCPOFFER
IS_DHCP_OFFER:
;* Si el estado no es SELECTING, ignorarlo
ld a,(DHCP_STATE)
cp SELECTING
jp nz,END_GET_PACK
;* Guarda el identificador del servidor
call DHCP_GET_SERVER
jp c,END_GET_PACK
ld de,DHCP_SERVER
ld bc,4
ldir
;* Guarda el campo 'yiaddr' como la IP ofrecida
ld hl,IN_BUFFER+48
ld de,DHCP_YIADDR
ld bc,4
ldir
;* Guarda el 'xid' recibido
ld hl,IN_BUFFER+36
ld de,DHCP_RCVXID
ld bc,4
ldir
;* Pasa a estado REQUESTING y envia DHCPREQUEST
ld a,REQUESTING
ld (DHCP_STATE),a
ld a,DHCPREQUEST
call SEND_DHCP
call DHCP_FIRST
jp END_GET_PACK
;--- Paquete ACK
IS_DHCP_ACK:
;* Si el estado no es REBINDING, REQUESTING, RENEWING
; o INFORMING, ignorarlo
ISDHCPACK2: cp REQUESTING
jr z,ISDHCPACK3
cp RENEWING
jr z,ISDHCPACK3
cp REBINDING
jr z,ISDHCPACK3
cp INFORMING
jp nz,END_GET_PACK
ISDHCPACK3:
;* Si el identificador del servidor no coincide con el anterior,
; ignorar el mensaje
; (Problema: Que pasa si el ACK ha sido recibido en estado REBINDING,
; por un servidor distinto al usado anteriormente?
; Por eso, nos fiaremos unicamente del XID)
;call DHCP_GET_SERVER
;jp c,END_GET_PACK
;ld de,DHCP_SERVER
;call COMP32
;jp nz,END_GET_PACK
;* Inicializa los campos Lease, T1 y T2
ld hl,DHCP_T1
ld de,DHCP_T1+1
ld bc,12-1
ld (hl),0
ldir
;* Guarda el campo 'yiaddr' como la IP asignada,
; a no ser que hubieramos enviado DHCPINFORM
ld a,(DHCP_VECT)
and 1
jr z,ISDHCPACK4
ld hl,IN_BUFFER+48
ld de,BUF_IPLOCAL
ld bc,4
ldir
ld a,1
ld (DHCP_VECT_O),a
ISDHCPACK4:
;* Recorre todas las opciones y las procesa
call DHCP_INIT_OP
ISDHCPACKL: call DHCP_NEXT_OP
or a
jp z,ISDHCPACKEND ;No quedan opciones?
;* T1: Lo almacena
cp 58
jr nz,ISDHCPACK_NOT1
push ix
pop hl
ld de,DHCP_T1
ld bc,4
ldir
ld ix,DHCP_T1
call POR60_32
jr ISDHCPACKL
ISDHCPACK_NOT1:
;* T2: Lo almacena
cp 59
jr nz,ISDHCPACK_NOT2
push ix
pop hl
ld de,DHCP_T2
ld bc,4
ldir
ld ix,DHCP_T2
call POR60_32
jr ISDHCPACKL
ISDHCPACK_NOT2:
;* Lease: Lo almacena
cp 51
jr nz,ISDHCPACK_NOLS
push ix
pop hl
ld de,DHCP_LEASE
ld bc,4
ldir
ld ix,DHCP_LEASE
call POR60_32
jr ISDHCPACKL
ISDHCPACK_NOLS:
;* Mascara de subred: la almacena si la habiamos pedido
cp 1
jr nz,ISDHCPACK_NOSB
ld a,(DHCP_VECT)
and %10 ;La habiamos pedido?
jr z,ISDHCPACKL
push ix
pop hl
ld de,SUBNET_MASK
ld bc,4
ldir
ld a,(DHCP_VECT_O)
or %10
ld (DHCP_VECT_O),a
jr ISDHCPACKL
ISDHCPACK_NOSB:
;* Gateway por defecto: lo almacena si lo habiamos pedido
cp 3
jr nz,ISDHCPACK_NOGW
ld a,(DHCP_VECT)
and %100 ;La habiamos pedido?
jr z,ISDHCPACKL
push ix
pop hl
ld de,DEFGW
ld bc,4
ldir
ld a,(DHCP_VECT_O)
or %100
ld (DHCP_VECT_O),a
jp ISDHCPACKL
ISDHCPACK_NOGW:
;* Servidores DNS: los almacena si los habiamos pedido
cp 6
jr nz,ISDHCPACK_NODN
ld a,(DHCP_VECT)
and %1000 ;Los habiamos pedido?
jp z,ISDHCPACKL
ld a,(DHCP_VECT_O)
or %1000
ld (DHCP_VECT_O),a
push bc
push ix
pop hl
ld de,BUF_IPDNS1
ld bc,4
ldir
pop bc ;Hay mas de un DNS en la opcion?
ld a,b
cp 8
jp c,ISDHCPACKL
ld de,BUF_IPDNS2
ld bc,4
ldir
jp ISDHCPACKL
ISDHCPACK_NODN:
;* Timeout ARP: lo almacena si lo habiamos pedido
cp 35
jr nz,ISDHCPACK_NOAT
ld a,(DHCP_VECT)
and %10000 ;Lo habiamos pedido?
jp z,ISDHCPACKL
push ix,ix
pop hl
ld de,ARP_TOUT
ld bc,4
ldir
pop hl
ld de,ARP_TOUT_SECS
ld bc,4
ldir
ld ix,ARP_TOUT
call POR60_32
ld a,(DHCP_VECT_O)
or %10000
ld (DHCP_VECT_O),a
jp ISDHCPACKL
ISDHCPACK_NOAT:
;* Tipo de trama ethernet: lo almacena si lo habiamos pedido
cp 36
jr nz,ISDHCPACK_NOFT
ld a,(DHCP_VECT)
and %100000 ;Lo habiamos pedido?
jp z,ISDHCPACKL
ld a,(ix)
or a
jr z,ISDHCPACK_FT
ld a,#FF
ISDHCPACK_FT: ld (FRAME_TYPE),a
ld a,(DHCP_VECT_O)
or %100000
ld (DHCP_VECT_O),a
;jp ISDHCPACKL
ISDHCPACK_NOFT:
;* Opcion no reconocida: ignorarla
jp ISDHCPACKL
ISDHCPACKEND:
;* Fin de las opciones.
; Si estamos en INFORMING, pasar a CONFIGURED y terminar.
ld a,(DHCP_STATE)
cp INFORMING
jr nz,ISDHCPACKEND0
ld a,CONFIGURED
ld (DHCP_STATE),a
jp END_GET_PACK
ISDHCPACKEND0:
;* Si T1 es 0, establecerlo a lease/2
ld hl,DHCP_T1
ld de,ZERO32
call COMP32
jr nz,OKT1NZ
ld hl,#FFFF ;Si lease infinito, T1 infinito
ld (DHCP_T1),hl
ld (DHCP_T1+2),hl
ld a,(DHCP_LEASE)
cp h
jr z,OKT1NZ
ld hl,DHCP_LEASE
ld de,DHCP_T1
ld bc,4
ldir
ld ix,DHCP_T1
ld b,1
call ENTRE2_32
OKT1NZ:
;* Si T2 es 0, establecerlo a 0.875*lease ((7/8)*lease)
ld hl,DHCP_T2
ld de,ZERO32
call COMP32
jr nz,OKT2NZ
ld hl,#FFFF ;Si lease infinito, T2 infinito
ld (DHCP_T2),hl
ld (DHCP_T2+2),hl
ld a,(DHCP_LEASE)
cp h
jr z,OKT2NZ
ld hl,DHCP_LEASE
ld de,DHCP_T2
ld bc,4
ldir
ld ix,DHCP_T2 ;Divide T2 entre 8
ld b,3
call ENTRE2_32
ld hl,DHCP_T2
ld de,IN_BUFFER
ld bc,4
ldir
ld b,6
T2ISZL: push bc ;Multiplica (T2/8) por 7
ld hl,IN_BUFFER
ld de,DHCP_T2
ld bc,DHCP_T2
call ADD32
pop bc
djnz T2ISZL
OKT2NZ:
;* Fin: pasa a BOUND y termina
ld a,BOUND
ld (DHCP_STATE),a
jp END_GET_PACK
;--- Paquete NAK
IS_DHCP_NAK:
;* En estado BOUND, SELECTING, INFORMING o CONFIGURED, ignorarlo
ld a,(DHCP_STATE)
cp BOUND
jp z,END_GET_PACK
cp SELECTING
jp z,END_GET_PACK
cp INFORMING
jp z,END_GET_PACK
cp CONFIGURED
jp z,END_GET_PACK
;* En otros estados, volver a INIT
xor a ;ld a,INIT
ld (DHCP_STATE),a
jp END_GET_PACK
;===============================
;=== Segmento TCP recibido ===
;===============================
;Despues de la publicidad.
NOTA: Si no sabes qué es esto, no eres un friki auténtico. Háztelo mirar.
4 comentarios:
Pues en contestacion:
if stat[conexact]=4 then
begin {*** D ***}
writeln('*** conexion abierta');
repeat {*** 2 ***}
{ letra:=inkey;}
letrain:=inltcp_rcvstr(conex[conexact]);
write('linea: ');
write(linea);
writeln(' ');
for code:=1 to 10 {Length(letrain)} do
write(letrain[code]);
writeln;
if Length(letrain)>0 then
begin {*** C ***}
if linea=1 then
begin {*** B ***}
Comm:=copy(letrain,1,pos(' ',letrain)-1);
if Comm='GET'then
begin
writeln('*** Recibido GET');
letraprime:=letrain;
linea:=linea+1
end;
if Comm='HEAD' then
begin
writeln('*** Recibido HEAD');
inltcp_close(conex[conexact]);
end;
if Comm='POST' then
begin
writeln('*** Recibido POST');
inltcp_close(conex[conexact]);
end;
end; {*** B ***}
if letrain[length(letrain)-2]=chr(10) then
begin {*** B ***}
writeln('*** Recibida Cabecera');
if Comm='GET'then
begin {*** A ***}
filename:=copy(letraprime , 5 , pos(' ',copy(letraprime,5,(length(letraprime)-1) ))-1);
if pos('?',filename)> 0 then
begin
capture;
filename:=copy(filename,1,pos('?',filename)-1);
end;
writeln('*** Pedido: '+Filename+'***');
IF FILENAME='/' THEN FILENAME:='index.htm'
else
Filename:=copy(filename,2,length(filename));
writeln('*** Abriendo: '+Filename);
{filesz:=trunc(GetFileSize(filename));}
sal:=real2intstr(GetFileSize(filename));
WRITELN('*** LONGITUD:',SAL);
WRITELN('*** IORESULT:',MsxIoResult);
if MsxIoResult = $D7 then
begin
writeln('*** ERROR 404');
inltcp_SENDstr(conex[conexact],'HTTP/1.0 Document follows'+chr(13)+chr(10));
inltcp_SENDstr(conex[conexact],'Content-type: text/html'+chr(13)+chr(10));
inltcp_SENDstr(conex[conexact],'Server MSX Server/0.1'+chr(13)+chr(10));
sal:=real2intstr(GetFileSize(filename));
inltcp_SENDstr(conex[conexact],'Content-length: '+sal+chr(13)+chr(10));
inltcp_SENDstr(conex[conexact],chr(13)+chr(10));
file_http:=msxfileopen('ERROR404.HTM') ; { Assign name to handle }
repeat {*** 3 ***}
lecturas:=448;
MSXfileRead(file_http,addr(bufftcpout),lecturas);
INLTCP_FLUSH(conex[conexact]);
repeat
freebuff:=INLTCP_FREEBUFF(conex[conexact]);
writeln('*** WAITING FOR BUFFER',freebuff);
until (freebuff>=lecturas) or (freebuff<0);
INLTCP_SENDblck (conex[conexact],addr(bufftcpout),lecturas);
until (MSXIoResult=$C7) or (freebuff<0); {*** 3 ***}
msxfileclose(file_http);
end
else
begin
inltcp_SENDstr(conex[conexact],'HTTP/1.0 Document follows'+chr(13)+chr(10));
fileext:=copy(filename , length(filename)-2,3);
writeln('*** '+fileext);
if ((fileext='gif') or (fileext='jpg') or (fileext='bmp') or (fileext='png')) then
begin
inltcp_SENDstr(conex[conexact],'Content-type: image/'+fileext+chr(13)+chr(10));
end
else
begin
inltcp_SENDstr(conex[conexact],'Content-type: text/html'+chr(13)+chr(10));
end;
inltcp_SENDstr(conex[conexact],'Server MSX Server/0.1'+chr(13)+chr(10));
inltcp_SENDstr(conex[conexact],'Content-length: '+sal+chr(13)+chr(10));
inltcp_SENDstr(conex[conexact],chr(13)+chr(10));
file_http:=msxfileopen(filename); { Assign name to handle }
repeat {*** 3 ***}
lecturas:=448;
MSXfileRead(file_http,addr(bufftcpout),lecturas);
WRITELN('*** IORESULT:',MsxIoResult);
WRITELN('*** LECTURAS:',LECTURAS);
INLTCP_FLUSH(conex[conexact]);
repeat
freebuff:=INLTCP_FREEBUFF(conex[conexact]);
writeln('*** WAITING FOR BUFFER',freebuff);
until (freebuff>=lecturas) or (freebuff<0);
INLTCP_SENDblck (conex[conexact],addr(bufftcpout),lecturas);
until (MSXIoResult=$C7) or (freebuff<0); {*** 3 ***}
msxfileclose(file_http);
end;
inltcp_close(conex[conexact]);
linea:=1;
letrain:='';
letraprime:='';
end; {*** A ***}
end; {*** B ***}
end; {*** C ***}
until (letra=chr(27)) or (INLTCP_STATUS (conex[conexact])<>4); {*** 2 ***}
inltcp_close(conex[conexact]);
repeat {*** 2b ***}
statin:=stat[conexact];
stat[conexact]:=INLTCP_STATUS (conex[conexact]);
if not(statin=stat[conexact]) then
begin
write('* ');
write(stat[conexact]);
write(' ');
end;
until (stat[conexact]=0); {*** 2b ***}
{-------}
end; {*** D ***}
protocolos tcp,udp ,suma de comprobacion todo eso me suena pero aun no soy lo suficiente friki eso si para el año me apunto a un curso, quiero llegar a ser tan friki como konamiman!!
Konamiman, acabo de verte en Kirai donde eramos los únicos a los que nos importaba mínimamente el MSX (y la pregunta estaba mal formulada :( :P )
Te agrego al RSS, y aprovecho para saludar... Próximamente me leeré todo lo que tengas que decir :P
Por cierto, el código que pones parece una pila de estas TCP/IP escrita ahí a lo bruto... Ya me gustaría a mi tener una ObsoNET para probarlo (*GUIÑO GUIÑO*) xD
Saludos!
Bienvenido y lee poco a poco, no te indigestes. Respecto a la Obsonet, paciencia, todo llegará.
Publicar un comentario