Пишем драйвер сетевой карты линукс

Пишем драйвер сетевой карты линукс

уПЪДБОЙЕ ДТБКЧЕТБ УЕФЕЧПЗП ХУФТПКУФЧБ — юБУФШ 1

бЧФПТ: Bhaskaran
рЕТЕЧПД: бОДТЕК лЙУЕМЕЧ

чЧЕДЕОЙЕ

ьФБ УФБФШС РТЙЪЧБОБ РПНПЮШ ЮЙФБФЕМА Ч РПОЙНБОЙЙ РТЙОГЙРПЧ УПЪДБОЙС ДТБКЧЕТБ УЕФЕЧПК ethernet-РМБФЩ ДМС пу Linux. ч ЛБЮЕУФЧЕ РТЙНЕЮБОЙС — ТБЪТБВПФЛБ НПДХМС ДТБКЧЕТБ ЧЩРПМОЕОБ ОБ СЪЩЛЕ РТПЗТБННЙТПЧБОЙС C, Б РПФПНХ С РПМБЗБА, ЮФП ЮЙФБФЕМШ ДПУФБФПЮОП ИПТПЫП ЪОБЛПН У СЪЩЛПН C Й пу Linux. ч ЬФПН ДПЛХНЕОФЕ ВХДХФ РПЛБЪБОЩ МЙЫШ УБНЩЕ ПУОПЧОЩЕ НПНЕОФЩ, ЛПФПТЩЕ ОЕПВИПДЙНП ЪОБФШ, ЮФПВЩ ОБРЙУБФШ ДТБКЧЕТ УЕФЕЧПК РМБФЩ (МХЮЫЙЕ Й ВПМЕЕ РТПЖЕУУЙПОБМШОЩЕ РТЙНЕТЩ ДТБКЧЕТПЧ ЧЩ ОБЧЕТОСЛБ УНПЦЕФЕ ОБКФЙ Ч ЙУИПДОЩИ ФЕЛУФБИ СДТБ).

уЕФЕЧБС РПДУЙУФЕНБ Ч Linux Й PCI-РМБФЩ

чРПМОЕ ПЮЕЧЙДОП, ЮФП УЕФЕЧБС РПДУЙУФЕНБ СЧМСЕФУС ОЕПФЯЕНМЕНПК ЮБУФША СДТБ Linux. лТПНЕ ФПЗП, НПЦОП ХФЧЕТЦДБФШ, ЮФП Linux СЧМСЕФУС ПДОПК ЙЪ «УБНЩИ ВЕЪПРБУОЩИ Й ОБДЕЦОЩИ» уЕФЕЧЩИ пРЕТБГЙПООЩИ уЙУФЕН, ЙЪ РТЕДУФБЧМЕООЩИ Ч ОБУФПСЭЕЕ ЧТЕНС ОБ ТЩОЛЕ. чОХФТЕООСС ТЕБМЙЪБГЙС УЕФЕЧПК РПДУЙУФЕНЩ Ч СДТЕ ДЕМЙФУС ОБ ДЧЕ ВПМШЫЙЕ ЮБУФЙ. рЕТЧБС — ЬФП УПВУФЧЕООП ТЕБМЙЪБГЙС УФЕЛБ РТПФПЛПМПЧ TCP/IP (ЛБФБМПЗ /usr/linux/net/ipv4). чФПТБС — ЬФП ТЕБМЙЪБГЙС ДТБКЧЕТПЧ ТБЪМЙЮОЩИ УЕФЕЧЩИ ХУФТПКУФЧ (/usr/src/linux/drivers/net ).

лПД, ТЕБМЙЪХАЭЙК УФЕЛ TCP/IP, ТБЪТБВПФБО ФБЛЙН ПВТБЪПН, ЮФП ПО ПЮЕОШ РТПУФП ЙОФЕЗТЙТХЕФУС У ДТБКЧЕТБНЙ УБНЩИ ТБЪОППВТБЪОЩИ УЕФЕЧЩИ ХУФТПКУФЧ (ЛБЛ ТЕБМШОЩИ, ФБЛ Й ЧЙТФХБМШОЩИ), ПУЧПВПЦДБС ТБЪТБВПФЮЙЛБ ПФ ОЕПВИПДЙНПУФЙ ЪБДХНЩЧБФШУС П ФПН ЛБЛ ТБВПФБЕФ ЛПД УЕФЕЧПЗП ЙМЙ ФТБОУРПТФОПЗП ХТПЧОС. еДЙОУФЧЕООПЕ ФТЕВПЧБОЙЕ УПУФПЙФ Ч ФПН, ЮФП ТЕБМЙЪХЕНЩК НПДХМШ ДПМЦЕО ПВЕУРЕЮЙЧБФШ УФБОДБТФОЩК РТПЗТБННОЩК ЙОФЕТЖЕКУ ДМС ДПУФХРБ Л БРРБТБФОПК ЮБУФЙ, ЛПФПТБС НПЦЕФ ВЩФШ РТЕДУФБЧМЕОБ УЕФЕЧПК Ethernet-ЛБТФПК, ДМС УМХЮБС РПДЛМАЮЕОЙС Л МПЛБМШОПК УЕФЙ, ЙМЙ НПДЕНПН — Ч УМХЮБЕ РПДЛМАЮЕОЙС Л йОФЕТОЕФ РП ЛПННХФЙТХЕНЩН ЛБОБМБН.

