1. Trang chủ
  2. » Luận Văn - Báo Cáo

ATMEGA32 GIAO TIẾP VỚI ENC28J60 QUA SPI – AVR WEBSERVER

149 701 7

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 149
Dung lượng 1,87 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

ATMEGA32 GIAO TIẾP VỚI ENC28J60 QUA SPI – AVR WEBSERVER Atmega32 giao tiếp với ENC28J60 qua SPI (MOSIMISOSCK) ngoài ra còn có chân chọn chip CS (nối với bất cứ IO nào của Atmega) và ngắt INT (nối vào ngắt ngoài VĐK). ENC28J60 dùng nguồn 3V3, do đó cần 1 IC ổn áp 3V3. ENC28J60 cần 1 port RJ45 có tích hợp sẵn Transformer và LED. Thêm MAX232 để dùng vào mục đích debug. Thêm LCD và keypad (dùng để config hay hiển thị gì đó sau này). Nếu không cần có thể bỏ ra.

Trang 1

ATMEGA32 GIAO TIẾP VỚI ENC28J60 QUA SPI – AVR WEBSERVER

- Thêm MAX232 để dùng vào mục đích debug

- Thêm LCD và keypad (dùng để config hay hiển thị gì đó sau này) Nếu không cần có thể bỏ ra

2 C s giao th c và thi t k l u đ d li u ơ sở giao thức và thiết kế lưu đồ dữ liệu ở giao thức và thiết kế lưu đồ dữ liệu ức và thiết kế lưu đồ dữ liệu ết kế lưu đồ dữ liệu ết kế lưu đồ dữ liệu ưu đồ dữ liệu ồ dữ liệu ữ liệu ệu

Cụ thể hóa và lưu đồ dữ liệu vào ra của giao thức (áp dụng cho phần lập trình)

Như vậy phần lập trình sẽ chia ra các module sau:

- Module điều khiển ENC28J60: nằm trong file “enc28j60.c” và file header “enc28j60.h”, thêm file

“enc28j60conf.h” để lưu các config

Trang 2

- Module giao thức Ethernet: gồm các file: “ethernet.c” và “ethernet.h”, thêm file "packet.h" khai báo các cấu trúc gói tin sử dụng trong bộ giao thức TCP/IP.

- Module giao thức phân giải địa chỉ Address Resolution Protocol, gồm file “arp.c” và “arp.h”

- Module giao thức IP gồm “ip.c” và “ip.h”

- Module giao thức cấp phát địa chỉ IP động DHCP (Dynamic Host Configuration Protocol) gồm các file

“dhcp.c” và “dhcp.h”

- Module giao thức UDP gồm các file “udp.c” và “udp.h”

- Module giao thức TCP gồm các file “tcp.c” và “tcp.h”

- Module giao thức HTTP gồm các file “http.c” và “http.h”

- Và một số các hàm hỗ trợ khác (uart, timer,…)

Sau khi tạo project, ta sẽ có source file đầu tiên là “ntAVRnet.c”.

Mở file này, thêm vào hàm main, chương trình chính, nội dung hàm này sẽ được viết cuối cùng

Trang 3

Bài 3: L p trình đi u khi n ENC28J60: ập trình điều khiển ENC28J60: ều khiển ENC28J60: ển ENC28J60:

Phần này có tham khảo các project open source của nước ngoài, thông tin về tài liệu tham khảo

sẽ được nêu cụ thể ở cuối tut

Tạo các file “enc28j60.c”, “enc28j60.h” và “enc28j60conf.h” Add vào project

ENC28J60 được điều khiển bởi một tập khá lớn các thanh ghi điều khiển, dữ liệu (frame ehternet gửi/nhận) được lưu trữ trên 1 buffer Việc đọc/ghi vào các thanh ghi điều khiển cũng như buffer

dữ liệu được thực hiện qua giao tiếp SPI tới 1 địa chỉ xác định.

Mở file enc28j60.h, khai báo địa chỉ các thanh ghi vào file

// ENC28J60 Control Registers

// Control register definitions are a combination of address,

// bank number, and Ethernet/MAC/PHY indicator bits

// - Register address (bits 0-4)

// - MAC/PHY indicator (bit 7)

Trang 4

#define EDMADSTH (0x15|0x00)

#define EDMACSL (0x16|0x00)

#define EDMACSH (0x17|0x00)// Bank 1 registers

Trang 7

#define TXSTART_INIT 0x0000 //Dia chi bat dau buffer gui

#define TXSTOP_INIT 0x05FF //Dia chi ket thuc buffer gui

#define RXSTART_INIT 0x0600 //Dia chi bat dau buffer nhan

#define RXSTOP_INIT 0x1FFF //Dia chi ket thuc buffer nhan

//Khai bao kich thuoc frame ethernet max va min

//Dinh nghia macro chon chip ENC28J60

#define ENC28J60_CS_LO() ENC28J60_CONTROL_PORT &=

Trang 8

#if defined ( AVR_ATmega32 )

#define ETH_INT_ENABLE GICR |= (1<<INT2)

#define ETH_INT_DISABLE GICR &= ~(1<<INT2)

#endif

#if defined ( AVR_ATmega644 ) || defined ( AVR_ATmega644P )

#define ETH_INT_ENABLE EIMSK |= (1<<INT2)

#define ETH_INT_DISABLE EIMSK &= ~(1<<INT2)

#endif

// MAC address for this interface

#ifdef ETHADDR0

#define ENC28J60_MAC0 ETHADDR0

#define ENC28J60_MAC1 ETHADDR1

#define ENC28J60_MAC2 ETHADDR2

#define ENC28J60_MAC3 ETHADDR3

#define ENC28J60_MAC4 ETHADDR4

#define ENC28J60_MAC5 ETHADDR5

// -Trước hết ta cần 1 hàm đọc và 1 hàm ghi dữ liệu vào 1 địa chỉ xác định trên ENC28J60 qua SPI:

Mở file enc28j60.c, thêm vào các hàm (sau đó nhớ thêm khai báo hàm vào file header

enc28j60.h nữa nhé)

Code:

// Writen by NTTam - PTITHCM

// -{

unsigned char res;

ENC28J60_CS_LO();

SPDR = op | (address & ADDR_MASK);

while(!(SPSR & (1<<SPIF)));

Trang 9

SPDR = op | (address & ADDR_MASK);

while(!(SPSR & (1<<SPIF)));

SPDR = data;

while(!(SPSR & (1<<SPIF)));

ENC28J60_CS_HI();

}

ENC28J60 chia tập thanh ghi thành các bank, ta viết 1 hàm để set bank thanh ghi:

Trước hết ta khai báo 1 biến kiểu char để lưu bank hiện tại (thêm vào đầu file):

Trang 10

Các hàm trên cho phép truy xuất đầy đủ vào tập thanh ghi của ENC28J60

Tiếp theo ta viết tiếp 2 hàm gửi và nhận 1 gói tin:

Trang 11

unsigned int NextPacketPtr;

