29 junio 2007

¡Ya soy estándar!

Hace algo así como un añito os comentaba que mi página web (no ésta, sino la que tengo para mis frikadas MSXeras) no cumplía los estándares del W3C, y ponía como excusa que es que la había hecho a mano y bla bla.

Pues bien, recientemente y a raíz del escándalo de la nueva web del congreso español, he recordado el tema. Una de las críticas se basa en el hecho de que dicha web no valida el más mínimo estándar. Al leer dichos algos, me he sentido aludido y he sentido un pelín de vergüenza por pecar mi propio sitio del mismo delito webístico.

Así que me he puesto manos a la obra, y he rehecho mi página web dedicada al MSX de forma que ahora cumple los estándares XHTML y CSS (lo cual me ha supuesto aprender algo de las susodichas tecnologías, de las que no tenía ni idea). Ahora sí puedo ir por la calle con la cabeza bien alta y gritar "¡Soy estándar!", a lo que probablemente los transeuntes responderán "No te acerques hijo, que está loco", pero bueno, son gajes del oficio.

Nota: La hoja de estilos da rabia de lo simple que es. Si algún webgurú se aburre mucho y se atreve a mejorarla, a lo mejor hasta incluso la uso y pongo su nombre en mi web (qué generoso soy).

25 junio 2007

Ríase usted de Kafka

Allá por el segundo lustro de los años 90, yo era un lozano jovenzuelo dedicado a la adquisición infatigable de conocimientos universitarios. Ello me proporcionaba, en épocas veraniegas y vacacionales en general, largos períodos de asueto que a menudo incluían largas sesiones de meditación y/o divertimento informático en mi casa.

Muchas de mis amistades se encontraban en similar situación, por lo que no era infrecuente que acabáramos reunidos en casa de alguno de nosotros filosofando sobre el origen del universo, haciendo fanzines sobre maquinitas obsoletas, jugando al Salamander a dobles, o todo ello a la vez; y divertimentos similares.

Pues bien, dos de estos amigotes tienen un talento especial para la plasmación gráfica de entidades abstractas (uséase para el dibujo), y era habitual que estando en mis aposentos me pidieran papel y hoja (no, no lo he escrito mal; es una historia muy larga) a fin de realizar en tiempo real un volcado en papel de un repentino arrebato de creatividad. Estos dos individuos no son otros que el putoso al que ya conoceis, y el señor Yombo, el cual no sé si quiere salir afoteado aquí pero como pista os diré que es hermano de Marce.

Por suerte, tuve la feliz idea de guardar tamañas obras de arte, y afortunadamente muchas de ellas han sobrevivido hasta nuestros días. Hete aquí una pequeña selección de las mismas, que tuve a bien escanear un día que a Kaito aún no le había dado por nacer. Eso sí, he de advertiros de la crudeza creativa de las mismas; no me responsabilizo de las posibles pesadillas que podais tener como consecuencia de la vislumbración de las mismas.

Nota: No olvideis hacer cataclack en las imágenes para verlas más grandotas, que si no, no tiene gracia.

Nota bonus: ¡Encuentra el infiltrado! Una de las obras de arte no está hecha por el putoso ni por el Yombo, ¿eres capaz de decir cuál es la obra en cuestión y cuál es el autor de la misma?


Esta cosa estuvo colgada en mi habitación años enteros, e iba siendo actualizada periódicamente por el artista. El "arte" está censurado porque es un número telefónico real.



Cruda reflexión sobre la naturaleza humana.


Crudo ser humano, directamente.


¿De verdad tardo tanto?


Los devastadores efectos de ver a otro jugar al Nemesis.


Original variación del famoso "desintegrome en mi propia parafernalia divisuatoria".


La gente no suele hacer esto ante la perspectiva de una visita de su novia...


Cualquier cosa que pueda decir sobre esto estaría fuera de lugar.


Lo cual es bastante lógico.


Y tú, ¿con qué mundo te quedas?


Más censura telefónica en este brillante ensayo filosófico.


Gracias, me abstendré de hacer chistes sobre ojos negros.


Amén.


Curioso retrato de un conocido (y auténtico) usuario de MSX.


Conviene estar preparado para catástrofes de todo tipo.


De "historieta" a "fistorieta", de ahí a "fishorieta" y de ahí...


Musho cuidao con é.

20 junio 2007

¡Cumpleaño!

Hace mucho tiempo, en una galaxia muy lejana...

- *BIP* Informe del agente K4-1-t0. Acabo de llegar al planeta Tierra. Procediendo al estudio de la morfología planetaria en vistas a una posible invasión.


- ¡Cariño, mira qué cosita más mona he encontrado! ¿Nos lo podemos quedar?
- Pero... oiga, señora... se confunde usted...


- Caramba, su densidad capilar es muy similar a la mía... pues sí, nos lo quedamos.
- ¡AAAAH! ¡Socorro! ¡A mí la brigada intergaláctica de rescate!


De esta prometedora forma comenzó la andadura de nuestro héroe Kaito en el planeta Tierra, hace ahora exactamente un año.

Tal evento no podía pasar desapercibido en el entorno familio-amistoidal del susodicho heredero al liderazgo social, y como era menester, fastuosas fueron las celebraciones correspondientes.