ч ОБУФПСЭЕЕ ЧТЕНС ТЩОПЛ УЕФЕЧЩИ ХУФТПКУФЧ НПЦЕФ РТЕДМПЦЙФШ ЧБН ПЗТПНОПЕ ТБЪОППВТБЪЙЕ УЕФЕЧЩИ РМБФ, УТЕДЙ ЛПФПТЩИ С ИПЮХ ПФНЕФЙФШ RTL8139. ьФП «plug and play» Ethernet РМБФБ, РПДЛМАЮБЕНБС ЮЕТЕЪ ТБЪЯЈН ЫЙОЩ PCI. PCI — ЬФП Peripheral Component Interconnect (чЪБЙНПДЕКУФЧЙЕ У рЕТЙЖЕТЙКОЩНЙ хУФТПКУФЧБНЙ), РПМОЩК ОБВПТ УРЕГЙЖЙЛБГЙК, ПРТЕДЕМСАЭЙИ РПТСДПЛ ЧЪБЙНПДЕКУФЧЙС НЕЦДХ ТБЪМЙЮОЩНЙ ЮБУФСНЙ ЛПНРШАФЕТБ. бТИЙФЕЛФХТБ PCI ВЩМБ ТБЪТБВПФБОБ Ч ЛБЮЕУФЧЕ ЪБНЕОЩ ВПМЕЕ ТБООЕЗП УФБОДБТФБ ISA, ЧЩЗПДОП ПФМЙЮБСУШ ПФ РПУМЕДОЕК ФБЛЙНЙ ИБТБЛФЕТЙУФЙЛБНЙ, ЛБЛ УЛПТПУФШ РЕТЕДБЮЙ ДБООЩИ, РТПУФПФБ ДПВБЧМЕОЙС Й ХДБМЕОЙС ДПРПМОЙФЕМШОЩИ ХУФТПКУФЧ, ОЕЪБЧЙУЙНПУФШ ПФ РТПГЕУУПТБ Й РТ.

пУОПЧЩ ТБВПФЩ У УЕФША

еЭЕ ПДОБ ОЕНБМПЧБЦОБС ХФЙМЙФБ, РТЕДОБЪОБЮЕООБС ДМС ДЙБЗОПУФЙЛЙ Й ТХЮОПК ОБУФТПКЛЙ УЕФЕЧЩИ ЙОФЕТЖЕКУПЧ, ЬФП ifconfig. фЙРЙЮОЩК РТЙНЕТ ЧЩЧПДБ ХФЙМЙФЩ ifconfig, ЪБРХЭЕООПК ВЕЪ БТЗХНЕОФПЧ, РТЕДУФБЧМЕО ОЙЦЕ (Х ЧБУ ПО НПЦЕФ ЧЩЗМСДЕФШ ОЕУЛПМШЛП ЙОБЮЕ, Ч ЪБЧЙУЙНПУФЙ ПФ ЛПОЛТЕФОЩИ ОБУФТПЕЛ Й ЛПОЖЙЗХТБГЙЙ УЙУФЕНЩ).

лБЛ ЧЙДОП ЙЪ ДБООПЗП МЙУФЙОЗБ, ОБ НПЕК УЙУФЕНЕ ЪБРХЭЕОП ДЧБ УЕФЕЧЩИ ЙОФЕТЖЕКУБ: eth0 Й lo, ЮФП ПВПЪОБЮБЕФ УЕФЕЧХА РМБФХ ethernet Й МПЛБМШОЩК «РЕФМЕЧПК» (loopback) ЙОФЕТЖЕКУ. мПЛБМШОЩК ЙОФЕТЖЕКУ loopback СЧМСЕФ УПВПК ЙУЛМАЮЙФЕМШОП РТПЗТБННОХА ТЕБМЙЪБГЙА Й ОЕ ЙНЕЕФ БРРБТБФОПЗП ПВЕУРЕЮЕОЙС. оБРТПФЙЧ, ЙОФЕТЖЕКУХ eth0, Ч НПЕН УМХЮБЕ, УППФЧЕФУФЧХЕФ ТЕБМШОБС УЕФЕЧБС РМБФБ Realtek 8139. лТПНЕ ФПЗП, Ч МЙУФЙОЗЕ НПЦОП ХЧЙДЕФШ БРРБТБФОЩК БДТЕУ (HWaddr), ЙМЙ MAC-БДТЕУ, УЕФЕЧПК РМБФЩ, IP-БДТЕУ (inet addr), БДТЕУ ДМС ЫЙТПЛПЧЕЭБФЕМШОЩИ РПУЩМПЛ Broadcast (Bcast), НБУЛХ РПДУЕФЙ (Mask) Й ДПРПМОЙФЕМШОХА УФБФЙУФЙЮЕУЛХА ЙОЖПТНБГЙА, УЧСЪБООХА У РЕТЕДБЮЕК ДБООЩИ, ЛПФПТБС ЧЛМАЮБЕФ Ч УЕВС НБЛУЙНБМШОЩК ТБЪНЕТ ВМПЛБ ДБООЩИ (MTU), ЛПМЙЮЕУФЧП РТЙОСФЩИ РБЛЕФПЧ (RX), ЛПМЙЮЕУФЧП РЕТЕДБООЩИ РБЛЕФПЧ (TX), ЛПМЙЮЕУФЧП ЛПММЙЪЙК Й РТ.. лПНБОДБ ifconfig НПЦЕФ ЙУРПМШЪПЧБФШУС ФБЛЦЕ ДМС ЪБРХУЛБ УЕФЕЧЩИ ЙОФЕТЖЕКУПЧ, ЛПФПТЩЕ ОЕ ВЩМЙ ПВОБТХЦЕОЩ УЙУФЕНПК ОБ ЬФБРЕ ЪБЗТХЪЛЙ. пДОПЧТЕНЕООП НПЦОП РЕТЕОБЪОБЮЙФШ IP-БДТЕУ, ЛБЛ РПЛБЪБОП ОЙЦЕ.

дБООБС ЛПНБОДБ ОБЪОБЮБЕФ РМБФЕ ethernet IP-БДТЕУ 192.9.200.1, УЕФЙ ЛМБУУБ C, Й ЪБРХУЛБЕФ УЕФЕЧПК ЙОФЕТЖЕКУ. лТПНЕ ФПЗП, ifconfig НПЦЕФ ЙУРПМШЪПЧБФШУС ДМС «ПУФБОПЧЛЙ» БЛФЙЧОПЗП УЕФЕЧПЗП ЙОФЕТЖЕКУБ . рТЙНЕТ ЛПНБОДЩ РТЙЧПДЙФУС ОЙЦЕ.

