Öncelikle herkese merhaba demek istiyorum, bu döküman benim de ilk döküman çalışmam olacağından hatalarımı mazur görmenizi diliyorum.
Bu yazıda bilgisayar ağları katmanlarından, fiziksel katmanın bir üst seviyesinde bulunan Veri Bağlantı Katmanı (Data Link Layer) fonksiyonlarından veri göndermek için kullanılan send ve veri almak için kullanılan receive fonksiyonlarının uygulamasını anlatmaya çalışacağım.
Öncelikle bir Veri Bağlantı Katmanı paketinin yapısını inceleyelim:
| 4 | 4 | 2 | 2 | 32-1500 | 2 |
|
Hedef MAC adresi |
Kaynak MAC adresi |
Uzunluk | Tip | Veri(Datagram) | CRC |
Şekilde yeralan Hedef Mac adresi, Kaynak Mac adresi, Uzunluk ve Tip alanları Veri Bağlanı katmanının başlığını içermektedir. Bu alanlar LL_Hdr ismi ile bir yapı olarak tanımlanmıştır. Veri Alanı en fazla 1500, en az 32 byte olabilmektedir. CRC ise gönderilen verinin bozulup bozulmadığını kontrol etmemiz içindir.
Bu uygulamada kullanılan SPacket ve LL_Hdr yapıları şu şekildedir:
struct SPacket{
SPacket *next; // Pointer to the next SPacket: Used to link different fragments of an IP packet together
char *tail; // Pointer to the end of the packet
char *head; // Pointer to the first byte of the packet
char *ll; // Pointer to the beginning of the LL header
char *nl; // Pointer to the beginning of the NL header (can be IP, ARP or any other NL protocol)
char *tl; // Pointer to the beginning of the TL header (can be UDP, RUDP or any other TL protocol)
char *al; // Pointer to the beginning of the application layer data
};
struct LL_Hdr{
unsigned int destMAC; // Destination MAC where we are sending the packet
unsigned int sourceMAC; // Source MAC: Who is sending the packet?
unsigned short length; // length of the LL packet payload (NL datagram size)
unsigned short protocolNo; // upper layer protocol sending the packet?
};
Şimdi veri almamızı sağlayacak olan receive fonksiyonu ile işe başlayalım. Fonksiyonun tanımlanması şu şekilde:
void LL_Receive(SPacket *pPacket);
Burada SPacket türünden bir pPacket bize gönderiliyor, öncelikle gelen paketin bozulup bozulmadığını kontrol etmemiz gerekiyor, eğer paketbozulmadıysa paketin bize mi gönderildiğine bakıyoruz. Paket bize gönderildi ise de hangi protokole gitmesi gerekiyorsa o protokole paketi gönderecek olan fonksiyonu çağırıyoruz.
unsigned short EDC; pPacket->ll=pPacket->nl-sizeof(LL_Hdr); LL_Hdr *pLL=(LL_Hdr *)(pPacket->ll); pLL->sourceMAC=LL_myMAC; pLL->destMAC=destMAC; pLL->length=pPacket->tail-pPacket->nl; pLL->protocolNo=NLProtoNo; EDC=CRC16((unsigned char *)pPacket->ll, (int)(pPacket->tail-pPacket->ll)); memcpy(pPacket->tail, &EDC, sizeof(unsigned short)); pPacket->tail+=sizeof(unsigned short); PL_Send(pPacket->ll, (int)(pPacket->tail-pPacket->ll));
İkinci olarak veriyi göndermemizi sağlayan send fonksiyonunu yazalım. Bu fonksiyonun tanımı da şu şekilde
void LL_Send(SPacket *pPacket, unsigned short NLProtoNo, unsigned int destMAC);
Fonksiyonun tanımlamasından da anlaşılacağı gibi fonksiyon SPacket türünde bir paket'i parametre olarak alıyor, paketin hangi protokole protokolden geldiğini bildiren protokolNo parametresi var, ayrıca paketi göndereceğimiz bilgisayarın MAC adresi bulunmakta.Fonksiyonun içeriği şu şekilde olması gerekiyor.
unsigned short EDC; pPacket->ll=pPacket->nl-sizeof(LL_Hdr); LL_Hdr *pLL=(LL_Hdr *)(pPacket->ll); //Veri Bağlantı Katmanı Başlığı pLL->sourceMAC=LL_myMAC; pLL->destMAC=destMAC; pLL->length=pPacket->tail-pPacket->nl; pLL->protocolNo=NLProtoNo; EDC=CRC16((unsigned char *)pPacket->ll, (int)(pPacket->tail-pPacket->ll)); memcpy(pPacket->tail, &EDC, sizeof(unsigned short)); pPacket->tail+=sizeof(unsigned short); PL_Send(pPacket->ll, (int)(pPacket->tail-pPacket->ll));
Bu fonksiyonda da öncelikle veri bozulmasını kontrol edebilmek için karşı tarafa göndiğimiz EDC değişkenini tanımlıyoruz. Daha sonra Veri bağlantı katmanının başlığı için pPacket'in başına LL_Hdr'ın boyutu kadar yer ayırıyoruz. Daha sonra da pLL adlı LL_Hdr tipinde bir gösterge tanımlayıp pPacket'te bulunacak olan veri Bağlantı katmanının baş kısmını buna eşitliyoruz. hemen alttaki 4 satırda Veri bağlantı katmanı başlıklarını ilgili değerlerle doldurup Hata kontrolü yapacak olan EDC'yi de paketin sonuna ekliyoruz. pPaket'in sonunu da doğru bir şekilde terar düzenledikten sonra Fiziksel katmana bu veriyi gönderiyoruz.
İki fonksiyonu da birarada görmek isteyenler için şimdi hepsini bir daha kopyalıyorum.
void LL_Send(SPacket *pPacket, unsigned short NLProtoNo, unsigned int destMAC){
unsigned short EDC;
pPacket->ll=pPacket->nl-sizeof(LL_Hdr);
LL_Hdr *pLL=(LL_Hdr *)(pPacket->ll);
pLL->sourceMAC=LL_myMAC;
pLL->destMAC=destMAC;
pLL->length=pPacket->tail-pPacket->nl;
pLL->protocolNo=NLProtoNo;
EDC=CRC16((unsigned char *)pPacket->ll, (int)(pPacket->tail-pPacket->ll));
memcpy(pPacket->tail, &EDC, sizeof(unsigned short));
pPacket->tail+=sizeof(unsigned short);
PL_Send(pPacket->ll, (int)(pPacket->tail-pPacket->ll));
}
void LL_Receive(SPacket *pPacket){
unsigned short edcOld;
LL_Hdr *pLL=(LL_Hdr *)pPacket->ll;
pPacket->tail-=2;
unsigned short edcNew = CRC16((unsigned char *)pPacket->ll, pPacket->tail-pPacket->ll);
memcpy(&edcOld,pPacket->tail,sizeof(unsigned short));
pPacket->nl=pPacket->ll+sizeof(LL_Hdr);
if(edcNew!=edcOld){
return;
}
else if((pLL->destMAC!=0xFFFFFFFF)||(pLL->destMAC!=LL_myMAC)){
return;
}
else{
if(pLL->protocolNo==0x8000){
IP_Receive(pPacket);
}
else{
ARP_Receive(pPacket);
}
}
}
ÖNEMLİ NOT: yukarıda tanımlanmış olan SPacket ve LL_Hdr yapıları Alper Bilge'nin hazırladığı proje kodundan alınmıştır. Anlatılan uygulamaki diğer kodlar benim geçen yıl Bilgisayar Ağları dersi projesi kapsamında yazmış olduğum kodlardır. Hatırladığım kadarı ile bu kodda paketi gönderirken karşı tarafa kaynak Mac adresini gönderemiyor olabilir. Zamanım kısıtlı olduğundan kodu tekrar kurcalayamıyorum. Umarım işinize yarar bir döküman olmuştur. Herkese iyi çalışmalar