- Gracias, querida familia... aunque a mi edad, uno ya va p'abajo y pocas ganas de celebración quedan...


- ...¿qué? ¿Que en realidad la tarta es de plástico?


- ¡Je, je! ¿Y a mí qué? ¡Con estos dientes puedo zamparme lo que sea!


- Eso de que el fuego quema es una leyenda urbana, ¡os lo voy a demostrar ahora mismo!


No obstante, pasados los ágapes y las felicitaciones, subyace la dura realidad: ahora que es mayor, Kaito debe enfrentarse a la vida adulta, que no es precisamente un camino de rosas. Toca en primer lugar, buscar pareja para formar una familia:

- (regla número uno del ligoteo: aproximarse sigilosamente a la víctima, sin despertar sospechas...)


- La señorita está conmigo, así que, ¡esfúmate, buitre!


- Ooooh, qué hombre...
- Y saben aquel que diu...


- ¡Chao, cielo! ¡Ya te llamaré!
- ¿Cómo? ¿¿Que es UN TIO?? ¡¡La m... que os... cab... hijos de...!!



Tareas no menos duras son conseguir un trabajo y una vivienda digna, y es que la vida está muy difícil.

- Mis papis ya empiezan a mirarme raro... voy a tener que buscarme un curro y un pisito, buf... vamos a ver, "se necesita babeador con experiencia en mordiscos a traición"...


- ¡¡La leche!! ¡Mi primer día de trabajo y me quedo dormido! Vamos, arranca, arranca...


- Pffff... y ahora va y se me rompe el diferencial cigüeñable de la transmisión...


- Pues nada, tendré que ir en autobús, qué remedio...


- La ministra de vivienda dirá lo que quiera, pero estos minipisos de 30 centímetros son una m...


- Y encima tiene unas goteras que pa' qué. En fin, así me ahorro ir a la playa...


- "Si se le desinfla la casa, sople por el tubito"... a mí, la verdad, no me parece muy normal esto...


Moraleja: Kaito ya sabe que no puede uno fiarse de los políticos.

- Ya me parecía a mí sospechoso que me cayeran encima tantas bolas durante la campaña electoral...

31 mayo 2007

Estantería REALMENTE fabulosa

He aquí parte de un folleto propagandístico aparecido en el buzón de mi humilde morada ayer mismo. Se trata de una empresa armariera que por la compra de sus productos regala una estantería, según dicen, fabulosa:


Ya lo creo que es fabulosa, teniendo en cuenta que mide veinte metros de alto por cinco de ancho por tres de fondo. Se me antoja realmente un buen negocio, pues con semejante monstruo en mi poder, las posibilidades son infinitas, pudiendo por ejemplo:

  • Alquilar las baldas como plazas de parking.
  • Montar un hotel cápsula al más puro estilo nipón (a cuatro cápsulas por balda).
  • Vender mi piso y vivir en el susodicho armario (¡seis habitaciones de 15 m2 cada una!)
El problema es dónde colocar semejante mamotreto, pues aunque mi piso es razonablemente diáfano, desde luego no tengo los techos a veinte metros de altura.

En fin, curioso lo que puede uno encontrar por esos mundos de Yupi.

25 mayo 2007

Mi orgullo friki (extracto)

;================================================
;=== 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.

22 mayo 2007

¿Coincidencia? No lo creo...

Se abre el telón y estamos a domingo 20 de mayo. El friki me llama por fonófono para decirme que ponga la tele, pues en cierto canal están emitiendo un programa en el que aparece Parque España, un pintoresco lugar de Japón sobre el que ya escribí algo. Nos echamos unas risas y se cierra el telón.

Se vuelve a abrir el telón y estamos a martes 22 de mayo. Me da por comprobar las palabras que la gente estaba buscando cuando encontró mi blog, y me encuentro esto:


Se cierra el telón y pregunto: ¿seguro que la gente ya no ve tanto la tele por culpa del interdem?

17 mayo 2007

Especial Kaito

En esta ocasión voy a llevar a cabo un experimento blogológico: una entrada sin texto, sólo con fotos y pies de idem. Así pus, olvida que has leído esta frase, y deléitate con el siguiente batiburrillo de píxeles coloreados a mayor gloria del señor Soriano Koizumi.


- ¡Arriad las velas! ¡Trincad el foque! ¡Descogorciad el birlibirloque!


Somnífero infalible: recitar en verso el código fuente de NestorBASIC.


- ¡Teneis que creerme! ¡Era una visión horrible! ¡De verdad, he visto a mi padre desnudo! ¡¡No estoy loco, maldita sea!!


- Vito, no me fío un pelo de ese tipo. Encárgate de que tenga un desgraciado accidente.
- Sí, capo.


Prueba irrefutable de que, digan lo que digan, los niños vienen de Carrefúl.


- El Emperador y su Enchufe Sagrado se dignarán recibirle en audiencia.


- Y ahora, el gran fakir Ka-i-toh se tragará una auténtica cuchara de plástico.


GAME OVER. PRESS F5 TO CONTINUE.


- ¿Y tú qué miras? ¿Quieres pelea?


- No se preocupe, señor, despistaré a los paparachis en un momento.


- ¡SOCORRO! ¡Que me violan!


¡HASTA LA VICTORIA SIEMPRE!