чУЕ ЧЩЫЕУЛБЪБООПЕ ЧРПМОЕ РТЙНЕОЙНП Й Л МПЛБМШОПНХ (loopback) ЙОФЕТЖЕКУХ, ОБРТЙНЕТ: лПНБОДБ ‘ifconfig’ ЙНЕЕФ НОПЦЕУФЧП ДПРПМОЙФЕМШОЩИ ПРГЙК, ПРЙУБОЙЕ ЛПФПТЩИ ЧЩ УНПЦЕФЕ ОБКФЙ Ч УФТБОЙГБИ УРТБЧПЮОПЗП ТХЛПЧПДУФЧБ man.

еЭЕ ПДОБ ХФЙМЙФБ, ЛПФПТБС ОБН РПОБДПВЙФУС — ЬФП netstat. пОБ ЧЩЧПДЙФ УЧЕДЕОЙС П УЕФЕЧЩИ УПЕДЙОЕОЙСИ, ФБВМЙГЩ НБТЫТХФЙЪБГЙЙ, УФБФЙУФЙЛХ РП УЕФЕЧЩН ЙОФЕТЖЕКУБН, НБУЛЙТХЕНЩЕ УПЕДЙОЕОЙС Й Ф.Р.. йУЮЕТРЩЧБАЭЕЕ ПРЙУБОЙЕ ДПРПМОЙФЕМШОЩИ ПРГЙК, ЛПФПТЩЕ РТЕДПУФБЧМСЕФ ДБООБС ЛПНБОДБ, ЧЩ ОБКДЕФЕ Ч УРТБЧПЮОПН ТХЛПЧПДУФЧЕ man.

йОФЕТЖЕКУ СДТБ

сДТП РТЕДПУФБЧМСЕФ ОЕВПМШЫЙЕ, ОП ЬЖЖЕЛФЙЧОЩЕ УФТХЛФХТЩ ДБООЩИ Й ЖХОЛГЙЙ, ПВЕУРЕЮЙЧБАЭЙЕ ЬМЕЗБОФОЩК ДПУФХР, РПОСФОЩК ДБЦЕ ОЕ ПЮЕОШ ПРЩФОПНХ РТПЗТБННЙУФХ, Й ЙОФЕТЖЕКУ, РПМОПУФША ОЕЪБЧЙУЙНЩК ПФ РТПФПЛПМПЧ ЧЕТИОЕЗП ХТПЧОС. юФПВЩ РПВЩУФТЕЕ ПЪОБЛПНЙФШ ЧБУ У ЙНЕАЭЙНЙУС УФТХЛФХТБНЙ ДБООЩИ, ЖХОЛГЙСНЙ Й РПТСДЛПН ЧЪБЙНПДЕКУФЧЙС ДТБКЧЕТБ УП УФЕЛПН РТПФПЛПМПЧ ЧЕТИОЕЗП ХТПЧОС, НЩ УОБЮБМБ РПРТПВХЕН ТБЪТБВПФБФШ БРРБТБФОП-ОЕЪБЧЙУЙНЩК ДТБКЧЕТ. рПУМЕ ФПЗП, ЛБЛ ПВЭБС ЛБТФЙОБ ВХДЕФ ЧЩТЙУПЧЩЧБФШУС ДПУФБФПЮОП ЮЕФЛП, НЩ УНПЦЕН ХЗМХВЙФШУС Ч ТБВПФХ У ТЕБМШОПК БРРБТБФХТПК.

чУСЛЙК ТБЪ, ЛПЗДБ НПДХМШ СДТБ ЪБЗТХЦБЕФУС Ч РБНСФШ, ПО ОБЮЙОБЕФ ЪБРТБЫЙЧБФШ ОЕПВИПДЙНЩЕ ДМС УЧПЕЗП ЖХОЛГЙПОЙТПЧБОЙС ТЕУХТУЩ, ФБЛЙЕ ЛБЛ РПТФЩ ЧЧПДБ/ЧЩЧПДБ, ЧЕЛФПТЩ РТЕТЩЧБОЙК Й Ф.Р. бОБМПЗЙЮОП, Ч НПНЕОФ ТЕЗЙУФТБГЙЙ ДТБКЧЕТБ, ПО ТБЪНЕЭБЕФ УФТХЛФХТЩ ДБООЩИ, УППФЧЕФУФЧХАЭЙЕ ЛБЦДПНХ ЙЪ ПВОБТХЦЕООЩИ УЕФЕЧЩИ ЙОФЕТЖЕКУПЧ, Ч ЗМПВБМШОПН УРЙУЛЕ УЕФЕЧЩИ ХУФТПКУФЧ.

лБЦДЩК ЙОФЕТЖЕКУ ПРТЕДЕМСЕФУС УФТХЛФХТПК struct net_device. фБЛ, ОБРТЙНЕТ, ПВЯСЧМЕОЙЕ ХУФТПКУФЧБ rtl8139 ВХДЕФ ЧЩЗМСДЕФШ УМЕДХАЭЙН ПВТБЪПН:

пРТЕДЕМЕОЙЕ УФТХЛФХТЩ struct net_device ОБИПДЙФУС Ч ЪБЗПМПЧПЮОПН ЖБКМЕ linux/net_device.h. лПД, РТЕДУФБЧМЕООЩК ЧЩЫЕ, ЙОЙГЙБМЙЪЙТХЕФ ФПМШЛП ПДОП РПМЕ УФТХЛФХТЩ — ‘init’, ЮФП УППФЧЕФУФЧХЕФ ЖХОЛГЙЙ ЙОЙГЙБМЙЪБГЙЙ НПДХМС ДТБКЧЕТБ. чУСЛЙК ТБЪ, ЛПЗДБ РТПЙУИПДЙФ ТЕЗЙУФТБГЙС ХУФТПКУФЧБ, СДТП ЧЩЪЩЧБЕФ ЬФХ ЖХОЛГЙА, Б ПОБ, Ч УЧПА ПЮЕТЕДШ, ДПМЦОБ ЙОЙГЙБМЙЪЙТПЧБФШ БРРБТБФОХА ЮБУФШ ХУФТПКУФЧБ Й ЪБРПМОЙФШ РПМС УФТХЛФХТЩ struct net_device. уБНБ РП УЕВЕ УФТХЛФХТБ struct net_device ДПУФБФПЮОП ЧЕМЙЛБ Й УПДЕТЦЙФ УУЩМЛЙ ОБ ЧУЕ ЖХОЛГЙЙ, ОЕПВИПДЙНЩЕ ДМС ПВЕУРЕЮЕОЙС ЧЪБЙНПДЕКУФЧЙС У БРРБТБФХТПК. дБЧБКФЕ ТБУУНПФТЙН ОЕЛПФПТЩЕ ЙЪ ОЙИ.