unsigned int enc28j60PacketReceive(unsigned int maxlen, unsigned char* packet){

unsigned int rxstat;

unsigned int len;

Code:

prog_char enc28j60_config[44] PROGMEM = {

ETXSTL, LO8(TXSTART_INIT), //start lo

ETXSTH, HI8(TXSTART_INIT), //start hi

ETXNDL, LO8(TXSTOP_INIT ), //end lo

ETXNDH, HI8(TXSTOP_INIT ), //end hi

ERXSTL, LO8(RXSTART_INIT), //start lo

ERXSTH, HI8(RXSTART_INIT), //start hi

ERXNDL, LO8(RXSTOP_INIT ), //end lo

ERXNDH, HI8(RXSTOP_INIT ), //end hi

MACON1, (MACON1_MARXEN | MACON1_RXPAUS | MACON1_TXPAUS),

MACON3, ( MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN),

Trang 12

unsigned short delay_loops;

register unsigned short i;

delay_loops = (time_us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)

// one loop takes 5 cpu cycles

for (i=0; i < delay_loops; i++) {};

#define LO8(x) ((x)&0xFF)

#define HI8(x) (((x)>>8)&0xFF)

#endif //NTAVRNET_H

Và đây là hàm khởi động ENC28J60:

Trang 13

(1<<ENC28J60_SPI_SCK); //SS,MOSI,SCK = OUT

ENC28J60_SPI_DDR &= ~(1<<ENC28J60_SPI_MISO); //MISO = IN

SPCR = (0<<SPIE)|(1<<SPE)|(0<<DORD)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA)|(0<<SPR1)|(0<<SPR0);

Anh mún cho code vào khung thì anh wrap[quote] html[quote] php[quote]=> ([QUOTE]copy

Trang 14

code here[QUOTE]) là okey anh.

Và kết quả là như thế này:

unsigned char enc28j60SPIRead(unsigned char op, unsigned char address) {

unsigned char res;

ENC28J60_CS_LO();

SPDR = op | (address & ADDR_MASK);

while(!(SPSR & (1<<SPIF)));

Trang 15

Bài 4: L p trình giao th c ethernet ập trình điều khiển ENC28J60: ức và thiết kế lưu đồ dữ liệu

HO T Đ NG C A TCP/IP ẠT ĐỘNG CỦA TCP/IP ỘNG CỦA TCP/IP ỦA TCP/IP

- Dữ liệu truyền từ ứng dụng, đến một trong 2 giao thức vận chuyển (TCP hay UDP) Một gói tin hay đơn vị dữ liệu (PDU) của TCP/UDP thường được gọi là segment (đoạn dữ liệu).

- Đoạn dữ liệu xuống lớp Internet, ở đó giao thức IP cung cấp thông tin đánh địa chỉ luận lý (địa chỉ IP) và đóng gói dữ liệu vào 1 datagram, thường được gọi là gói tin IP (IP packet).

- Datagram IP đến lớp truy cập mạng (ở đây là giao thức ethernet), và được đóng gói vào 1 hay nhiều khung dữ liệu (frame ethernet), sau đó đưa xuống tầng vật lý (ví dụ IC ENC28J60) để gửi

đi Khung dữ liệu được chuyển thành một luồng các bit để truyền đi trên môi trường mạng.

Ở phía thu, quá trình xảy ra ngược lại, tầng vật lý sẽ nhận luồng bit, khôi phục lại frame dữ liệu, giao thức ethernet phía nhận sẽ xử lý frame dữ liệu này, tách ra gói tin IP (IP packet) và đẩy lên giao thức IP nếu đây là gói IP Còn trong trường hợp bên trong frame ethernet không phải là 1 gói IP mà là 1 gói tin của giao thức ARP thì nó sẽ đẩy gói này sang cho giao thức ARP xử lý (xem lại hình minh họa lưu đồ dữ liệu giữa các giao thức).

Tại tầng giao thức IP, gói IP sẽ được xử lý, xác định xem dữ liệu chứa bên trong là của giao thức nào (TCP, UDP, hay ICPM) và chuyển đến giao thức tương ứng để xử lý tiếp theo.

Cuối cùng, giao thức kế (TCP, UDP, hay ICMP sẽ xử lý tiếp segment dữ liệu nhận được, xác định xem dữ liệu này là của ứng dụng nào (ví dụ như HTTP hay DHCP,…) và chuyển dữ liệu đến ứng dụng tương ứng

Trước hết, ta cần nắm rõ cấu trúc của tất cả các gói tin của mỗi giao thức để có thể xử lý được thông tin chứa trong nó.

Ta tạo 1 file header mới là “packet.h”, file này sẽ dùng để chứa mô tả cấu trúc của tất cả các gói tin của các giao thức sử dụng trong project này:

Code:

// Writen by NTTam - PTITHCM

// -#ifndef PACKET_H

#define PACKET_H

#endif //PACKET_H

Trước hết ta tìm hiểu cấu trúc 1 frame ethernet:

Như vậy 1 frame ethernet bắt đầu bắng các byte Preamble để dồng bộ và 1 byte Start of Frame

để xác định đầu frame (phần này sẽ được ENC28J60 tự động lược bỏ, ta không cần quan tâm) Tiếp theo là địa chỉ MAC của host nhận (destination address), địa chỉ MAC của host gửi (source address), mỗi địa chỉ MAC này gồm 6 byte Kế đến là 2 byte length (cho biết chiều dài) hoặc type (cho biết dữ liệu chứa trong frame là loại dữ liệu của giao thức lớp trên nào) Kế đến là dữ liệu Cuối cùng là phần kiểm tra lỗi (FCS), phần này cũng được ENC28J60 xử lý, ta không quan tâm.

Như vậy ta cần khai báo cấu trúc của header frame ethernet (từ phần địa chỉ đến 2 byte type) trong file “packet.h”

Trước hết ta định nghĩa 1 struc cho địa chỉ MAC:

Trang 16

-

// -//Dia chi vat ly hay dia chi MAC (lop Ethernet)

// -//Ethernet header

// Gom 14 byte:

// 06 byte dia chi dich

// 06 byte dia chi nguon

// 02 byte type (cho biet frame ethernet mang ben trong loai du lieu gi)

#define ETH_HEADER_LEN 14

struct ntEthHeader

{

struct ntEthAddr desAddr;

struct ntEthAddr srcAddr;

unsigned int type;

Code:

-

// -//Ethernet header 802.1q VLAN Tagging

struct ntEth802_1qHeader

{

struct ntEthAddr desAddr;

struct ntEthAddr srcAddr;

unsigned int type;

unsigned int TPID;

unsigned int PCP_CFI_VID;

};

Trang 17

// -//Ethernet header 802.1ad Q-in-Q VLAN Tagging

struct ntEth802_1adHeader

{

struct ntEthAddr desAddr;

struct ntEthAddr srcAddr;

unsigned int type;

unsigned int OuterTPID;

unsigned int OuterPCP_CFI_VID;

unsigned int InnerTPID;

unsigned int InnerPCP_CFI_VID;

// -//Cau truc MPLS Header

struct ntMPLSHeader

{

unsigned int HighLabelValue;

unsigned char TrafficClass_Stack;

Trong mỗi frame ethernet đều chứa 2 địa chỉ MAC: một địa chỉ của host gửi và 1 địa chỉ của host nhận

khi lớp ethernet nhận được 1 frame dữ liệu, trước hết nó sẽ kiểm tra địa chỉ host nhận xem có phải là địa chỉ của nó không (tức là gửi cho nó), nếu đúng nó sẽ nhận frame này và chuyển đến lớp IP Ngoài ra còn có 1 trường hợp nữa lớp ehternet sẽ nhận frame: đó là nếu địa chỉ host nhận

là địa chỉ broadcast (tức là gửi cho tất cả mọi máy trong mạng LAN), trong trường hợp này frame sẽ được nhận và xử lý.

Ngoài việc kiểm tra địa chỉ, trong frame ethernet còn có 1 trường chứa mã kiểm tra lỗi giúp phát

Trang 18

hiện những lỗi xảy ra trong quá trình truyền, các frame bị xác định là có lỗi sẽ bị bỏ qua.

Trong mạch của chúng ta, việc kiểm tra lỗi và kiểm tra địa được thực hiện tự động bởi IC

ENC28J60, do đó ta không cần lập trình cho các chức năng này Mỗi khi nhận được 1 frame trên đường truyền, ENC28J60 sẽ kiểm tra lỗi xem có sai sót không, tiếp đó nó sẽ đối chiếu địa chỉ host nhận với địa chỉ đã được cấu hình cho nó (trong các thanh ghi địa chỉ MAC: MAADR0-5) Nếu không có lỗi và địa chỉ là gửi cho nó, nó sẽ tạo 1 ngắt cứng (trên chân INT của ENC28J60)

để báo cho VĐK biết là nó vừa nhận được 1 frame hợp lệ và yêu cầu VĐK xử lý frame này Vậy công việc của chúng ta là viết hàm xử lý cho trường hợp này, cũng như cung cấp 1 hàm gửi

đi 1 frame dữ liệu (để sử dụng khi muốn gửi dữ liệu đi) Bên cạnh đó ta cũng cần một số hàm cung cấp các chức năng bổ sung như set/get địa chỉ MAC,…

Tạo 1 file source "ethernet.c" để viết module ethernet và file header cho nó "ethernet.h"

File ethernet.c

Code:

// Writen by NTTam - PTITHCM

// -#ifndef ETHERNET_H

#define ETHERNET_H

#endif //ETHERNET_H

Lập trình cho giao thức ethernet (tiếp theo)

Trước hết, ta khai báo 1 buffer trên bộ nhớ RAM của VĐK để lưu trữ frame dữ liệu mà ta cần xử lý.

Kích thước của buffer này sẽ bằng kích thước lớn nhất của 1 segment dữ liệu mà hệ thống của ta

có thể xử lý (MTU) + kích thước header TCP + kích thước header UDP + kích thước header của frame.

Trong đó:

- Với giao thức TCP/IP thì MTU max là 1460

- Kích thước Header của TCP là 20 bytes

- Kích thước Header của IP là 20 bytes (ở đây xem như không có trường Option trong Header IP, cấu trúc gói IP sẽ được giải thích chi tiết ở phần lập trình cho giao thức IP).

Trang 19

- Kích thước Header của frame Ethernet là 14 byte.

Vậy trước hết ta thêm các khai báo kích thước này vào file “ethernet.h”

Sau đó khai báo buffer dành cho frame ethernet trong file source (“ethernet.c”):

Code:

unsigned char ethBuffer[ETHERNET_BUFFER_SIZE];

Tiếp theo ta viết một số hàm cung cấp các chức năng cơ bản cho lớp ethernet:

Code:

//Ham khoi tao chip Ethernet

// -//Ham goi 1 frame xuong chip ethernet

void ethSendFrame(unsigned int len, unsigned char* packet)

{

enc28j60PacketSend(len, packet);

}

-

// -//Ham doc 1 frame ethernet tu chip ethernet ve buffer tren RAM cua CPU

unsigned int ethGetFrame(unsigned int maxlen, unsigned char* packet)

{

return enc28j60PacketReceive(maxlen, packet);

}

-

// -//Ham doc dia chi MAC hien tai tu chip ethernet, luu vao buffer macaddr[6]void ethGetMacAddress(unsigned char* macaddr)

{

*macaddr++ = enc28j60Read(MAADR5);

Trang 20

// -//Ham set dia chi MAC (dang luu trong buffer macaddr[6] xuong chip ethernetvoid ethSetMacAddress(unsigned char* macaddr)

// -//Ham tra lai con tro den buffer ethernet (tren RAM cua CPU)

unsigned char* ethGetBuffer(void)

Code:

unsigned char enc28j60SPIRead(unsigned char op, unsigned char address);

// -void enc28j60SPIWrite(unsigned char op, unsigned char address, unsigned char data);

void enc28j60SetBank(unsigned char address);

void enc28j60ReadBuffer(unsigned int len, unsigned char* data);

void enc28j60WriteBuffer(unsigned int len, unsigned char* data);

unsigned char enc28j60Read(unsigned char address);

void enc28j60Write(unsigned char address, unsigned char data);

unsigned int enc28j60PhyRead(unsigned char address);

void enc28j60PhyWrite(unsigned char address, unsigned int data);

void enc28j60PacketSend(unsigned int len, unsigned char* packet);

unsigned int enc28j60PacketReceive(unsigned int maxlen, unsigned char*

packet);

void delay_us(unsigned short time_us);

void enc28j60Init(void);

Tiếp theo ta viết phần xử lý khi ENC28J60 nhận được 1 frame dữ liệu hợp lệ.

Như đã nói trước đó, khi ENC28J60 nhận được 1 frame dữ liệu hợp lệ, nó sẽ tạo 1 ngắt để báo cho VĐK biết và xử lý dữ liệu nhận được này Như vậy ta cần viết một ISR ngắt tương ứng cho

sự kiện đó:

Code:

-

// -//Vector ngat cua ethernet, mot ngat ngoai se duoc khoi tao boi chip ethernet// moi khi no nhan duoc 1 frame ethernet (dung dia chi cua no)

ISR (ETH_INTERRUPT)

Trang 21

unsigned char eth_got_frame = 0;

volatile unsigned int time_watchdog;

Giải thích: thay vì viết toàn bộ phần xử lý trong hàm ngắt (ISR), trong hàm ngắt ta chỉ đơn giản

là set biến eth_got_frame = 1 để báo cho biết có 1 frame đang chờ xử lý, biến này

(eth_got_frame) sẽ liên tục được kiểm tra bởi hàm dịch vụ ethernet (ethService) mà ta sẽ viết sau đây, hàm này (ethService) sẽ liên tục được gọi trong 1 vòng lặp ở chương trình chính (hàm main trong file “ntAVRnet.c”) để thực thi liên tục.

Cách viết này nhằm tránh xảy ra hiện tượng ngắt chồng ngắt, có thể dẫn đến chương trình thực thi không đúng mong muốn do nội dung hàm ngắt quá dài, chưa thực thi xong đã xảy ra 1 ngắt khác.

Còn biến time_watchdog là một biến nhằm phát hiện các lỗi dẫn đến treo các giao thức mạng hoặc IC ENC28J60 Biến này sẽ được tăng liên tục bởi timer nhưng lại được reset về 0 mỗi khi nhận được 1 frame ethernet mới, điều này cho phép phát hiện 1 khoảng thời gian quá lâu mà ta không nhận được frame ethernet nào (khi biến time_watchdog tăng đến một giá trị ngưỡng), khi

đó ta giả thiết là ENC28J60 bị treo hay phát sinh lỗi, lúc đó ta sẽ gọi hàm reset IC này và khởi động lại giao thức ethernet Điều này trong thực tế rất hữu ích, nó giúp mạch của chúng ta chạy

ổn định hơn rất nhiều.

Đồng thời ta cũng disable ngắt ngoài này trong thời gian chờ xử lý frame.

Vậy ta viết tiếp phần xử lý frame ethernet trong hàm ethService như sau:

Code:

-

// -//Ham duoc goi lien tuc de thuc thi cac tac vu cua giao thuc ethernet

// look for a packet

len = ethGetFrame(ETHERNET_BUFFER_SIZE, ethBuffer);

if(len)

{

ethPacket = (struct ntEthHeader*)&ethBuffer[0];

#ifdef ETH_DEBUGprintf("Received packet len: %d, type:", len);

Trang 22

#endifif(ethPacket->type == HTONS(ETH_TYPE_IP))//Neu day la frame danh cho giao thuc IP{

#ifdef ETH_DEBUGprintf("IP packet\r\n");

#endifarpIPPacketIn((unsigned char*)&ethBuffer[0]);

IPProcess( len-ETH_HEADER_LEN, (struct ntIPHeader*)&ethBuffer[ETH_HEADER_LEN] );

}else if(ethPacket->type == HTONS(ETH_TYPE_ARP))//Neu day la 1 frame cua giao thuc ARP

{

#ifdef ETH_DEBUGprintf("ARP packet\r\n");

#endifarpArpProcess(len, ethBuffer );

}else{

#ifdef ETH_DEBUGprintf("Unknown packet:%x\r\n",ethPacket->type);

#endifethInit();

}ETH_INT_ENABLE;

}

return;

}

-

// -Giải thích:

Hàm này khi phát hiện có frame mới (biến eth_got_frame khác 0) thì tiến hành kiểm tra trường Type trong header frame ethernet để xem dữ liệu chứa trong frame là của giao thức nào (IP hay ARP) và sẽ gọi hàm tương ứng của giao thức đó để xử lý.

Có một lưu ý quan trọng là trong trình biên dịch gcc (cũng như các trình biên dịch ngôn ngữ C khác cho AVR), đối với các biến có kích thước lớn hơn 1 byte (int, double, long,…) thì thứ tự các byte trong bộ nhớ của AVR được sắp xếp theo thứ tự ngược lại với thứ tự trong các header của gói tin (frame ethernet, IP packet,…) Do đó khi đọc các biến này ra từ buffer ethernet cũng như trước khi ghi vào buffer, ta phải đổi thứ tự các byte này Ta viết một số macro cho mục đích này và lưu luôn trong file “packet.h” để sử dụng sau này.

Code:

-

// -#define HTONS(s) ((s<<8) | (s>>8)) //danh cho bien 2 byte

#define HTONL(l) ((l<<24) | ((l&0x00FF0000l)>>8) |

((l&0x0000FF00l)<<8) | (l>>24)) //danh cho bien 4 byte

//

Lưu ý là trong hàm này ta có gọi các hàm của giao thức lớp trên (IP và ARP) Đó là các hàm arpIPPacketIn, IPProcess, và arpArpProcess Các hàm này ta vẫn chưa viết nên khi biên dịch file

“ethernet.c” sẽ có báo lỗi thiếu các hàm này.

Để cho mục đích debug sau này, trong hàm ta có sử dụng hàm xuất ra cổng serial là printf Hàm này các bạn tự viết lấy dùng uart nhé Trong nội dung hướng dẫn này tập trung vào giao thức

Trang 23

TCP/IP thôi.

Sau khi xử lý xong frame, ta cần enable ngắt ngoài trở lại.

Đến đây là cơ bản xong giao thức ethernet, tiếp theo sẽ là giao thức IP và ARP, rắc rối hơn nhiều.

Trang 24

Bài 5: L p trình cho giao th c IP (Internet Protocol) và giao th c ARP ập trình điều khiển ENC28J60: ức và thiết kế lưu đồ dữ liệu ức và thiết kế lưu đồ dữ liệu (Address Réolution Protocol)

Trước hết, ta cần tìm hiểu về hoạt động của giao thức IP.

(phần này viết một cách đơn giản và dễ hiểu nhất cho dân điện tử, không chuyên về network có thể hiểu phần nào hoạt động của các giao thức để có thể hiểu code và tự viết code, dân IT vào đọc đừng cười nhé)

Cách thức mà dữ liệu được gửi qua giao thức IP được tiến hành như sau:

- Khi nhận được 1 segment dữ liệu (từ giao thức lớp trên là TCP hay UDP) cần gửi đến đích nào

đó, địa chỉ đích này phải được xác định bằng địa chỉ IP (tức là địa chỉ mạng hay địa chỉ luận lý) Lớp giao thức IP sẽ gắn thêm vào đầu segment dữ liệu một header IP để tạo thành gói IP hoàn chỉnh Trong header IP này có chứa 2 thông tin quan trọng, đó là địa chỉ host gửi (source IP address) và địa chỉ host nhận (destination IP address) Địa chỉ source đương nhiên là địa chỉ của bản thân nó, còn địa chỉ đích phải được cung cấp cho lớp IP khi muốn gửi dữ liệu qua giao thức này.

- Gói tin IP này sau đó được chuyển đến lớp giao thức ethernet để thêm phần header ethernet vào

và gửi đi.

- Nhưng như ở phần trước ta đã biết, giao thức ethernet lại gửi các frame dữ liệu đi dựa vào 1 loại địa chỉ khác là địa chỉ MAC (hay còn gọi là địa chỉ vật lý) Tại sao lại cần đến 2 địa chỉ như vậy? Lý do là địa chỉ vật lý chỉ có giá trị trong phạm vi mạng LAN, nó sẽ không thể giúp xác định vị trí host ở bên ngoài phạm vi mạng LAN Khi gửi dữ liệu ra ngoài mạng LAN, các router

sẽ chuyển dữ liệu đi dựa và địa chỉ IP.

- Như vậy trong phần địa chỉ MAC nguồn và địa chỉ MAC đích trong header của frame ehternet,

ta sẽ điền các địa chỉ nào? Đối với địa chỉ MAC nguồn, đương nhiên ta sẽ điền địa chỉ MAC của chính ENC28J60 đã được xác lập Nhưng còn địa chỉ MAC đích, sẽ có 2 trường hợp xảy ra: + Nếu host đích nằm trong cùng 1 mạng LAN với chúng ta, ta sẽ điền địa chỉ MAC đích là địa chỉ tương ứng của host đích Frame dữ liệu sẽ được gửi thẳng đến đích.

+ Nếu host đích nằm bên ngoài mạng LAN, rõ ràng ta không thể gửi dữ liệu trực tiếp đến host đích mà phải thông qua gateway, khi đó địa chỉ MAC đích phải là địa chỉ gateway (Để dễ hiểu,

cứ hình dung ta gắn mạch này tại nhà, sau modem ADSL cùng với 1 máy tính để bàn tại nhà, nếu mạch của chúng ta cần gửi dữ liệu đến máy tính cũng ở tại nhà, trong cùng mạng LAN, nó sẽ gửi trực tiếp theo địa chỉ MAC của máy tính đó Nhưng nếu cần gửi dũ liệu đến 1 máy tính bên ngoài, nằm trên mạng Internet, khi đó nó không thể gửi frame dữ liệu thẳng đến máy tính kia mà

nó phải gửi qua gateway, trong trường hợp này chính là modem ADSL Như vậy lúc đó địa chỉ MAC đích phải là địa chỉ MAC của gateway).

- Vẫn còn một vấn đề nữa mà ta phải giải quyết Đó là trong cả hai trường hợp trên, dù là cần gửi cho gateway hay thẳng đến host đích, thì đến đây, ta mới chỉ biết địa chỉ IP của host đích (hay của gateway) mà không biết địa chỉ MAC tương ứng Vậy nảy sinh một vấn đề là làm sao biết được địa chỉ MAC của một host khi biết địa chỉ IP?

Trang 25

Đến đây, chính là phát sinh vai trò của giao thức phân giải địa chỉ (APR – Address Resolution Protocol) Vai trò của giao thức này là tìm ra địa chỉ MAC khi biết địa chỉ IP của 1 host.

Hoạt động của giao thức ARP:

- Cách thức làm việc của giao thức ARP thực ra khá đơn giản Nhiệm vụ của nó là khi giao thức

IP hỏi nó: “Host có địa chỉ IP là a.b.c.d thì địa chỉ MAC là bao nhiêu?” thì nó phải trả lời ngay:

“Địa chỉ MAC của nó là XX:XX:XX:XX:XX:XX!” Chức năng này trong project của chúng ta

sẽ được cung cấp bởi hàm “arpIpOut” (xem lại lưu đồ dữ liệu vào ra) Tức là trước khi giao thức

IP chuyển dữ liệu xuống cho giao thức ethernet, nó sẽ gọi hàm “arpIpOut” để phân giải địa chỉ MAC cho host đích.

- Tuy nhiên chỉ chừng đó chưa đủ giải thích cho hoạt động của ARP Câu hỏi tiếp theo sẽ là: Vậy ARP lấy thông tin ở đâu để trả lời cho câu hỏi trên?

- Cách thức nó giải quyết vấn đề cũng đơn giản không kém: giao thức ARP duy trì một bảng gọi

là ARP cache gồm 2 cột, một cột ghi địa chỉ IP, một cột ghi địa chỉ MAC tương ứng với địa chỉ

IP đó Mỗi khi được hỏi bởi giao thức IP, nó sẽ tra bảng này để tìm câu trả lời.

- Vậy đến đây, các bạn phải nảy ra ngay 1 câu hỏi kế tiếp: vậy những gì chứa trong bảng ARP cache từ đâu mà có, khi mới khởi động hệ thống, bảng này đương nhiên sẽ trống trơn Và chuyện

gì sẽ xảy ra khi giao thức ARP được hỏi về 1 địa chỉ IP, mà khi nó tra trong bảng ARP thì không thấy?

- Cách giải quyết của giao thức ARP như sau: khi được hỏi về một địa chỉ IP a.b.c.d nào đó mà không có sẵn trong bảng ARP cache, nó sẽ lập tức “la lớn” trong mạng LAN: “Ai là người có địa chỉ IP là a.b.c.d?” Các máy tính trong mạng LAN đều nghe được câu hỏi này, và lẽ dĩ nhiên chỉ

có đúng máy tính có địa chỉ IP a.b.c.d sẽ trả lời: “Là tôi đây, tôi có địa chỉ MAC là

XX:XX:XX:XX:XX:XX!” Vậy giao thức ARP sẽ lập tức thêm cặp địa chỉ IP a.b.c.d và địa chỉ MAC XX:XX:XX:XX:XX:XX vào trong bảng ARP cache và trả lời lại cho giao thức IP: “Địa chỉ MAC của nó là XX:XX:XX:XX:XX:XX!”.

- Nghe có vẻ buồn cười nhưng trong thực tế, trên máy tính của chúng ta, mọi việc diễn ra đúng như vậy, việc “la lớn” của ARP được thực hiện bằng cách nó gửi đi một gói tin có tên gọi là ARP request dưới dạng broadcast, tức là gửi đến mọi máy trong mạng LAN, địa chỉ MAC đích của gói broadcast sẽ là FF:FF:FF:FF:FF:FF Trong gói ARP request có chứa địa chỉ IP mà nó cần tìm Tất cả các máy tính trong mạng LAN sẽ nhận được gói tin này, và máy tính có địa chỉ IP trên sẽ trả lời bằng bản tin ARP reply, trong bản tin này sẽ có địa chỉ MAC của nó.

- Đó là cách thứ nhất để giao thức ARP điền thông tin vào bảng ARP cache Còn có 1 cách nữa khá đơn giản giúp nó điền đầy thông tin vào bảng ARP cache: đó là mỗi khi có 1 gói tin IP đến,

lẽ dĩ nhiên là phía host đã gửi gói tin này đã điền đầy đủ thông tin địa chỉ MAC (chứa trong header ehternet) và địa chỉ IP của nó (chứa trong header IP) Như vậy giao thức ARP sẽ lấy cặp địa chỉ này và cập nhật vào bảng ARP cache.

- Điều cuối cùng cần lưu ý về bảng ARP cache này là các dòng (tức cặp địa chỉ IP – MAC) chứa trong nó không được duy trì mãi mãi mà có 1 thời gian timeout, quá thời gian này mà không có

Trang 26

thông tin cập nhật cho cặp địa chỉ đó thì nó sẽ bị xóa khỏi ARP cache, và nếu lỡ giao thức IP cần gửi dữ liệu cho địa chỉ IP đã bị xóa thì ARP sẽ đi hỏi lại về địa chỉ IP đó.

Note: để xem được bảng arp cache trên máy tính của mình, các bạn có thể mở cửa sổ command (vào Start->Run->gõ cmd, nhấn Enter), sau đó gõ lệnh "arp -a".

Bây giờ ta bắt tay vào viết code:

Việc trước tiên phải làm là khai báo cấu trúc header IP và cấu trúc gói ARP trong file “packet.h” Cấu trúc của gói IP như sau:

- Ý nghĩa các field trong header IP:

+ Version (có chiều dài 4 bit): cho biết phiên bản của giao thức, đối với trường hợp của chúng ta, giao thức là IP version 4, trường này sẽ luôn có giá trị là 4 (0100)

+ Header Length (4 bit): cho biết chiều dài của header IP, tính theo đơn vị 4 byte (32 bit)

+ TOS (8 bit): Type of Service

+ Total Length (16 bit): 16 bit tổng chiều dài của gói IP gồm cả phần header

+ Identification (16 bit): dùng nhận diện các phân đoạn của gói IP

+ Flags: gồm 3 bit

Bit đầu tiên: không sử dụng

Bit 2: DF (Don’t Fragment) = 1 có nghĩa là không phân đoạn gói này

Bit 3: MF (More Fragment) = 0 => đây là phân đoạn cuối cùng

+ Fragmented offset (13 bit): độ dời (đơn vị 8 byte) tính từ điểm bắt đầu của Header tới điểm bắt đầu của phân đoạn

(3 trường trên: Identification, Flags, Fragmented offset dùng cho trường hợp đặc biệt khi ta cần chia đoạn dữ liệu ban đầu thành nhiều phân đoạn, đóng gói trong các gói tin nhỏ hơn, khi đó ta cần dùng các trường này cho mục đích ráp lại các phân đoạn để khôi phục lại đoạn dữ liệu ban đầu, trong project của chúng ta sẽ không có xử lý trường hợp này).

+ TTL (Time to Live) (8 bit): thời gian tồn tại trên mạng hoặc số chặng trên mạng mà gói đi qua

Trang 27

trước khi bị hủy bỏ

+ Protocol (8 bit): nhận diện Protocol trên lớp IP

+ Header checksum (16 bit): sửa sai cho phần Header

+ Các vùng địa chỉ nguồn, địa chỉ đích: địa chỉ IP 32 bit

+ Option: các tùy chọn dùng cho việc kiểm tra: Loose source routing, Strict source routing, Record route và Timestamp

+ Padding: Gồm các số zero được thêm vào sao cho chiều dài của vùng Header là bội số của 32 bit

(Trong phạm vi project của chúng ta, sẽ không có phần option và padding)

Vậy ta khai báo trong file “packet.h” nội dung như sau:

Code:

-

// -//Cau truc IP header

struct ntIPHeader

{

unsigned char verHdrLen;

unsigned char ToS;

unsigned int Len;

unsigned int IDNumber;

unsigned int Offset;

unsigned char TTL;

unsigned char Protocol;

unsigned int Checksum;

unsigned long srcIPAddr;

unsigned long desIPAddr;

unsigned char Option[4];

Trang 28

+ Hardware type (2 bytes): cho biết loại địa chỉ phần cứng, đối với địa chỉ MAC của giao thức ethernet thì giá trị này được qui định là "0x0001".

+ Protocol type (2 bytes): cho biết loại địa chỉ giao thức lớp trên, đối với địa chỉ IP, giá trị này được qui định là “0x0800”.

+ HLEN (1 byte): cho biết chiều dài của địa chỉ vật lý (địa chỉ MAC).

+ PLEN (1 byte): cho biết chiều dài của địa chỉ giao thức (địa chỉ IP)

+ Operation (2 bytes): cho biết hoạt động đang thực hiện trong gói tin này (request hay reply) + Sender H/W (hardware address, 6 bytes): địa chỉ vật lý của phía gửi.

+ Sender IP (4 bytes): địa chỉ IP của phía gửi.

+ Target H/W (6 bytes): địa chỉ vật lý của phía nhận, nếu chưa biết thì sẽ là chứa toàn 0.

+ Target IP (4 bytes): địa chỉ IP của phía nhận.

Vậy ta khai báo cấu trúc gói ARP trong file “packet.h” như sau:

Code:

-

// -//Cau truc ARP header

struct ntARPHeader

{

unsigned int hwType;

unsigned int protocol;

unsigned char hwLen;

unsigned char protoLen;

unsigned int opcode;

struct ntEthAddr shwaddr;

unsigned long sipaddr;

struct ntEthAddr dhwaddr;

unsigned long dipaddr;

};

#define ARP_OPCODE_REQUEST 1

#define ARP_OPCODE_REPLY 2

#define ARP_HWTYPE_ETH 1

Không có thời gian để viết chi tiết hơn Bạn nào đọc thấy chỗ nào khó hiểu thì cứ hỏi nhé.

Dù là trên PIC hay AVR hay bất cứ micro controller nào thì cơ chế cũng như nhau thôi (thậm chí trên máytính thì cũng tương tự), chỉ khác là đối với PIC thì Microchip đã cung cấp đầy đủ bộ thư viện cho các giaothức ethernet, ip, arp, udp, tcp, dhcp, http, không cần phải viết lại như anh đang làm cho AVR Cơ chế như sau:

- Khi ta mở máy tính lên, mở trình duyệt và gõ vào địa chỉ của webserver (PIC hay AVR gì cũng thế), giả

sử ở đây ta gõ vào địa chỉ IP như sau: http://192.168.1.10

- Sau khi nhấn enter thì máy tính của chúng ta sẽ gửi đi một bản tin request của giao thức HTTP (Hyper Text Transfer Protocol, giao thức để truyền/nhận nội dung trang web), thường là HTTP Get thông qua giao thức TCP (với cổng TCP được qui định cho giao thức HTTP là 80) đến địa chỉ webserver trên

- Webserver, ở đây chính là vi điều khiển của chúng ta (PIC hay AVR) nhận được bản tin này (tất nhiên bản tin này sẽ đi qua hết các lớp giao thức ethernet, IP, TCP rồi mới đến HTTP) Tại đây vi điều khiển sẽ đọc và phân tích bản tin HTTP request này để biết máy tính đang yêu cầu tải nội dung trang web nào

- Sau đó vi điều khiển sẽ lấy nội dung trang web này (được soạn thảo theo ngôn ngữ HTML) chứa trên

Trang 29

trên flash ROM, nó cũng có thể thêm vào trang web đó một số thông tin (ví dụ đọc giá trị từ các sensor cảm biến nhiệt độ và đưa vào trong trang web), và gửi toàn bộ nội dung trang web thông qua giao thức TCP trở lại cho máy tính Nếu nội dung trang web lớn nó có thể được gửi đi trên rất nhiều gói tin, vì mỗi gói tin chỉ chứa tối đa 1460 byte dữ liệu mà thôi.

- Máy tính nhận nội dung trang web và trình duyệt sẽ hiển thị lên cho chúng ta thấy

- Để điều khiển board từ xa qua web, trên trang web ta có thể thiết kế một nút nhấn chẳng hạn Khi ta nhấn nút này trên trình duyệt, máy tính sẽ gửi đi một bản tin HTTP nữa là HTTP Post, trong bản tin này

sẽ chứa các thông tin về trạng thái các nút option hay các giá trị trong các ô edit text có trên trang web

- Vi điều khiển sẽ nhận bản tin HTTP post này, phân tích dữ liệu chứa trong đó để có đáp ứng tương ứng (bật tắt relay chẳng hạn) sau đó nó sẽ gửi trả lại lần nữa nội dung trang web đã cập nhật những thay đổi vừa rồi (ví dụ bật reley thì trên web sẽ có 1 hình tròn đổi sang màu đỏ chẳng hạn) Trình duyệt sẽ updatenội dung này lên và ta sẽ thấy được tác động của thao tác điều khiển đó

Từ từ anh sẽ viết và giải thích tất cả các hoạt động đó trên AVR, trên PIC cũng thế nhưng các hàm được Microchip cung cấp sẵn mà thôi

Thầy cho em hỏi chỗ này, vì vừa đọc em vừa tưởng tượng thức thế cho dễ hiểu.

Trong mỗi frame ethernet đều chứa 2 địa chỉ MAC: một địa chỉ của host gửi và 1 địa chỉ của host nhận

.

Câu hỏi:Số host truyền nhận trong trường hợp này là bao nhiêu : 2 hay >2 host ? Vì em nghĩ 2 host là TH riêng, 1 host truyền 1 host nhận, thì host nhận check IP là chính nó.

Nếu host nhận đc frame mà nó kiểm tra ko phải IP add(dst) của nó thì nó sẽ xử lý như thế nào,

có phải lúc này IP add(dst) là IP broadcast?

Và sau đó tới một host nào đó, check IP add là của chính nó thì TH1 được xảy ra, phải ko ạ?

Em liên tưởng TCP/IP lúc này xử lý IP như một Router check IP cho cả 1 mạng LAN, kết nối với nó

Nếu frame được gửi cho tất cả máy tính trong LAN, thì sẽ ko có host đích cụ thể nào ạ?

Nếu với HTTP, hay 1 ứng dụng nào khác thì điều này có thể được, nhưng với các ứng Email chẳng hạn, cần tính bảo mật riêng tư thì IPbroadcast lại ko được- do các máy đều nhận đc frame

để xử lí.

EM có vài câu, ko biết đúng sai thế nào?

Câu hỏi của em thực ra rất hay, vấn đề này tôi đã không giải thích chi tiết trong phần giao thức ethernet.

- Giao thức ethernet chỉ hỗ trợ 2 hình thức truyền: unicast: tức là 1 host gửi, 1 host nhận; và broadcast, tức là 1 host gửi, tất cả các host trong mạng LAN đều nhận.

- Trong mạng LAN cơ bản, sử dụng 1 HUB để kết nối các máy tính với nhau trong mạng LAN Khi một máy tính gửi đi một frame ethernet, bất kể là nó gửi unicast hay broadcast, thì tất cả các máy tính trong mạng LAN đó (kết nối với HUB) đều nhận được frame đó Nhưng mỗi máy tính

sẽ đối chiếu địa chỉ MAC nhận với địa chỉ của chính nó (ở đây chỉ kiểm tra địa chỉ MAC, không kiểm tra địa chỉ IP, khi lên giao thức IP thì mới kiểm tra địa chỉ IP), và các host sẽ chỉ nhận

Trang 30

frame và chuyển lên giao thức IP trong 2 trường hợp:

+ Hoặc địa chỉ là của chính nó

+ Hoặc địa chỉ là broadcast

- Vậy điều gì sẽ xảy ra nếu một máy tính nào đó phá vỡ luật chơi, nhận dữ liệu không phải dành cho nó, như vậy phải chăng nó có thể nghe trộm dữ liệu gửi cho máy tính khác.

- Câu trả lời ở đây là: đúng như vậy, mạng LAN kiểu này hoàn toàn không có bảo mật, với các phần mềm nghe trộm dữ liệu, một máy tính có thể nghe trộm dữ liệu của các máy khác trong cùng mạng LAN.

- Ở đây thiết bị HUB dùng để kết nối các máy tính tạo thành mạng LAN chỉ đơn giản là khi nhận được dữ liệu đến 1 port của nó, nó sẽ khuyếch đại và phát ra lại ở tất cả các port, để tất cả máy tính nối đến nó đều nhận được dữ liệu.

Hy vọng câu trả lời trên giải đáp được thắc mắc của em, nếu còn chưa rõ cứ hỏi tiếp nhé.

Câu hỏi:ARP: Em nghĩ tới 1 cái là: mình ko đánh 192.xxx.x.x nữa mà có thể đánh chữ nào đó như avrnet và Enter thì có hiển thị được webserver không ạ? Và vai trò của ARP trong trường hợp này thế nào.

Lại một câu hỏi rất đáng để bàn luận nữa, tuy nhiên vấn đề này không thuộc giao thức ARP mà thuộc một hệ thống khác, ta gọi là hệ thống tên miền (domain name system).

Đúng ra, máy tính chỉ gửi và nhận dữ liệu trên mạng dựa vào địa chỉ IP Tức là lẽ ra để truy cập vào trang chủ yahoo chẳng hạn, ta phải gõ địa chỉ IP server của yahoo: http://98.137.149.56 (các bạn có thể thử).

Trang 31

Tuy nhiên rõ ràng là cách này quá khó nhớ với người sử dụng, do đó người ta mới nghĩ ra một loại địa chỉ gợi nhớ dễ nhớ hơn, đó là tên miền (domain name) như vậy thay vì gõ:

nó sẽ trả lời ngay tên miền đó ứng với địa chỉ IP nào.

Vậy bây giờ, nếu chúng ta mở trình duyệt và gõ vào đó http://www.yahoo.com thì cơ chế sẽ như sau:

- Máy tính sẽ gửi đi một câu hỏi đến DNS server là: tên miền http://www.yahoo.com thì tương ứng với địa chỉ IP nào?

- DNS server sẽ trả lời: Tên miền www.yahoo.com tương ứng với địa chỉ IP 98.137.149.56.

- Máy tính sẽ truy cập theo địa chỉ 98.137.149.56 và tải nội dung trang web yahoo về.

Vậy để có thể sử dụng tên miền, máy tính bắt buộc phải biết ít nhất một địa chỉ DNS server Thông tin về DNS server sẽ được cung cấp thông qua giao thức DHCP hoặc cấu hình tĩnh.

Có rất nhiều DNS server trên mạng, mỗi nhà cung cấp dịch vụ Internet của Việt Nam chẳng hạn đều có 1 vài DNS server Ví dụ VNPT có các DNS server: 203.162.4.190; 203.162.4.191; 203.162.4.1 Viettel có 203.113.131.1; 203.113.131.2; FPT có 210.245.0.11,

Vậy làm cách nào để có được tên miền của riêng mình (ví dụ www.avrnet.vn)? Câu trả lời là phải đăng ký tên miền (trả phí) và trả chi phí hàng năm để duy trì tên miền Lúc đó ta có quyền chỉ định tên miền đó tương ứng với địa chỉ IP nào.

Nếu không có điều kiện mua tên miền, ta có thể sử dụng 1 số tên miền miễn phí (ví dụ của dyndns) Đó là cách mà ta sẽ dùng cho project này (đến phần cuối cùng nhé).

Thầy có thể so sánh Add luận lí và Add MAC được không ạ?

Tại sao trương MAC đích khi truyền ra internet lại là địa chỉ Gateway? gateway giống MAC ở điểm nào, mà lại đc điền vào MAC đích?

Và ARP cache có giống với bảng NAT ip không ạ? Em thấy na lá Có phải Gateway and local IP(mạng LAN) của host sẽ cho địa chỉ MAC của host đích không ạ?

Mong thầy trả lời!

Để hiểu về 2 loại địa chỉ ta có thể hình dung như thế này:

Giả sử ta cần gửi 1 bức thư loanh quanh trong xóm, ta chỉ cần ghi tên người nhận là được, trong xóm sẽ dễ dàng xác định ông Nguyễn Văn A ở chỗ nào.

Tuy nhiên khi gửi thư đi trong phạm vi cả nước, nếu ta chỉ ghi tên người nhận, thậm chí có thêm

cả ngày tháng năm sinh và số chứng minh thư để bảo đảm không sợ bị trùng, thì bưu điện cũng

bó tay vì không biết ông Nguyễn Văn A ở đâu, vì với địa chỉ này (gồm tên, ngày tháng năm sinh,

số chứng minh thư) thì dù không sợ trùng địa chỉ, thì nó cũng không thể giúp ta xác định được

Trang 32

ông Nguyễn Văn A đang ở tỉnh, thành phố, đường nào.

Vậy ta cần một cách ghi địa chỉ khác, mà nhìn vào ta xác định được nơi cần chuyển thư tới, ví dụ tỉnh huyện đường số nhà.

Điều này hoàn toàn tương tự với địa chỉ IP và địa chỉ MAC: địa chỉ MAC mặc dù là bảo đảm không trùng nhau, nhưng nhìn vào nó ta không thể biết host có địa chỉ MAC đó đang ở đâu? Mỹ, Việt Nam hay Trung Quốc, ? Do đó địa chỉ MAC chỉ sử dụng được trong mạng LAN, nơi số lượng máy tính là ít, các thiết bị như SWITCH có thể biết hết các địa chỉ MAC trong mạng.

Để gửi dữ liệu ra ngoài mạng LAN, ta cần 1 loại địa chỉ khác, một địa chỉ mà khi nhìn vào ta biết ngay là host tương ứng đang ở Mỹ hay Việt Nam, thậm chí nếu ở Việt Nam thì thuộc mạng của nhà cung cấp dịch vụ nào Địa chỉ thõa mãn yêu cầu này chính là địa chỉ IP.

Sở dĩ như vậy vì trong địa chỉ IP, người ta chia thành 2 phần, phần đầu là địa chỉ mạng, cho biết máy tính đó đang thuộc mạng nào, phần sau là địa chỉ host, giúp phân biệt các máy tính trong mạng.

Ta có thể dễ dàng nhận thấy điều này: các máy tính trong cùng mạng thì phần đầu của địa chỉ IP

là giống nhau.

Nhìn vào 1 địa chỉ IP, ta sẽ biết ngay máy tính tương ứng đang ở nước nào.

Trong phạm vi mạng LAN, việc chuyển dữ liệu đến đích về mặt vật lý hoàn toàn chỉ cần dựa vào HUB hay SWITCH, tuy nhiên khi gửi ra ngoài mạng LAN thì HUB hay SWITCH sẽ bó tay, vì

sẽ không biết được địa chỉ MAC của máy tính bên ngoài Lúc này, HUB hay SWITCH sẽ chuyển gói tin đến một thiết bị khác có khả năng đưa gói tin ra khỏi mạng LAN, đó chính là Gateway, thiết bị kết nối giữa mạng LAN với bên ngoài Và rõ ràng để SWITCH chuyển gói tin đến Gateway, thì bây giờ địa chỉ MAC đích trong frame ethernet phải là địa chỉ MAC của Gateway.

ARP cache hoàn toàn khác bảng NAT IP (NAT-Network Address Translation)

Trong project này sẽ hướng dẫn đến kết nối, cài đặt modem, đăng ký tên miền, thiết kế

website, nói chung từ A-Z luôn.

Có lẽ mình cần dừng lại để giải thích rõ hơn về hoạt động của 2 giao thức IP và ARP một chút, cũng như các sử dụng 2 loại địa chỉ IP và MAC trên mạng, trước khi viết code tiếp, tuy hơi dài dòng 1 chút nhưng

sẽ giúp mọi người hiểu rõ hơn cách thức làm việc của TCP/IP, như vậy thì sẽ dễ hiểu code hơn và có thể

tự viết hay sửa đổi code được dễ dàng

Ta hãy xem xét 1 mạng ví dụ như sau:

- Mạng LAN tại nhà gồm 3 máy tính và 1 board mạch của chúng ta kết nối vào ADSL router, từ đó nối vàomạng của nhà cung cấp dịch vụ

- Các bạn cũng cần biết là thực ra modem ADSL hay ADSL router mà ta dùng ở nhà, thật ra bên trong nó gồm 3 thiết bị: một HUB để mở rộng số lượng port, cho phép nhiều máy tính có thể cùng kết nối vào mạng; một Router IP đóng vai trò Gateway, thực hiện chức năng định tuyến giữa mạng bên trong (LAN)

và mạng bên ngoài (WAN); và cuối cùng là 1 modem (Modulation - Demodulation) để có thể truyền dữ liệu trên đường dây ADSL

Trang 33

Ta xẽ xem xét 2 ví dụ:

Ví dụ A: board mạch của chúng ta gửi dữ liệu đến 1 máy tính trong cùng mạng LAN, ví dụ là máy có địa chỉ 192.168.1.6

Ví dụ B: board mạch gửi dữ liệu đến 1 máy tính nằm bên ngoài, ví dụ là máy có địa chỉ 203.162.44.164

A-Trường hợp gửi trong mạng LAN

Bước 1: Giao thức IP trong board mạch nhận được yêu cầu gửi dữ liệu đến địa chỉ IP 192.168.1.6

Bước 2: Nó đi hỏi giao thức ARP (thông qua hàm ArpIpOut) về địa chỉ này ARP sau khi tìm trong bảng ARP cache không thấy, nó sẽ gửi 1 bản tin ARP request dưới hình thức broadcast đến mọi máy tính trongmạng Máy tính có địa chỉ tương ứng sẽ trả lời

Trang 34

Bước 3: ARP sẽ cập nhật bảng ARP cache và trả lời lại cho giao thức IP.

Bước 4: giao thức IP dùng thông tin này để điền vào frame ethernet và chuyển sang giao thứ ethernet

để gửi đi

Trang 35

B-Trường hợp gửi ra ngoài mạng LAN

Nếu vẫn làm theo cách cũ thì sẽ xảy ra trường hợp như sau:

Trang 37

Như vậy, nếu vẫn làm theo cách cũ, việc gửi dữ liệu sẽ thất bại.Mọi việc phải được tiến hành như sau:

Trang 39

Vậy bây giờ ta bắt đầu viết code cho các giao thức ip và arp:

Ta tạo file “ip.c” với nội dung ban đầu”

Code:

// Writen by NTTam - PTITHCM

Trang 40

// Writen by NTTam - PTITHCM

- Subnet Mask của nó (có thời gian se giải thích Subnet mask sau).

- Địa chỉ IP của Gateway.

- Địa chỉ MAC của nó.

Ta sẽ lưu các thông tin này trong một biến kiểu struct là ipConfig Mở file “ip.h”, khai báo kiểu struct này vào:

unsigned long netmask; ///< netmask

unsigned long gateway; ///< gateway IP address

struct ntEthAddr ethaddr;

};

Mở tiếp file “ip.c”, khai báo biến IpMyConfig có kiểu là struct ipConfig

Code:

-

// -struct ipConfig IpMyConfig; ///< Local IP address/config structure

Tiếp theo ta viết trong file “ip.c” một số hàm chức năng cho giao thức này:

Đầu tiên là hàm để tính trường kiểm tra lỗi (checksum) trong Header IP Nếu các bạn xem lại phần cấu trúc Header của IP sẽ thấy nó có 1 trường kiểm tra lỗi cho Header (không bao gồm data) Trường này giúp phía nhận gói IP kiểm tra lại xem thông tin chứa trong Header (rất quan trọng) có bị sai trong quá trình truyền hay không Nếu có sai sót, gói tin đó sẽ bị hủy bỏ mà không xử lý.

Phía phát trước khi gửi phải tính giá trị checksum và ghi nó vào trường checksum trong header Phía thu khi nhận gói tin sẽ tự mình tính lại check sum 1 cách độc lập, sau đó so sánh với

checksum mà phía phát đã tính (lưu trong header) nếu có khác biệt thì tức là có lỗi xảy ra, và gói

Ngày đăng: 01/12/2015, 11:45

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w