Sei sulla pagina 1di 27

ESCUELA TCNICA SUPERIOR DE INGENIEROS DE TELECOMUNICACIN

MANUAL TCNICO DEL CLIENTE DE TFTP IMPLEMENTADO EN C PARA EL ENTORNO EDCOLDFIRE DEL MCF5272
AUTORES:
CORONADO BARRIOS, MIGUEL LPEZ NAVARRO, ANTONIO JOS PREZ MAGARIOS, NURIA SAN SEGUNDO HERNNDEZ, RUBN

FECHA JUNIO 2006

Departamento de Ingeniera Electrnica

E.T.S.I. de Telecomunicacin Universidad Politcnica de Madrid

-1-

NDICE DE CONTENIDOS
AUTORES:........................................................................................................1 Departamento de Ingeniera Electrnica.......................................................................1 Transmisin de tramas...............................................................................................9 Recepcin de tramas..................................................................................................9

-2-

NDICE DE FIGURAS
Figura 1: traza habitual de la lectura de un fichero mediante TFTP...................4 Figura 2: traza habitual de la escritura de un fichero mediante TFTP.................4 Figura 3: Diagrama de flujo de datos en memoria de MFC5272.........................9 Figura 4: Registro ECR (Ethernet Control Register). Figura obtenida del manual de usuario del MCF5272....................................................................................14 Figura 5: Registro EIMR (Ethernet Interrupt Mask Register). Figura obtenida del manual de usuario del MCF5272.......................................................................15 Figura 6: Registro EIR (Interrupt Event register). Figura obtenida del manual de usuario del MCF5272.........................................................................................15 Figura 7: Registro MALR (RAM Perfect Match Address Low). Figura obtenida del manual de usuario del MCF5272..................................................................15 Figura 8: Registro MAUR (RAM Perfect Match Address High). Figura obtenida del manual de usuario del MCF5272..................................................................16 Figura 9: Registro HTUR (Hash Table High Register). Figura obtenida del manual de usuario del MCF5272.......................................................................16 Figura 10: Registro HTLR (Hash Table Low Register). Figura obtenida del manual de usuario del MCF5272.......................................................................16 Figura 11: Registro EMRBR (Receive Buffer Size Register). Figura obtenida del manual de usuario del MCF5272.......................................................................17 Figura 12: Registro ERDSR (Point to Receive Descriptor Ring).Figura obtenida del manual de usuario del MCF5272..................................................................17 Figura 13: Registro ETDSR (Point to Transmit Descriptor Ring). Figura obtenida del manual de usuario del MCF5272..................................................................17 Figura 14: Registro RCR (Receive Control Register). Figura obtenida del manual de usuario del MCF5272.......................................................................18 Figura 15: Registro TCR (Transmit Control Register). Figura obtenida del manual de usuario del MCF5272.......................................................................18 Figura 16: Registro ECR (Ethernet Control Register). Figura obtenida del manual de usuario del MCF5272.......................................................................19 Figura 17: Registro EIMR (Ethernet Interrupt Mask Register). Figura obtenida del manual de usuario del MCF5272..................................................................19 Figura 18: Registro RDAR (Receive Descriptor Active Register). Figura obtenida del manual de usuario del MCF5272...................................................20 Figura 19: Registro TDAR (Transmit descriptor active register). Figura obtenida del manual de usuario del MCF5272..................................................................20 Figura 20 Registro EIR (Interrupt Event register). Figura obtenida del manual de usuario del MCF5272.........................................................................................21

-3-

1. Introduccin a TFTP
1.1 Introduccin al protocolo TFTP
El protocolo TFTP (Trivial File Transfer Protocol) es un protocolo muy sencillo de transferencia de ficheros usado, entre otras aplicaciones, en la carga inicial del Sistema Operativo a travs de la red. Debido a la sencillez que lo caracteriza, se implementa normalmente sobre UDP (User Datagram Protocol) y por tanto debe estar preparado para los errores de este protocolo de transporte: prdida, duplicacin o desorden. Para realizar la lectura o escritura de un fichero, el cliente de TFTP se conecta mediante un puerto aleatorio al servidor, el cual escucha en el puerto 69. Una traza habitual en la lectura de un fichero es la siguiente:

Figura 1: traza habitual de la lectura de un fichero mediante TFTP

y en el caso de la escritura:

Figura 2: traza habitual de la escritura de un fichero mediante TFTP

Se considera que la lectura/escritura ha concluido cuando se recibe un paquete con menos de 512 octetos de datos. Una traza real de captura en la lectura de un fichero es lectura_tftp (abrir con el programa ethereal, disponible en www.ethereal.com ).

-4-