Читайте также:  Shift insert mac os

name : рЕТЧПЕ РПМЕ, ЛПФПТПЕ ФТЕВХЕФ РПСУОЕОЙК — ЬФП ‘name’, ЪДЕУШ ИТБОЙФУС ЙНС ЙОФЕТЖЕКУБ (УФТПЛБ, ЙДЕОФЙЖЙГЙТХАЭБС ЙОФЕТЖЕКУ). пЮЕЧЙДОП, ЮФП Ч ДБООПН ЛПОЛТЕФОПН УМХЮБЕ, ЬФП УФТПЛБ «rtl8139».

int (*open) (struct net_device *dev) : нЕФПД, РПУТЕДУФЧПН ЛПФПТПЗП ЙОФЕТЖЕКУ ЪБРХУЛБЕФУС ЧУСЛЙК ТБЪ, ЛПЗДБ ХФЙМЙФБ ifconfig БЛФЙЧЙТХЕФ ЕЗП. нЕФПД open ДПМЦЕО РПРЩФБФШУС ЪБИЧБФЙФШ ЧУЕ ОЕПВИПДЙНЩЕ УЙУФЕНОЩЕ ТЕУХТУЩ.

int (*stop) (struct net_device *dev) : ьФПФ НЕФПД ЪБЛТЩЧБЕФ, ЙМЙ ПУФБОБЧМЙЧБЕФ, ЙОФЕТЖЕКУ.

int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev) : ьФПФ НЕФПД ЙОЙГЙЙТХЕФ РЕТЕДБЮХ ДБООЩИ ЮЕТЕЪ ХУФТПКУФЧП ‘dev’. дБООЩЕ ТБУРПМПЦЕОЩ Ч ВХЖЕТЕ УПЛЕФБ Ч УФТХЛФХТЕ skb. л ТБУУНПФТЕОЙА УФТХЛФХТЩ skb НЩ РТЙУФХРЙН РПЪДОЕЕ.

struct net_device * (*get_status) (struct net_device *dev): ьФПФ НЕФПД ЧЩЪЩЧБЕФУС ЧУСЛЙК ТБЪ, ЛПЗДБ РТЙМПЦЕОЙЕ РЩФБЕФУС РПМХЮЙФШ УФБФЙУФЙЛЙ ЙОФЕТЖЕКУБ. фБЛ ЬФПФ НЕФПД ЧЩЪЩЧБЕФУС, ЛПЗДБ ЪБРХУЛБЕФУС, ОБРТЙНЕТ, ХФЙМЙФБ ifconfig ЙМЙ netstat -i.

void *priv :дПРПМОЙФЕМШОЩК ХЛБЪБФЕМШ, ЛПФПТЩК НПЦЕФ ЙУРПМШЪПЧБФШУС ТБЪТБВПФЮЙЛПН ДТБКЧЕТБ ДМС УЧПЙИ ОХЦД. оБЪОБЮЕОЙЕ ЬФПЗП РПМС УФТХЛФХТЩ ВХДЕФ ПВЯСУОСФШУС РПЪДОЕЕ. уФТХЛФХТБ ЧЛМАЮБЕФ Ч УЕВС ЕЭЕ ГЕМЩК ТСД НЕФПДПЧ, ЛПФПТЩЕ ВХДХФ ХРПНЙОБФШУС ОЙЦЕ, ОП РТЕЦДЕ С РТЕДМБЗБА ЧЪЗМСОХФШ ОБ ТБВПЮЙК ЛПД ЪБЗПФПЧЛЙ ДТБКЧЕТБ, РПУФТПЕООЩК У ХЮЕФПН ЧЩЫЕУЛБЪБООПЗП. ьФПФ ЛПД РПСУОСЕФ РПТСДПЛ ЧЪБЙНПДЕКУФЧЙС НЕЦДХ ПРЙУБООЩНЙ ЬМЕНЕОФБНЙ.

ьФП НПДХМШ ТЕБМЙЪХЕФ ФЙРЙЮОХА ФПЮЛХ ЧИПДБ — ЖХОЛГЙА rtl8139_init_module. ъДЕУШ ПРТЕДЕМСЕФУС ХУФТПКУФЧП ФЙРБ net_device, ЪБДБЕФУС ЕЗП ЙНС «rtl8139», РПУМЕ ЮЕЗП ХУФТПКУФЧП ТЕЗЙУФТЙТХЕФУС Ч СДТЕ. дТХЗБС ЧБЦОБС ЖХОЛГЙС rtl8139_init — ЧУФБЧМСЕФ ЪБЗПФПЧЛЙ ЖХОЛГЙК (ФПЮОЕЕ ЙИ БДТЕУБ, РТЙН. РЕТЕЧ.) rtl8139_open, rtl8139_stop, rtl8139_xmit Ч УФТХЛФХТЕ net_device. лПЗДБ ЧЩЪЩЧБЕФУС ЖХОЛГЙС rtl8139_open — ПОБ ПВЯСЧМСЕФ П ЗПФПЧОПУФЙ ДТБКЧЕТБ Л РТЙЕНХ ДБООЩИ ЧЩЪПЧПН ЖХОЛГЙЙ netif_start_queue. бОБМПЗЙЮОП, РТЙ ПУФБОПЧЛЕ ЙОФЕТЖЕКУБ ЧЩЪЩЧБЕФУС ЖХОЛГЙС netif_stop_queue.

рПРТПВХЕН УЛПНРЙМЙТПЧБФШ ЧЩЫЕРТЙЧЕДЕООЩК НПДХМШ Й «РПЙЗТБФШ» У ОЙН. дМС ЬФПЗП ДПУФБФПЮОП ЧПУРПМШЪПЧБФШУС ЛПНБОДПК ‘cc’ ФБЛ, ЛБЛ ЬФП РПЛБЪБОП ОЙЦЕ:

б ФЕРЕТШ РПРТПВХЕН РТПЧЕТЙФШ ОБЫХ ЪБЗПФПЧЛХ. с ОБ УЧПЕК УЙУФЕНЕ РПМХЮЙМ УМЕДХАЭЕЕ (ЮФПВЩ РПМХЮЙФШ УРЙУПЛ ЪБЗТХЦЕООЩИ НПДХМЕК, ЧПУРПМШЪХКФЕУШ ХФЙМЙФПК lsmod):

(рТЙНЕЮБОЙЕ: юФПВЩ ЙНЕФШ ЧПЪНПЦОПУФШ ЪБЗТХЦБФШ/ЧЩЗТХЦБФШ НПДХМЙ СДТБ, ЧЩ ДПМЦОЩ ПВМБДБФШ РТЙЧЙМЕЗЙСНЙ УХРЕТРПМШЪПЧБФЕМС.)

(рТПЧЕТЕОП, «НЙО» ОЕФ. рТЙН.ТЕД.)

йФБЛ, НЩ РПЪОБЛПНЙМЙУШ У ПУОПЧОЩНЙ РТЙОГЙРБ РПУФТПЕОЙС ДТБКЧЕТБ ЖЙЛФЙЧОПЗП ХУФТПКУФЧБ. б ФЕРЕТШ РЕТЕКДЕН Л ТЕБМЙЪБГЙЙ ДТБКЧЕТБ ДМС ЛПОЛТЕФОПК УЕФЕЧПК РМБФЩ rtl8139.

рМБФБ PCI Й ЕЕ ЙОЙГЙБМЙЪБГЙС

иПФС УЕФЕЧПК ЙОФЕТЖЕКУ Й ВЩМ УПЪДБО ОБНЙ, ОП ПО РПЛБ ЕЭЕ ОЕ Ч УПУФПСОЙЙ ПВОБТХЦЙФШ Й ЙОЙГЙБМЙЪЙТПЧБФШ УЕФЕЧХА РМБФХ. ьФП УФБОЕФ ЧПЪНПЦОЩН ФПМШЛП РПУМЕ ФПЗП, ЛБЛ НЩ ОБКДЕН УППФЧЕФУФЧХАЭЕЕ PCI-ХУФТПКУФЧП. фБЛЙН ПВТБЪПН, ОБН УПЧЕТЫЕООП ОЕПВИПДЙНП РЕТЕКФЙ Л ТБУУНПФТЕОЙА ЙОФЕТЖЕКУБ PCI Й ОБВПТБ ЖХОЛГЙК ДМС ТБВПФЩ У ОЙН.

лБЛ С ХЦЕ ХРПНЙОБМ ТБОЕЕ, PCI — ЬФП РПМОЩК ОБВПТ УРЕГЙЖЙЛБГЙК, ПРТЕДЕМСАЭЙИ РПТСДПЛ ЧЪБЙНПДЕКУФЧЙС НЕЦДХ ТБЪМЙЮОЩНЙ ЮБУФСНЙ ЛПНРШАФЕТБ. лБЦДПЕ PCI-ХУФТПКУФЧП ЙДЕОФЙЖЙГЙТХЕФУС РП ОПНЕТХ ЫЙОЩ, ОПНЕТХ ХУФТПКУФЧБ Й ОПНЕТХ ЖХОЛГЙЙ. уРЕГЙЖЙЛБГЙС ДПРХУЛБЕФ ОБМЙЮЙЕ Ч УЙУФЕНЕ ДП 256 ЫЙО PCI Й ДП 32 ХУФТПКУФЧ ОБ ЛБЦДПК ЙЪ ОЙИ.

чУФТПЕООПЕ РТПЗТБННОПЕ ПВЕУРЕЮЕОЙЕ ЛПНРШАФЕТБ (firmware) ЧЩРПМОСЕФ ЙОЙГЙБМЙЪБГЙА БРРБТБФХТЩ PCI ЧП ЧТЕНС ЪБЗТХЪЛЙ, ПФПВТБЦБЕФ ДЙБРБЪПО БДТЕУПЧ ЧЧПДБ/ЧЩЧПДБ ЛБЦДПЗП ХУФТПКУФЧБ ОБ ТБЪМЙЮОЩЕ БДТЕУОЩЕ РТПУФТБОУФЧБ, ДПУФХРОЩЕ Ч ЛПОЖЙЗХТБГЙПООПН РТПУФТБОУФЧЕ, ЛПФПТПЕ РТЕДУФБЧМСЕФ УПВПК 256-ФЙ ВБКФОХА ПВМБУФШ ОБ ЛБЦДПЕ ХУФТПКУФЧП. лБЦДПЕ ЙЪ PCI-ХУФТПКУФЧ ЙДЕОФЙЖЙГЙТХЕФУС ФТЕНС ТЕЗЙУФТБНЙ: vendorID, deviceID Й class. йОПЗДБ, Ч ГЕМСИ ВПМЕЕ ФПЮОПК ЙДЕОФЙЖЙЛБГЙЙ ЙУРПМШЪХАФУС ТЕЗЙУФТЩ Subsystem vendorID Й Subsystem deviceID. тБУУНПФТЙН ЙИ ВПМЕЕ РПДТПВОП.

  • vendorID — 16-ФЙ ВЙФПЧПЕ ЮЙУМП, ЙДЕОФЙЖЙГЙТХАЭЕЕ РТПЙЪЧПДЙФЕМС. оБРТЙНЕТ, vendorID, ДМС ХУФТПКУФЧ РТПЙЪЧЕДЕООЩИ Intel, РТЕДУФБЧМСЕФ УПВПК ЮЙУМП 0x8086.
  • deviceID — ДПРПМОЙФЕМШОПЕ 16-ФЙ ВЙФПЧЩК ЙДЕОФЙЖЙЛБФПТ ЖЙТНЩ-РТПЙЪЧПДЙФЕМС. ч РБТЕ У vendorID ПДОПЪОБЮОП ЙДЕОФЙЖЙГЙТХЕФ ХУФТПКУФЧП.
  • мАВПЕ РЕТЙЖЕТЙКОПЕ ХУФТПКУФЧП РТЙОБДМЕЦЙФ Л ЛБЛПНХ МЙВП ЛМБУУХ ХУФТПКУФЧ. Class — ЬФП 16-ФЙ ВЙФПЧПЕ ЮЙУМП, Ч ЛПФПТПН ЪОБЮБЭЙЕ ВБКФЩ ПРТЕДЕМСАФ ЛМБУУ ХУФТПКУФЧБ, ФБЛ ОБРТЙНЕТ ethernet-ХУФТПКУФЧБ РТЙОБДМЕЦБФ ЛМБУУХ УЕФЕЧЩИ ХУФТПКУФЧ.
  • Subsystem vendorID Й Subsystem deviceID — ЬФП ДПРПМОЙФЕМШОЩЕ РПМС, ЛПФПТЩЕ ЙУРПМШЪХАФУС ДМС ХФПЮОСАЭЕК ЙДЕОФЙЖЙЛБГЙЙ ХУФТПКУФЧБ.