Para conocer ms sobre este protocolo puede consultarse la RFC 1350 (http://www.faqs.org/ftp/pub/rfc/pdf/rfc1350.txt.pdf ).

1.2

Introduccin al programa

El programa desarrollado es una implementacin en C para el MCF5272 de la parte cliente del protocolo TFTP. Para ello, se utiliza el mdulo ethernet de dicho microcontrolador, configurando adecuadamente los registros necesarios. A partir de ah, vamos construyendo la pila de protocolos IP (Internet Protocol) / UDP sobre los que se sustenta TFTP, as como otros protocolos necesarios en una comunicacin a travs de una red como son ARP (Address Resolution Protocol) e ICMP (Internet Control Message Protocol). Como servidor de TFTP utilizaremos SolarWinds-TFTP-Server, disponible gratuitamente en Internet (http://www.solarwinds.net/Tools/Free_tools/TFTP_Server/ ) y que nos servir as para comprobar la conformidad de nuestro cliente con la norma RFC 1350. Dicho servidor lo instalaremos en un PC con una direccin IP conocida y que conectaremos (directamente o a travs de alguna red IP) al microcontrolador, tal y como se describe en el manual de usuario.

2. Programa Principal
Como decamos anteriormente, el protocolo TFTP nos ofrece la posibilidad de subir y descargar ficheros entre un servidor (en nuestro caso un PC) y un cliente (el microcontrolador con el programa que estamos tratando). Los primeros parmetros que debemos establecer son las direcciones de memoria que vamos a utilizar. En nuestro caso hemos seleccionado las siguientes (se encuentran definidas en m5272.h): Dinmica: RAM Interna: RAM Externa: Memoria Flash: SDRAM=0x60000; SRAM=0x70000; EXT_SRAM=0x80000; FLASH=0x90000;

Todas ellas con un tamao de 0x10000 En realidad, detrs de todas estas secciones de memoria se encuentra una memoria SDRAM de un tamao mayor, aunque la divisin en varias memorias nos permite agrupar los datos en funcin de su contenido. Por ejemplo, la zona de datos de usuario es la SDRAM (a partir de 0x60000) que es la que se utiliza para el intercambio de ficheros con el servidor. Otras variables de vital importancia para el funcionamiento del protocolo son las direcciones IP del cliente, del servidor y la del gateway, la mascara de red, la direccin MAC (Medium Access Control) del MCF5272 y el nombre del fichero a intercambiar. Todas estas variables estn definidas en tftp_main.c, aunque tambin se puede acceder a ellas mediante los comandos TFTP show (que muestra los valores actuales de dichas variables) y set (que nos permite cambiarlos durante la ejecucin)

-5-

2.1 Ejecucin del programa


Al ejecutar EJEMPLO_TFTP.c, limpiamos los bits de interrupcin pendiente del mdulo ethernet, del ICR3 (Interrupt Control Registrer n3) y del ICR1 y saltamos a la funcin main_tftp(), contenida en el archivo tftp_main.c. En esta funcin, lo que se hace es entrar en un bucle infinito (while(1)) en el que se escribe en cada iteracin la cadena "TFTP> " y se salta a la funcin run_cmd() (que se encuentra tambin en tftp_main.c). En esta funcin lo que se hace es leer del teclado lo que el usuario teclee, parsear dicha entrada para obtener los comandos y argumentos deseados y saltar a la funcin correspondiente en funcin del comando obtenido. Solo se aceptan los comandos help, read (leer un fichero de host remoto), write (escribir un fichero a host remoto), md (mostrar datos en memoria local), set (para cambiar parmetros de la transmisin), show (mostrar la configuracin actual) y quit (salir). Estos comandos se definen en el siguiente array:
CMD CMDTAB[] = { {"help", 0, {"read", 0, {"md", 0, {"set", 0, {"show", 0, {"write", 1, <filename>"}, {"quit", 0, }

0, 1, 1, 2, 0, 2,

help, read, md, set, show, write,

"Display this help message", ""}, "Read from TFTP host", "<filename>"}, "Memory display", "<address>"}, "Set parameter", "option value"}, "Show parameters", ""}, "Write to TFTP host", "bytes "Exit TFTP", " "}

0, quit,

Este array es un array de estructuras de comandos. La estructura de comandos (que se encuentra definida en tftp_main.h) est compuesta por los campos: nombre, nmero mnimo y mximo de argumentos, funcin que se ejecutar cuando se invoque el comando, una breve descripcin del comando y la sintaxis que debemos seguir a la hora de llamarlo.
typedef const struct { char * cmd; /* nombre del comando */ int min_args; /* nmero mnimo de argumentos */ int max_args; /* nmero mximo de argumentos */ void (*func)(int, char **); /* funcin que se ejecutar*/ char * description; /* descripcin del comando*/ char * syntax; /* sintaxis*/ } CMD;

Por tanto, una vez averiguado cual es el comando tecleado con if(strcasecmp(CMDTAB[i].cmd, argv[0]) == 0){ y verificado el numero de argumentos, saltamos a la funcin deseada con CMDTAB[i].func(argc,argv);

3. Descarga de un fichero desde el servidor

-6-

Esta tarea se ejecuta cuando tecleamos el comando read file, saltando en este caso a la funcin read() de tftp_main.c. En esta funcin, se comienza inicializando un temporizador para controlar el tiempo de espera en lectura (pero an no se arranca), se permite las interrupciones del FEC (actuando sobre el bit correspondiente del registro ICR) y se salta a la funcin fec_init (NIF *nif) de fec.c., pasando como parmetro la estructura NIF fec_nif creada en dicho archivo.

3.1

Funcionamiento del mdulo FEC


La estructura NIF (Network InterFace) contiene todos los datos y funciones necesarios para la transmisin a nivel fsico: direccin MAC, MTU (Maximum Transmision Unit), array con los protocolos soportados y sus manejadores (necesario para que cuando nos llegue una trama Ethernet sepamos a que protocolo superior debemos pasarla), funciones para controlar (resetear, arrancar, parar o enviar datos) el FEC, as como para gestionar los bferes de transmisin y recepcin (obtener bferes vacos, liberarlos,). A continuacin podemos ver con ms detalle la estructura:
{ typedef struct NIF_t char ETH_ADDR ETH_ADDR int int name[16]; hwa; broadcast; hwa_size; mtu; /* direccin MAC */ /* direccin MAC de broadcast */ /* hardware maximum transmission unit */

SUP_PROTO unsigned short int void void int uint16, NBUF *); void NBUF* NBUF* void void

protocol[MAX_SUP_PROTO]; num_protocol;

(*reset)(struct NIF_t *); (*start)(struct NIF_t *); (*stop)(struct NIF_t *); (*send)(struct NIF_t *, (*receive)(struct NIF_t *); (*rx_alloc)(void); (*tx_alloc)(void); (*rx_free)(NBUF *); (*tx_free)(NBUF *);

HWA_ADDR_P,

HWA_ADDR_P,

void int unsigned int unsigned unsigned unsigned unsigned unsigned } NIF; int int int int int

*nic; /* base address of NIC chipset */ vector; /* vector used by device */ next_receive; /* needed by the SEEQ */ f_rx; f_tx; f_rx_err; f_tx_err; f_err;

Tambin se utilizan las siguientes estructuras para trabajar con NIF: La estructura SUP_PROTO representa a cada uno de los protocolos que utilizamos. Contiene el nmero del protocolo (que lo identifica unvocamente), la funcin

-7-

(manejador) a la que los protocolos inferiores deben saltar cuando se encuentren una cabecera de este protocolo, y un puntero a una zona de informacin sobre dicho protocolo.
{ typedef struct

uint16 protocol; void (*handler)(void * /* nif */, NBUF * /* buffer */); void *info; /* puntero a informacin configuracin del protocolo*/ } SUP_PROTO;

de

El tipo ETH_ADDR[6] es un array de enteros que define la direccin fsica o MAC


typedef uint8 ETH_ADDR[6];

En fec_init(NIF *nif)lo que se hace es inicializar la estructura NIF pasada como parmetro (fec_nif). Para ello se llama a la funcin nif_init(nif, "mcf5272_fec") (definida en nif.c) que inicializa la estructura fec_nif a los valores por defecto. Tras esto se ajustan los valores de hwa_size (a 6, parece ser la longitud de la estructura ETH_ADDR[6]hwa) y de la MTU (a 1500 octetos, el mximo). Tras esto, se asignan algunas funciones de fec.c (y tambin de nbuf.c) a las funciones definidas en la estructura NIF. Es decir, que desde fec_init() no se llama a estas funciones, sino que con la asignacin, lo que se hace es que, por ejemplo, cada vez que hacemos fec_nif->send se ejecuta el mtodo fec_send() de fec.c. Tras la ejecucin de fec_init(NIF *nif),se escribe la direccin MAC (dada por el usuario en la cabecera del archivo tftp_main.c) en la variable hwa de la estructura NIF fec_nif.

3.1.1 Configuracin de los bferes Ahora es el turno de inicializar los bferes en la funcin nbuf_init(), definida en nbuf.c. Veamos primero para qu sirven los bferes y como es la estructura NBUF que los representa en este programa. El MCF5272 almacena los datos asociados al controlador FEC en la memoria de usuario, ya que es la nica que dispone de suficiente capacidad de almacenamiento. Esta zona esta organizada en bferes que se referencian mediante descriptores de buffer (BDs). Para permitir la mxima flexibilidad los BDs tambin estn situados en la memoria principal. Estos descriptores de buffer estn organizados en tablas y son realmente tiles puesto que disponen de informacin adicional sobre los datos que se almacenan en el buffer. As, el FEC utiliza los campos de los descriptores para indicar errores o eventos, confirmar recepciones o envos La memoria se organiza en dos zonas: Transmit buffer ring y Receive buffer ring. Cada una de ellas tiene una tabla asociada. Estas tablas forman colas circulares o rings.

-8-

Dedicated DMA Unit


Transmit Buffer Ring Recieve Buffer Ring Transmit Block Transmit FIFO Recieve Block Recieve FIFO

Physical Layer

User Memory

RAM

Figura 3: Diagrama de flujo de datos en memoria de MFC5272

Los datos de una trama se pueden almacenar en uno o varios buffer y en la tabla correspondiente los BDs contienen informacin sobre el estado del buffer. Transmisin de tramas. El mdulo de transmisin de ethernet esta diseado para trabajar con la mxima independencia del host. Tan pronto como se habilita al transmisor FEC mediante el bit de ENABLE y se le notifique que hay datos listos para enviar la transmisin dar comienzo el envo. El DMA (Direct Memory Access) transmite 512 bits a la cola de transmisin FIFO. En el momento en que estos 512 bits estn listos comenzar el envo. Sin embargo, si la lnea esta ocupada el controlador retrasa la transmisin mientras la seal carrier sense (indicativo de que el canal esta siendo usado) este activa. Cuando dicha seal pasa a ser inactiva el propio controlador verifica que durante un tiempo (96 periodos de bit) no hay envos, y por tanto, el canal esta listo para transmitir a travs de l. El controlador enva la cabecera, los datos almacenados en los buffer y al alcanzar el tamao de trama aade el checksum. Al mismo tiempo el FEC actualiza el contenido de los descriptores de fichero. Si hay colisiones durante la transmisin de trama, el FEC lleva a cabo el procedimiento de retransmisin. Recepcin de tramas. El mdulo de recepcin de ethernet tambin esta diseado para trabajar con la mxima independencia del host. Cuando se habilita el receptor FEC mediante el bit de ENABLE y se le notifica que la zona de recepcin esta lista comienza la recepcin. Tan pronto como se hayan recibido 512 bits, y no hayan sido rechazados por el algoritmo de reconocimiento de direccin, el FEC transfiere los datos recibidos al buffer de recepcin, actualiza el contenido de los descriptores de fichero y genera las interrupciones correspondientes siempre que no estn enmascaradas. Sin embargo, si la trama es demasiado pequea o la direccin no coincide con lo esperado esta ser rechazada sin parar la ejecucin. Estructura NBUF

-9-

La estructura NBUF representa a los bferes utilizados por el mdulo FEC para transmitir y recibir tramas ethernet. El primer campo es el estado del buffer (preparado para transmitir, vaco, lleno,...). El segundo es la longitud de dicho buffer y el tercero es un puntero a los datos que componen el buffer en s.
{ typedef struct status; length; *data; /* control y estado */ /* longitud de trasferencia */ /* puntero a datos */

uint16 int16 uint8 } NBUF;

En la funcin nbuf_init() se crean los anillos de descriptores de buffer de recepcin NBUF *RxNBUF (8 bferes) y de transmisin NBUF *TxNBUF (2 bferes), se inicializa el estado de cada una de las estructuras NBUF que los forman, se ponen sus longitudes a 0 y se asigna un puntero a un buffer de datos a cada descriptor (*TxBuffer y *RxBuffer). Finalmente se pone a uno el wrap bit en el ltimo de los descriptores de buffer (modifican el estado de la ltima estructura NBUF), y se inicializa a 0 el ndice de descriptores de buffer iTxbd = iRxbd = 0. Tras esto, se configuran los protocolos ARP, IP y UDP como se describe en los siguientes apartados.

3.2

Configuracin del protocolo ARP


Las siguientes estructuras y definiciones (de arp.c) son importantes para entender esta explicacin: La estructura arp_frame_hdr contiene los campos ms importantes de la cabecera ARP: direcciones MAC (o ethernet) e IP de origen y destino, protocolo superior,
{ typedef struct ar_hrd; ar_pro; ar_hln; ar_pln; opcode; ar_sha[6]; ar_spa[4]; ar_tha[6]; ar_tpa[4];

uint16 uint16 uint8 uint8 uint16 uint8 uint8 uint8 uint8 } arp_frame_hdr;

/* /* /* /*

direccin direccin direccin direccin

MAC origen*/ IP origen*/ MAC destino*/ IP destino*/

#define MAX_HWA_SIZE #define MAX_PA_SIZE

(6) (4)

/* longitud de la direccin ethernet */ /* longitud del campo de protocolo */

En las siguientes estructuras se define cmo es una tabla ARP. Esta tabla se utiliza para guardar las direcciones IP conocidas junto con las direcciones MAC correspondientes. De este modo, una vez que hayamos recibido algn paquete desde una

-10-

direccin IP, guardaremos su direccin MAC asociada y no tendremos que preguntar a la red por la direccin MAC asociada a esa IP la prxima vez que lo necesitemos. ARPENTRY representa una entrada de la tabla (par de direcciones MAC/IP) y ARP_INFO es un array de entradas junto con el nmero de entradas disponibles: la tabla ARP.
{ typedef struct protocol; hwa_size; hwa[MAX_HWA_SIZE]; pa_size; pa[MAX_PA_SIZE]; longevity; (10) /*mximo n de entradas en la tabla

uint16 uint8 uint8 uint8 uint8 int } ARPENTRY; ARP*/

#define MAX_ARP_ENTRY

typedef struct tab_size; table[MAX_ARP_ENTRY]; /*n de entradas*/ /*tabla ARP*/

unsigned int ARPENTRY } ARP_INFO;

#define ARP_ENTRY_EMPTY (0) #define ARP_ENTRY_PERM (1) #define ARP_ENTRY_TEMP (2)

La inicializacin del protocolo arp se realiza en la funcin arp_init(&arp_info), a la cual se le pasa como parmetro la estructura ARP_INFO arp_info en el archivo tftp_main.c. En esta funcin se establece MAX_ARP_ENTRY=10 como el nmero mximo de entradas de la tabla ARP (al introducir este valor en el campo tab_size de la estructura arp_info). Despus se recorren todas las ARPENTRY (entradas de la tabla de ARP_INFO) y se inicializan los valores de direccin MAC e IP a 0. Con la funcin nif_bind_protocol(&fec_nif,FRAME_ARP,(void *)arp_handler,(void *)&arp_info) se registra el protocolo ARP en la estructura fec_nif. Para ello se debe incluir el protocolo en la primera posicin libre de la tabla de estructuras SUP_PROTO (que es un campo ms de la estructura NIF fec_nif). Dentro de esta estructura SUP_PROTO existen los campos protocol (en el cual se guarda un entero que identifica al protocolo: FRAME_ARP), *handler (en el cual se guarda un puntero a la funcin arp_handler(), de arp.c) e *info (en el cual se guarda un puntero a la tabla ARP arp_info). De este modo, por ejemplo, cuando hagamos nif->protocol[0].info tendremos un puntero a la tabla ARP (para obtener la estructura ARP_INFO solo tendremos que poner el *)

3.3

Configuracin del protocolo IP

-11-

Al igual que con el protocolo anterior, vamos a incluir las estructuras y constantes ms importantes: /* Direccin IP (32 bits) */
typedef uint8 IP_ADDR[4];

/* Puntero a la direccin IP */

typedef uint8 IP_ADDR_P[];

En la siguiente estructura se aglutinan los campos de una cabecera IP: direcciones IP origen y destino, checksum, protocolo superior, Time To Live (TTL), flags, /* Definition of an IP packet header */
{ typedef struct version_ihl; service_type; total_length; identification; flags_frag_offset; ttl; protocol; checksum; source_addr;/*direccin IP origen*/ dest_addr; /*direccin IP destino*/ options; /* opciones del protocolo IP*/ uint8 uint8 uint16 uint16 uint16 uint8 uint8 uint16 IP_ADDR IP_ADDR uint8 } ip_frame_hdr;

En IP_INFO guardamos los parmetros ms importantes de la comunicacin a nivel IP, como son las direcciones IP origen, la del gateway y tambin la mscara de red, entre otros.
typedef struct { IP_ADDR IP_ADDR IP_ADDR IP_ADDR unsigned unsigned unsigned unsigned } IP_INFO; myip; gateway; netmask; broadcast; rx; rx_unsup; tx; err; /*direccin IP cliente*/ /*direccin IP del gateway*/ /*mascara IP*/ /*direccin IP de broadcast*/

int int int int

La inicializacin comienza con la funcin ip_init(&ip_info,client,gateway,netmask). ip_info es una estructura IP_INFO creada en el archivo tftp_main.c, y que se inicializa en esta funcin con el resto de argumentos. Despus se ejecuta la funcin nif_bind_protocol (&fec_nif,FRAME_IP, (void*)ip_handler, (void*)&ip_info) cuya actuacin es muy similar a la realizada en la llamada del apartado anterior.

3.4

Configuracin del protocolo UDP


-12-

Como en los anteriores protocolos, se define una estructura para guardar los campos de la cabecera del protocolo. En este caso, los puertos origen y destino, entre otros:
{ typedef struct src_port; dest_port; length; chksum; /*puerto origen*/ /*puerto destino*/

uint16 uint16 uint16 uint16 } udp_frame_hdr;

En la siguiente estructura se guardan los puertos en uso junto con un manejador, es decir, una funcin a la que se saltar cuando recibamos un paquete UDP con este puerto como destino. Con esto se puede tener a varias aplicaciones funcionando a la vez utilizando el protocolo UDP con distintos puertos.
typedef struct { uint16 port; void (*handler)(NIF *, NBUF *, int); } UDP_BOUND_PORT;

#define UDP_MAX_PORTS

(5)

/* plenty for this implementation */

static UDP_BOUND_PORT udp_port_table[UDP_MAX_PORTS]; static uint16 udp_port;

Para configurar este protocolo se ejecuta la funcin udp_init(). Aqu se inicializa a cero el campo port de cada una de las estructuras UDP_BOUND_PORT contenidas en el array udp_port_table. El entero udp_port se inicializa a DEFAULT_UDP_PORT, que es el prximo puerto libre por defecto.

3.5

Configuracin del protocolo TFTP

El protocolo TFTP tiene asociada una estructura (TFTP_connection) en la que mantiene variables necesarias para la conexin que va a establecer: direcciones IP, puertos, n de bloque de datos esperado, n de bytes transmitidos, estructura NIF, A continuacin podemos ver con ms detalle la estructura.
typedef struct { /*puntero al siguiente carcter en el anillo de bferes */ uint8 *next_char; /* direccin de la actual conexin */ uint8 dir; /* flag de conexin establecida */ uint8 open; /* puntero a la estructura NIF */ NIF *nif; /* nombre del fichero*/ char *file; /* direccin IP del servidor */ IP_ADDR server_ip; /* puntero al buffer de datos */

-13-

DATA_BUF pkt_data; /* contador de bytres recibidos */ uint32 bytes_recv; /* contador de bytes enviados */ uint32 bytes_sent; /* Puerto UDP del servidor */ uint16 server_port; /* Puerto UDP del cliente */ uint16 my_port; /* nmero de bloque de paquete TFTP esperado */ uint16 exp_blocknum; /* Flag de error */ uint8 error; } TFTP_Connection;

En este punto se imprime un mensaje por pantalla en el que nos avisa de que se comienza a leer el archivo pedido desde el servidor elegido. Sin embargo, an no se ha enviado ni recibido ningn paquete. An falta por configurar la transmisin a nivel fsico y para ello debemos programar adecuadamente algunos registros del mdulo FEC del MCF5272.

3.6

Configuracin del mdulo FEC

Tras imprimir el mensaje anterior, se salta a la funcin tftp_read() en la cual, entre otras cosas, se llama a las funciones tcxn.nif->reset(tcxn.nif) y tcxn.nif->start(tcxn.nif) asociadas a las funciones fec_reset() y fec_start() del mdulo fec.c. Veamos que tareas realiza cada una de ellas. La funcin fec_reset(NIF *nif)hace los siguiente: 1. Resetea el registro ECR. Como podemos ver, esto se hace escribiendo 0x00000001 en dicho registro (activar el bit de reset).

Figura 4: Registro ECR (Ethernet Control Register). Figura obtenida del manual de usuario del MCF5272

2. Deshabilita las interrupciones del FEC escribiendo un 0 en el registro EIMR.

-14-

Figura 5: Registro EIMR (Ethernet Interrupt Mask Register). Figura obtenida del manual de usuario del MCF5272

3. Limpia las interrupciones de EIR. Para ello, escribimos un uno en todos los bits de este registro.

Figura 6: Registro EIR (Interrupt Event register). Figura obtenida del manual de usuario del MCF5272

4. Introducimos la direccin MAC del microcontrolador en los registros MALR (los 4 bytes inferiores) y MAUR (los dos superiores). Este valor lo obtenemos del campo hwa[] de la estructura nif.

Figura 7: Registro MALR (RAM Perfect Match Address Low). Figura obtenida del manual de usuario del MCF5272

-15-

Figura 8: Registro MAUR (RAM Perfect Match Address High). Figura obtenida del manual de usuario del MCF5272

5. Se inicializan a 0 los registros HTUR y HTLR. Estos registros contienen la tabla hash utilizada en la recepcin de tramas multicast. En nuestro programa no aceptamos este tipo de tramas y por ello escribimos un cero en estos registros.

Figura 9: Registro HTUR (Hash Table High Register). Figura obtenida del manual de usuario del MCF5272

Figura 10: Registro HTLR (Hash Table Low Register). Figura obtenida del manual de usuario del MCF5272

6. Fijamos el tamao del buffer de recepcin. Para ello, basta con escribir el tamao elegido en el registro EMRBR. El valor elegido debe ser mltiplo de 16 (por ello, los 3 bits inferiores del registro se fuerzan a cero y las escrituras sobre ellos no tienen efecto). En nuestro caso elegimos 576 (#define RX_BUFFER_SIZE 576)

-16-

Figura 11: Registro EMRBR (Receive Buffer Size Register). Figura obtenida del manual de usuario del MCF5272

7. Obtiene las direcciones de comienzo del anillo de bferes de transmisin y de recepcin, y las guarda en los registros ERDSR y ETDSR respectivamente. Para obtener estas direcciones se llama a la funcin nbuf_get_start(Rx) y nbuf_get_start(Tx).

Figura 12: Registro ERDSR (Point to Receive Descriptor Ring).Figura obtenida del manual de usuario del MCF5272

Figura 13: Registro ETDSR (Point to Transmit Descriptor Ring). Figura obtenida del manual de usuario del MCF5272

8. Elige el modo de transmisin/recepcin MII. Para ello escribimos MCF5272_FEC_RCR_MII_MODE | MCF5272_FEC_RCR_DRT en el registro RCR, o lo que es lo mismo: 0x04 | 0x02. Como podemos ver en la figura siguiente, el primero de los valores pone a uno el bit MII_MODE (modo MII) y el segundo pone a uno el bit DRT, que sirve para deshabilitar la recepcin de tramas durante la transmisin (half duplex). El bit LOOP fija la transmisin/recepcin en modo local (loop-back) y el bit PROM en modo -17-

promiscuo (captura de todas las tramas encontradas independientemente de su direccin MAC de destino)

Figura 14: Registro RCR (Receive Control Register). Figura obtenida del manual de usuario del MCF5272 PROM=1 MII_MODE=1 DRT = 1 LOOP = 1 modo promiscuo (captura de todas las tramas encontradas) modo MII deshabilita recepcin durante la transmisin (half duplex) modo loop-back (transmisin/recepcin en modo local)

9. Tx y rx en half duplex sin heart beat control. Para ello ponemos a cero los bits FDEN, HBC y GTS del registro TCR.

Figura 15: Registro TCR (Transmit Control Register). Figura obtenida del manual de usuario del MCF5272 FDEN=1 HBC=1 GTS = 1 habilita full duplex. heartbeat control. si ocurre colisin durante la tx, sta se paraliza y comienza de nuevo cuando se borre GTS.

En la funcin fec_start(NIF *nif): 1. Se habilita el FEC colocando 0x00000002 en el registro FEC_ECR:

-18-

Figura 16: Registro ECR (Ethernet Control Register). Figura obtenida del manual de usuario del MCF5272 ETHER_EN=1 RESET=1 habilita la recepcin y transmisin de tramas del mdulo FEC se restablecen los valores por defecto de todos los registros

2. Se permiten las interrupciones. Para ello ponemos las siguientes mscaras en el registro EIMR: #define MCF5272_FEC_IMR_RXFEN #define MCF5272_FEC_IMR_RXBEN (0x02000000) (0x01000000)

lo que equivale a poner a uno los bits RXB y RXF (habilita interrupciones por recepcin de trama y/o de buffer)

Figura 17: Registro EIMR (Ethernet Interrupt Mask Register). Figura obtenida del manual de usuario del MCF5272

3. Se le indica al FEC que tiene un buffer de rx vaco escribiendo sobre el registro RDAR: con la escritura de cualquier dato, el bit R_DES_ACTIVE se pone a uno. Cuando el FEC detecte que no hay ningn buffer vaco pondr este bit a cero.

-19-

Figura 18: Registro RDAR (Receive Descriptor Active Register). Figura obtenida del manual de usuario del MCF5272

3.7 Construccin y envo del paquete TFTP


A partir de aqu lo que el programa hace es rellenar las estructuras definidas anteriormente con los parmetros de transmisin dados por el usuario (nombre del archivo, direcciones,) e ir construyendo los paquetes TFTP, UDP e IP (representados por estructuras cuyos campos son los campos de las cabeceras de dichos protocolos y los datos son un puntero al buffer). Para ello, desde tftp_read() se llama a udp_send(), que llama a ip_send() y desde ah (indirectamente) a fec_send() que hace lo siguiente: 1. Copia en la zona del buffer reservada para la cabecera IP, las direcciones IP origen y destino (pasadas como parmetro en la llamada) as como otros valores de dicha cabecera. 2. Marcamos el buffer como preparado para transmitir (con un uno al inicio) e indicamos que el buffer est en uso (escribiendo 0x4000 en el campo status de la estructura pnbuf correspondiente al buffer). 3. Escribimos un 1 en el registro TDAR. Como podemos ver en la figura siguiente, esto es equivalente a indicar al FEC que el buffer est listo para ser transmitido:

Figura 19: Registro TDAR (Transmit descriptor active register). Figura obtenida del manual de usuario del MCF5272

-20-

La escritura (da igual lo que escribamos) sobre este registro provoca que el bit X_DES_ACTIVE se ponga a 1. En cuanto esto sucede, el FEC busca los buffers listos para transmitir. Una vez que no hay ms, resetea este bit. 4. El cdigo nif->f_tx++; sirve para que cuando necesitemos un buffer de nuevo, utilicemos el siguiente (y dejemos as tiempo a que el buffer escrito sea transmitido) Una vez enviado este mensaje de peticin, se espera a recibir los datos del servidor. Para ello, en tftp_main.c se entra en un bucle en el que se ejecuta constantemente la funcin tftp_in_char(). Si hay datos recibidos, la funcin nos da el primer carcter no leido. Si se ha terminado de leer un buffer, se enva un ACK al servidor a la espera de recibir ms tramas. En caso de que la conexin haya sido cerrada, nos devuelve un -1 que indica el fin de la lectura del fichero. Es importante ver que la recepcin de las tramas es transparente al programador: solo hay que poner a disposicin del FEC buffer de llegada y l nos avisar mediante una interrupcin cuando haya datos recibidos. En la rutina de atencin a la interrupcin del FEC (fec_handler(NIF *nif))se hace lo siguiente: Comprobamos que la interrupcin se ha producido debido a la llegada de una trama. Para ello nos quedamos solamente con los bits 25 y 24 del registro de eventos de interrupcin EIR (definidos por las constantes que muestran a continuacin): #define MCF5272_FEC_EIR_RXF #define MCF5272_FEC_EIR_RXB (0x02000000) (0x01000000)

Figura 20 Registro EIR (Interrupt Event register). Figura obtenida del manual de usuario del MCF5272 RXF=1 RXB=1 recepcin de trama producido un nuevo buffer de entrada

Si la interrupcin es debida a la llegada de datos, se resetean estos bits (para que no vuelvan a producir interrupciones) y se salta a la funcin fec_receive(NIF *nif). En esta funcin lo que hacemos es entrar en un bucle en el que vamos recorriendo los bferes de llegada con datos y listos para leer. Lo primero que hacemos es, leyendo el campo protocol de la cabecera ethernet, comprobar que el protocolo superior de la trama -21-

est soportado por la aplicacin. Para ello, basta con comprobar si en el array de estructuras SUP_PROTO incluido como campo en la estructura NIF, se encuentra incluido dicho protocolo: nif->protocol[index].protocol == protocol donde index es un entero que nos sirve para ir recorriendo todo el array. En caso de que est soportado, saltamos al manejador de dicho protocolo, para que se encargue de tratar dicha trama: nif->protocol[index].handler(nif,pNbuf); Por tanto, en caso de recibirse una trama ARP, en la funcin arp_handler() se llevan a cabo las acciones oportunas (guardar la direccin MAC e IP en la tabla ARP, responder,). En el caso que nos interesa, recibiremos una trama IP y por tanto saltaremos a la funcin ip_handler() y de sta a udp_handler(). En estas funciones se comprueba que las cabeceras son correctas, se eliminan y se llama al nivel superior. Finalmente, llegamos a tftp_handler(), que prepara el buffer para ser ledo por tftp_in_char(): pone el nmero de bytes de datos recibidos en tcxn.pkt_data.bytes y apunta al primero con tcxn.next_char, puntero que utiliza tftp_in_char() para obtener los datos. Finalmente, resaltar que cada dato obtenido por tftp_in_char() es introducido en la posicin correspondiente de la memoria de usuario (posicin inicial: USERNAME=60000, direccin de comienzo de la SDRAM)

Envo de un fichero al servidor

La escritura de un fichero en el servidor es muy similar a la lectura del mismo, ya que en ambas operaciones es necesario intercambiar mensajes entre el cliente (nuestro programa) y el servidor. La principal diferencia radica en que en la lectura, el cliente pide el fichero y luego se limita a confirmar los paquetes que le llegan del servidor (ver figura 1), mientras que en la escritura es l el que se encarga de enviar el fichero, y el servidor el que confirma los paquetes llegados (figura 2). Debido a las similitudes que describamos antes, las funciones involucradas en la escritura son prcticamente las mismas que en el caso anterior. Cuando ejecutamos el comando write en el cliente de TFTP ocurre lo siguiente 1. Saltamos a la funcin write() de tftp_main.c. 2. En esa funcin se inicializa un timer para controlar el tiempo de espera en escritura. 3. Se permite las interrupciones del FEC (actuando sobre el bit correspondiente del registro ICR).

-22-

4. Se salta a la funcin fec_init (NIF *nif) que inicializa la estructura NIF vista anteriormente. 5. Tras esto, se crea el anillo de bferes de llegada y de salida. 6. Se configuran los protocolos ARP, IP y UDP. 7. Una vez realizadas estas tareas (comunes al apartado 3) se salta a la funcin tftp_write(&fec_nif, fn, server, USERSPACE, USERSPACE + bytes) donde nif es la estructura inicializada con anterioridad, fn el nombre del fichero, server la direccin IP del servidor, USERSPACE es la direccin de memoria donde estn los datos a enviar y bytes el nmero de bytes a transmitir (especificados en la llamada al comando write). Aunque esta funcin no es usada en el apartado anterior, realiza tareas muy similares a su anloga tftp_read(): 8. crea y enva un paquete TFTP de peticin de escritura en servidor para lo que tiene que ir completando las cabeceras de los protocolos involucrados: TFTP, UDP e IP, utilizando para ello las mismas funciones que se utilizaban en la lectura: de tftp_write() se llama a rwrq() que se encarga de realizar la peticin de escritura, enviando para ello un paquete UDP con los datos adecuados a travs de udp_send(), la cual llamar a ip_send() y sta a fec_send() que se encargar de programar los registros necesarios (los mismos que en el apartado 3.7). 9. Una vez enviado el mensaje de peticin, se espera el ACK de confirmacin para comenzar con el envo de los datos en paquetes de 512 bytes, tal y como indica la figura 2.

-23-

Anexo 1: Ficheros
Fichero
Arp.c

Funciones relevantes
arp_find_pair(..) y arp_handler()

Descripcin
Funciones para tratar las tramas ARP y establecer una relacin entre direccin IP y MAC Contiene las definiciones de la cabecera de la trama ARP, la tabla ARP y otras constantes

Arp.h Ejemplo_TFTP.c Eth.h Fec.c Fec_reset(), fec_send(), fec_receive(), fec_handler() bucleMain(void)

Es el programa principal. Contiene la definicin de las rutinas de atencin a las interrupciones Define constantes importantes para el protocolo Ethernet Contiene las funciones necesarias para inicializar el mdulo FEC, as como para enviar tramas Ethernet, recibirlas y tratar las interrupciones de dicho mdulo. Fichero de definicin del mdulo Fec.c Funciones necesarias para tratar un paquete ICMP Define mediante estructuras los paquetes ICMP ms comunes

Fec.h Icmp.c Icmp.h Ip.c Ip.h M5272.h M5272c3.h M5272lib.c outNumDec(), output(), asm_set_ipl(int) Ip_send(), Ip_handler()

Funciones necesarias para tratar el envo y recepcin de paquetes IP Cabecera de los paquetes IP y constantes ms importantes de este protocolo Contiene las direcciones de los registros del MCF 5272, as como macros para acceder a ellos Define las memorias usadas y sus direcciones de comienzo y fin. Funciones que usan recursos a bajo nivel, por lo que estn implementadas en ensamblador Definicin de los tipos BOOL, BYTE, WORD, LONG, Definicin de los tipos bsicos y de constantes utilizadas a lo largo del programa

M5272lib.h Mcf5xxx.h Nbuf.c nbuf_init()

Con las funciones de este archivo se crean y gestionan los anillos de bferes de lectura y -24-

escritura Nbuf.h Nif.c Nif_init(), nif_protocol_ha ndler() Definicin de la estructura de un buffer y otras constantes involucradas en su manejo Funciones para inicializar la estructura nif, as como para registrar los protocolos tratados y sus handlers, y saltar a estos handler cuando se reciba una trama con la cabecera de su protocolo Estructuras y constantes utilizadas a nivel fsico Define las rutinas a las que debemos saltar cuando recibimos una determinada interrupcin Funciones para trabajar con cadenas de texto Interface de stdlib.c Contiene las funciones de envo y recepcin de paquetes TFTP: Tftp_write(), tftp_read(), tftp_inchar(), tftp_handler() Tftp.h Peticin de escritura de un fichero al servidor Peticin de un fichero al servidor Lectura de los datos recibidos, una vez y eliminadas todas las cabeceras Tratamiento de paquetes TFTP recibidos Define la cabecera de los paquetes TFTP, los parmetros de una conexin TFTP y otras constantes de inters de esta aplicacin main_tftp(),re ad(), write(), help(), set(), setxxx(), show(), md() Creacin de las variables necesarias para la comunicacin entre cliente y servidor, definicin de los comandos del cliente TFTP y las funciones que implementan cada uno de ellos Definicin de los comandos usados en el cliente de TFTP Timer_start(), timer_stop(), timer_get_refere nce() Udp_send(), udp_handler() Funciones para arrancar, parar y leer los temporizadores del microcontrolador. Sern utilizadas para temporizar retransmisiones de paquetes perdidos, Constantes y estructuras utilizadas en timer.c Funciones para enviar y tratar paquetes UDP Define la cabecera UDP y otras constantes utilizadas por este protocolo

Nif.h Start.asg Stdlib.c Stdlib.h Tftp.c

Tftp_main.c

Tftp_main.h Timer.c

Timer.h Udp.c Udp.h

-25-

Anexo 2: Estructuras
Estructura
arp_frame_hdr ARPENTRY CMD eth_frame_hdr ip_frame_hdr NBUF SUP_PROTO NIF SETCMD

Descripcin
Define la cabecera de las tramas ARP Representa la tabla de pares de dir ARP-IP Definicin de un comando TFTP Define la cabecera de las tramas Ethernet Cabecera de las tramas IP Estructura de un buffer de datos Array con los protocolos soportados y sus handlers Contiene todas las variables y funciones para la transmisin a nivel fsico Definicin de los argumentos de los comandos set/show para trabajar con las variables de la comunicacin Contiene las posibles cabeceras de los paquetes TFTP:rwrq,data,ack,error,generic Estructura que almacena los parmetros de una conexin TFTP Establece una relacin entre un nmero de puerto UDP y un handler que maneja los paquetes destinados a ese puerto Define la cabecera del paquete UDP

Fichero donde esta definida Arp.h Arp.h Tftp_main.h Eth.h Ip.h Nbuf.h Nif.h Nif.h Tftp_main.h

TFTPpacket TFTP_Connection UDP_BOUND_PORT

Tftp.h Tftp.h Udp.c

udp_frame_hdr

Udp.h

-26-

Anexo 3: Registros del Mdulo Ethernet


Registro
ECR EIMR EIR MALR MAUR HTUR HTLR EMRBR ERDSR ETDSR RCR R_BUF_SIZE R_DES_START X_DES_START PROM MII_MODE DRT LOOP TCR FDEN HBC GTS RDAR TDAR R_DES_ACTIVE X_DES_ACTIVE

Campos Importantes
ETHER_EN RESET Cada bit define una interrupcin Cada bit define una interrupcin

Valor
0/1 1 0/1 1 Bytes 1,2,3,4 de la MAC 0 0 576 nbuf_get_start(rx) nbuf_get_start(tx) 0 1 1 0 0 0 0 Cualquier escritura 1

Descripcin
Habilita/deshabilita FEC Resetea el FEC Interrupcin habilitada/deshabilitada Borra interrupcin pendiente Parte baja de la direccin MAC

Bytes 5,6 de la MAC Parte alta de la direccin MAC Parte alta de la Hash Table utilizada en multicast Parte baja de la Hash Table Tamao del buffer de rx Direccin de comienzo del anillo de bferes de rx Direccin de comienzo del anillo de bferes de tx Modo promiscuo deshabilitado Modo MII Half dplex Modo bucle local Half dplex Sin heartbeat control Sin espera de tx en caso de colisin Indicacin de buffer de rx vaco Buffer de tx listo para ser transmitido

-27-

Potrebbero piacerti anche