рПМОЩК УРЙУПЛ ХУФТПКУФЧ PCI, Ч пу Linux, НПЦЕФ ВЩФШ РПМХЮЕО ЧЩЪПЧПН ЛПНБОДЩ lspci.

пФФБМЛЙЧБСУШ ПФ ЬФПК ОПЧПК ЙОЖПТНБГЙЙ, НЩ ФЕРЕТШ НПЦЕН РПРТПВПЧБФШ ЙДЕОФЙЖЙГЙТПЧБФШ РМБФХ rtl8139, Ч ЖХОЛГЙЙ rtl8139_init. йЪНЕОЕООБС ЧЕТУЙС ФЕРЕТШ ВХДЕФ ЧЩЗМСДЕФШ ФБЛ:

лБЛ ЧЩ НПЦЕФЕ ЧЙДЕФШ, ЖХОЛГЙС probe ЧЩЪЩЧБЕФУС ЙЪ ЖХОЛГЙЙ rtl8139_init. еУМЙ ЧЩ ВЩМЙ ДПУФБФПЮОП ЧОЙНБФЕМШОЩ, ФП ОБЧЕТОСЛБ ЪБНЕФЙМЙ, ЮФП ЖХОЛГЙЙ probe РЕТЕДБАФУС ДЧБ ЧИПДОЩИ БТЗХНЕОФБ: ХЛБЪБФЕМШ ОБ УФТХЛФХТХ struct net_device Й ХЛБЪБФЕМШ ОБ УФТХЛФХТХ struct pci_dev. зДЕ РЕТЧБС УППФЧЕФУФЧХЕФ УЕФЕЧПНХ ХУФТПКУФЧХ, Б ЧФПТБС — PCI-ХУФТПКУФЧХ.

жХОЛГЙС pci_present РТПЧЕТСЕФ ОБМЙЮЙС РПДДЕТЦЛЙ PCI. ч УМХЮБЕ ХУРЕИБ ЧПЪЧТБЭБЕФ ЪОБЮЕОЙЕ ‘0’. ъБФЕН, У РПНПЭША ЖХОЛГЙЙ pci_find_device, РТПЙЪЧПДЙФУС РПРЩФЛБ ЙОЙГЙБМЙЪБГЙЙ РМБФЩ RTL8139. жХОЛГЙС РТЙОЙНБЕФ ОБ ЧИПДЕ ЪОБЮЕОЙС vendor_ID, device_ID Й ХЛБЪБФЕМШ ‘pdev’. ч УМХЮБЕ ПФУХФУФЧЙС ПЫЙВПЛ, Ф.Е. ЛПЗДБ ХУФТПКУФЧП RTL8139 РПДЛМАЮЕОП ЖЙЪЙЮЕУЛЙ, ЬФБ ЖХОЛГЙС ЧПЪЧТБЭБЕФ ХЛБЪБФЕМШ ОБ ХЦЕ ЪБРПМОЕООХА УФТХЛФХТХ pdev. лПОУФБОФЩ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139 ПРТЕДЕМСАФ ЪОБЮЕОЙС vendorID Й device_ID ДМС РМБФЩ realtek. пОЙ ПРТЕДЕМЕОЩ Ч ЖБКМЕ linux/pci.h.

жХОЛГЙЙ pci_read_config_byte/word/dword УЮЙФЩЧБАФ byte/word/dword ЙЪ ЛПОЖЙЗХТБГЙПООПК ПВМБУФЙ ХУФТПКУФЧБ. чЩЪПЧПН ЖХОЛГЙЙ pci_enable РТПЙЪЧПДЙФУС «ЧЛМАЮЕОЙЕ» ХУФТПКУФЧБ rtl8139, ЬФБ ЖХОЛГЙС ФБЛ ЦЕ ЧЩРПМОСЕФ ТЕЗЙУФТБГЙА ОПНЕТБ РТЕТЩЧБОЙС ЙОФЕТЖЕКУБ. уППФЧЕФУФЧЕООП, ЕУМЙ ЧУЕ ЙДЕФ ЗМБДЛП, ФП ЧБЫБ РМБФБ rtl_8139 ВХДЕФ ПВОБТХЦЕОБ Й УЧСЪБОБ У ПРТЕДЕМЕООЩН ОПНЕТПН РТЕТЩЧБОЙС.

ч УМЕДХАЭЕК ЮБУФЙ НЩ ТБУУНПФТЙН РТПВМЕНХ ПРТЕДЕМЕОЙС БРРБТБФОПЗП БДТЕУБ ХУФТПКУФЧБ rtl8139 Й ОБЮОЕН ПВНЕО ДБООЩНЙ.

Читайте также:  Как посмотреть разрядность системы linux

Источник

LXF78:Драйвер сетевого устройства – своими руками

Подписка на печатную версию Весь 2015 год (12 номеров) Первое полугодие (6 номеров) Второе полугодие (6 номеров) Подписка на электронную версию Весь 2015 год (12 номеров) Первое полугодие (6 номеров) Второе полугодие (6 номеров) Подшивки старых номеров журнала (печатные версии) Весь 2014 год (12 номеров) Первое полугодие (6 номеров) Второе полугодие (6 номеров)

Часть 1. Не нашли, как включить нужную функцию в make menuconfig? Не беда – Игорь Тимошенко расскажет, как написать драйвер самостоятельно!

Содержание

Эта статья предназначена для тех, кто желает приобрести начальные знания, позволяющие самостоятельно создавать драйверы сетевых устройств, работающих в среде ОС Linux. Не так давно у меня самого возникла такая задача, и я обнаружил явный недостаток информации по этой теме. В доступной литературе на русском языке подробно описаны все драйвера, кроме сетевых. В англоязычной библии на все времена «Linux Device Drivers» (http://www.oreilly.com/catalog/linuxdrive3) есть всё, но понимания этого «всего» можно достичь, пройдя не самый простой путь. Отчаянные метания по форумам привели меня к неутешительному выводу, что интересующихся этим вопросом несколько больше, чем что-то понимающих в нём. Итак, в результате многочисленных проб и ошибок, я получил некоторое количество полезных знаний и драйвер, который сейчас успешно использую дома для подключения второго компьютера к Интернету. Простота получившейся программы натолкнула меня на мысль, что путь, который я прошёл, мог бы быть гораздо короче и куда менее извилист, если бы в начале мне удалось прочитать статью, которую я сейчас вам и предлагаю.

Не смотря на то, что по ходу изложения, я постараюсь сделать необходимые разъяснения и ссылки, для успешного и правильного понимания материала статьи, читателю понадобятся некоторые начальные познания. Прежде всего – знакомство с языком программирования C, кроме того, я полагаю, что читатель представляет, как работают компьютерные сети, уже работал в ОС Linux и знает, что такое «модуль ядра».

Все примеры, приведённые в статье – рабочие, и представляют собой необходимые начальные этапы того самого пути, который нужно пройти, чтобы научиться создавать драйверы различных сетевых устройств. Я использовал дистрибутив Mandrake 10.1 с ядром 2.6.8.1-12mdk. Для других версий ядра, возможно, понадобится внести некоторые незначительные изменения в исходные тексты.

Чтобы иметь возможность компилировать модули ядра, после обычной установки дистрибутива, нужно дополнительно установить исходные тексты вашей версии ядра в каталог usr/src. В моём дистрибутиве это пришлось сделать вручную, потому, что даже при выборе расширенного варианта установки и указании на необходимость включения в неё исходных текстов, в нужном каталоге у меня оказались только дремучие исходники ядра 2.4. Нужные исходные тексты находятся на третьем диске дистрибутива в папке /media/main3/ в виде rpm-пакета: kernel-source-2.6-2.6.8.1-12mdk.i586.rpm. Их можно установить с помощью команды:

Установку следует производить в консольном режиме из каталога, содержащего пакет, в режиме суперпользователя.

Перед началом работы советую создать свой рабочий каталог /home/user/ , в котором будут находиться ваши исход ные тексты и поместить туда Makefile, взятый мной из примера, предлагаемого средой разработки KDevelop, слегка модифицированный, для обеспечения его работоспособности (ох уж эти особенности свободно распространяемых программ!):

Чтобы приспособить этот файл под свои нужды, замените myname на имя вашего модуля. Сборка осуществляется командой make.

Добро пожаловать в мир хакеров Linux!

Для начала, создадим простейший модуль ядра, который будет регистрироваться в системе и сообщать об этом миру доступными ему средствами: «Hello world!». Это необходимый шаг: надо же уважать традиции! Кроме этого, он позволяет удостовериться в работоспособности инструментов (компилятора, компоновщика, . ), корректности make-файлов и правильности установки исходных текстов Linux. Кстати, корифеи от ядра настоятельно рекомендуют разрабатывать и отлаживать модули в текстовой консоли. Вызов printk (речь о котором пойдет ниже) не работает с графическими терминалами типа xterm, поэтому единственным способом понять, что происходит, остается просмотр файлов журнала, а это не всегда удобно. В общем, вооружайтесь любимым текстовым редактором (от mcedit до joe) и – в путь!

Сохраните этот модуль в каком-нибудь файле (например, helloworld.c), внесите соответствующие изменения в Makefile (см. выше), а затем дайте команду make. На экране должен появиться текст:

После успешной компиляции в вашем каталоге образуется множество файлов, из которых для нас интересен собственно объектный модуль helloworld.ko. Для загрузки получившегося модуля в ядро нужно использовать команду:

При этом наш модуль будет занесён в список загруженных модулей в файле /proc/modules (в этом можно убедиться, используя команду cat /proc/modules | grep helloworld). Кроме того, будет запущена инициализирующая функция ssl_init_module(void), вызывающая системную функцию printk(), которая предназначена для регистрации событий и предупреждений из режима ядра. Мы не будем сейчас подробно рассматривать работу этой функции, отметим лишь, что переданное ей в качестве аргумента сообщение «Hello World!» после загрузки модуля следует искать в файле /var/log/messages, куда (при соответствующей настройке демона syslog) отправляется большинство сообщений, приходящих из ядра. Для удобства наблюдения за появляющимися новыми сообщениями в этом файле можно воспользоваться командой

Если вы проигнорировали советы бывалых и все-таки разрабатываете модули ядра в графической среде, её удобно запускать в отдельном окне терминала, создав своеобразную «консоль сообщений».

Выгрузить модуль из ядра можно при помощи команды:

При этом в запущенной консоли сообщений можно будет наблюдать, как модуль попрощается с миром все теми же «доступными ему средствами».

Читайте также:  Драйвер для bluetooth устройств для windows

Матрица: подключение

Следующим шагом на нашем пути будет создание простейшего модуля сетевого драйвера. Для этого в нашем модуле нужно определить структуру данных сетевого драйвера struct net_device, определение которой находится в заголовочном файле /usr/include/linux/netdevice.h. В структуре представлено множество функций и полей, из которых для нас наиболее важными являются следующие:
char name[IFNAMSIZ] – содержит имя интерфейса, которое будет отображаться при конфигурировании сетевой подсистемы.
int (*open) (struct net_device *dev) – функция, которая запускается всякий раз, когда утилита ifconfig активирует интерфейс.
int (*stop) (struct net_device *dev) – функция, которая запускается при остановке интерфейса.
int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev) – функция, которая активизируется сетевой подсистемой всякий раз, когда нужно передать пакет данных.
struct net_device_stats* (*get_stats)(struct net_device *dev) – функция, которая вызывается всякий раз, когда какое либо приложение пытается получить статистические данные о работе интерфейса.
void *priv – дополнительный указатель, который можно использовать произвольным образом.

Остальные поля и функции обеспечивают драйверу дополнительные возможности, которые мы сейчас рассматривать не будем. Их назначение можно узнать в справочной литературе. Следует сразу отметить, что приём данных от сетевого устройства обычно происходит по прерыванию, его обработчиком, и явного указания на этот обработчик в структуре интерфейса не содержится.

Нам нужно заполнить необходимые для работы драйвера поля. Если поле содержит указатель на функцию – необходимо реализовать эту функцию. В нашем драйвере мы определим функции инициализации (open), остановки (stop) и передачи данных (hard_start_xmit), кроме того определим структуру net_device_stats, содержимое которой мы будем получать через дополнительный указатель (priv).

Для того, чтобы система узнала, что загружаемый модуль является драйвером сетевого устройства, при загрузке модуль дожен сообщить ей об этом специальной функцией register_netdev(). О своей выгрузке модуль сообщает функцией unregister_netdev(). В качестве аргумента для этих функций передаётся указатель на структуру данных драйвера.

Для инициализации интерфейса в сетевой подсистеме драйвер должен воспользоваться специальной функцией netif_start_queue(), при остановке – функцией netif_stop_queue(), аргументом которых также является указатель на структуру драйвера.

При необходимости передачи данных через сетевой интерфейс ОС вызывает функцию hard_start_xmit() которой в качестве аргумента передаётся указатель на буфер (sk_buff), содержащий готовую IP-датаграмму. Вызванная функция должна сделать всё необходимое для отправки датаграммы сетевому устройству для передачи на физическом уровне, а затем сообщить системе о том, что пакет передан, вызвав функцию dev_kfree_skb(), аргументом которой служит указатель на буфер, полученный от ОС. На этом цикл передачи для драйвера завершается, система может заполнять освобождённый буфер новыми данными, а драйвер ожидает следующей передачи и указателя на готовый буфер.

Поскольку наш драйвер пока не связан с каким либо устройством, функция передачи будет переносить передаваемые данные в свой собственный буфер (my_buf), а затем регистрировать эти данные в виде сообщений при помощи функции printk(). Для представления регистрируемых данных в текстовом формате мы введём в программу вспомогательные функции tpdumpk() и printAddr().

Приведём текст нашего, пусть простейшего, но уже сетевого драйвера:

Для загрузки и инициализации скомпилированного драйвера удобно пользоваться небольшим сценарием, текст которого приведен ниже:

Задержка (sleep 1) требуется для того, чтобы система успела зарегистрировать модуль и была готова к инициализации его интерфейса к моменту подачи команды ifconfig. После загрузки и инициализации нашего драйвера на экране должен появиться примерно такой текст (информация о других сетевых интерфейсах опущена для экономии места):

Как видно, наш интерфейс запущен, имеет собственный IP-адрес и готов к работе.

Если ваш компьютер подключен к Интернету, то перед тем, как отправлять на наш интерфейс данные, убедитесь, что этому не препятствуют настройки компьютера. Сконфигурируйте межсетевой экран (firewall) с учётом появления новой подсети, или даже вообще отключите его на время отладки (особо осторожные могут одновременно отключиться и от Интернета).

Для проверки работоспособности нашего интерфейса нужно запустить в отдельной консоли команду tail -f /var/log/messages для отображения текущих сообщений из ядра, а в вашей рабочей консоли воспользоваться командой:

Таким образом, мы пытаемся отправлять ICMP-пакеты на несуществующий интерфейс, который доступен через наш драйвер. Поскольку такого интерфейса, как и функций приема данных, у нашего драйвера пока нет, для ОС все отправленные пакеты будут потеряны. Но не для нас! Все передаваемые пакеты будут документироваться в файле /var/log/messages, и это можно наблюдать в консоли сообщений примерно в таком виде:

Если ваш компьютер настроен на работу в сети, то вы наверняка увидите, что периодически наш интерфейс поступают и широковещательные пакеты, которые несложно узнать на однообразном фоне управляющих.

Наша следующая задача – научить драйвер принимать данные и отправлять их в сетевую подсистему ОС Linux. Для этого мы введём в него необходимые функции, а затем свяжем с аппаратным устройством, управляющим передачей данных по кабелю. В качестве такого устройства мы используем СОМ-порт компьютера. Таким образом мы получим программу, похожую на известный драйвер SLIP. Конечно, наш драйвер не будет поддерживать всех функций своего известного прототипа, но зато он будет намного проще и не будет требовать для работы дополнительных программ-демонов. Однако, все это будет уже в следующей части. Не пропустите!

Источник

Оцените статью