1 Star 0 Fork 99

yangqiming/grub2

forked from src-openEuler/grub2 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0119-Support-UEFI-networking-protocols.patch 143.53 KB
一键复制 编辑 原始数据 按行查看 历史
hanzj0122_admin 提交于 2020-07-29 20:47 . update to 2.04
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056
From 52cf36ce649fc8a5f915b143ccc680cf4a2ebbda Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Wed, 22 Feb 2017 14:27:50 +0800
Subject: [PATCH 119/220] Support UEFI networking protocols
References: fate#320130, bsc#1015589, bsc#1076132
Patch-Mainline: no
V1:
* Add preliminary support of UEFI networking protocols
* Support UEFI HTTPS Boot
V2:
* Workaround http data access in firmware
* Fix DNS device path parsing for efinet device
* Relaxed UEFI Protocol requirement
* Support Intel OPA (Omni-Path Architecture) PXE Boot
V3:
* Fix bufio in calculating address of next_buf
* Check HTTP respond code
* Use HEAD request method to test before GET
* Finish HTTP transaction in one go
* Fix bsc#1076132
Signed-off-by: Michael Chang <mchang@suse.com>
[pjones: make efi_netfs not duplicate symbols from efinet]
Signed-off-by: Peter Jones <pjones@redhat.com>
---
grub-core/Makefile.core.def | 12 +
grub-core/io/bufio.c | 2 +-
grub-core/kern/efi/efi.c | 96 ++-
grub-core/net/drivers/efi/efinet.c | 27 +
grub-core/net/efi/dhcp.c | 397 ++++++++++
grub-core/net/efi/efi_netfs.c | 57 ++
grub-core/net/efi/http.c | 419 +++++++++++
grub-core/net/efi/ip4_config.c | 398 ++++++++++
grub-core/net/efi/ip6_config.c | 422 +++++++++++
grub-core/net/efi/net.c | 1428 ++++++++++++++++++++++++++++++++++++
grub-core/net/efi/pxe.c | 424 +++++++++++
grub-core/net/net.c | 74 ++
include/grub/efi/api.h | 180 ++++-
include/grub/efi/dhcp.h | 343 +++++++++
include/grub/efi/http.h | 215 ++++++
include/grub/net/efi.h | 144 ++++
util/grub-mknetdir.c | 23 +-
17 files changed, 4620 insertions(+), 41 deletions(-)
create mode 100644 grub-core/net/efi/dhcp.c
create mode 100644 grub-core/net/efi/efi_netfs.c
create mode 100644 grub-core/net/efi/http.c
create mode 100644 grub-core/net/efi/ip4_config.c
create mode 100644 grub-core/net/efi/ip6_config.c
create mode 100644 grub-core/net/efi/net.c
create mode 100644 grub-core/net/efi/pxe.c
create mode 100644 include/grub/efi/dhcp.h
create mode 100644 include/grub/efi/http.h
create mode 100644 include/grub/net/efi.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 49c5dc4..48491b5 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2277,6 +2277,12 @@ module = {
};
module = {
+ name = efi_netfs;
+ common = net/efi/efi_netfs.c;
+ enable = efi;
+};
+
+module = {
name = net;
common = net/net.c;
common = net/dns.c;
@@ -2290,6 +2296,12 @@ module = {
common = net/arp.c;
common = net/netbuff.c;
common = net/url.c;
+ efi = net/efi/net.c;
+ efi = net/efi/http.c;
+ efi = net/efi/pxe.c;
+ efi = net/efi/ip4_config.c;
+ efi = net/efi/ip6_config.c;
+ efi = net/efi/dhcp.c;
};
module = {
diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
index a458c3a..1637731 100644
--- a/grub-core/io/bufio.c
+++ b/grub-core/io/bufio.c
@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
return res;
/* Need to read some more. */
- next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1);
+ next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size;
/* Now read between file->offset + res and bufio->buffer_at. */
if (file->offset + res < next_buf)
{
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 19054b1..ada3004 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -709,7 +709,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
{
grub_efi_ipv4_device_path_t *ipv4
= (grub_efi_ipv4_device_path_t *) dp;
- grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)",
+ grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x",
(unsigned) ipv4->local_ip_address[0],
(unsigned) ipv4->local_ip_address[1],
(unsigned) ipv4->local_ip_address[2],
@@ -722,33 +722,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
(unsigned) ipv4->remote_port,
(unsigned) ipv4->protocol,
(unsigned) ipv4->static_ip_address);
+ if (len == sizeof (*ipv4))
+ {
+ grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u",
+ (unsigned) ipv4->gateway_ip_address[0],
+ (unsigned) ipv4->gateway_ip_address[1],
+ (unsigned) ipv4->gateway_ip_address[2],
+ (unsigned) ipv4->gateway_ip_address[3],
+ (unsigned) ipv4->subnet_mask[0],
+ (unsigned) ipv4->subnet_mask[1],
+ (unsigned) ipv4->subnet_mask[2],
+ (unsigned) ipv4->subnet_mask[3]);
+ }
+ grub_printf (")");
}
break;
case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE:
{
grub_efi_ipv6_device_path_t *ipv6
= (grub_efi_ipv6_device_path_t *) dp;
- grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)",
- (unsigned) ipv6->local_ip_address[0],
- (unsigned) ipv6->local_ip_address[1],
- (unsigned) ipv6->local_ip_address[2],
- (unsigned) ipv6->local_ip_address[3],
- (unsigned) ipv6->local_ip_address[4],
- (unsigned) ipv6->local_ip_address[5],
- (unsigned) ipv6->local_ip_address[6],
- (unsigned) ipv6->local_ip_address[7],
- (unsigned) ipv6->remote_ip_address[0],
- (unsigned) ipv6->remote_ip_address[1],
- (unsigned) ipv6->remote_ip_address[2],
- (unsigned) ipv6->remote_ip_address[3],
- (unsigned) ipv6->remote_ip_address[4],
- (unsigned) ipv6->remote_ip_address[5],
- (unsigned) ipv6->remote_ip_address[6],
- (unsigned) ipv6->remote_ip_address[7],
+ grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x",
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]),
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]),
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]),
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]),
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]),
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]),
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]),
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]),
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]),
(unsigned) ipv6->local_port,
(unsigned) ipv6->remote_port,
(unsigned) ipv6->protocol,
(unsigned) ipv6->static_ip_address);
+ if (len == sizeof (*ipv6))
+ {
+ grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned) ipv6->prefix_length,
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]),
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]),
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]),
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]),
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]),
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]),
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]),
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7]));
+ }
+ grub_printf (")");
}
break;
case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE:
@@ -788,6 +815,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
dump_vendor_path ("Messaging",
(grub_efi_vendor_device_path_t *) dp);
break;
+ case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE:
+ {
+ grub_efi_uri_device_path_t *uri
+ = (grub_efi_uri_device_path_t *) dp;
+ grub_printf ("/URI(%s)", uri->uri);
+ }
+ break;
+ case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE:
+ {
+ grub_efi_dns_device_path_t *dns
+ = (grub_efi_dns_device_path_t *) dp;
+ if (dns->is_ipv6)
+ {
+ grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)",
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16),
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])),
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16),
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])),
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16),
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])),
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16),
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3])));
+ }
+ else
+ {
+ grub_printf ("/DNS(%d.%d.%d.%d)",
+ dns->dns_server_ip[0].v4.addr[0],
+ dns->dns_server_ip[0].v4.addr[1],
+ dns->dns_server_ip[0].v4.addr[2],
+ dns->dns_server_ip[0].v4.addr[3]);
+ }
+ }
+ break;
default:
grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype);
break;
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
index c843654..ca8bd3c 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -28,6 +28,7 @@
#include <grub/lib/hexdump.h>
#include <grub/types.h>
#include <grub/net/netbuff.h>
+#include <grub/env.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -492,6 +493,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
ldp = grub_efi_find_last_device_path (ddp);
+ /* Skip the DNS Device */
+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
+ {
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ ldp->length = sizeof (*ldp);
+
+ ldp = grub_efi_find_last_device_path (ddp);
+ }
+
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
@@ -761,6 +773,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
continue;
dup_dp = grub_efi_duplicate_device_path (dp);
@@ -776,6 +789,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
}
dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
+ {
+ dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ dup_ldp->length = sizeof (*dup_ldp);
+ }
+
+ dup_ldp = grub_efi_find_last_device_path (dup_dp);
dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
dup_ldp->length = sizeof (*dup_ldp);
@@ -846,6 +868,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
GRUB_MOD_INIT(efinet)
{
+ if (grub_efi_net_config)
+ return;
+
grub_efinet_findcards ();
grub_efi_net_config = grub_efi_net_config_real;
}
@@ -857,5 +882,7 @@ GRUB_MOD_FINI(efinet)
FOR_NET_CARDS_SAFE (card, next)
if (card->driver == &efidriver)
grub_net_card_unregister (card);
+
+ grub_efi_net_config = NULL;
}
diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c
new file mode 100644
index 0000000..dbef63d
--- /dev/null
+++ b/grub-core/net/efi/dhcp.c
@@ -0,0 +1,397 @@
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/misc.h>
+#include <grub/net/efi.h>
+#include <grub/charset.h>
+
+#ifdef GRUB_EFI_NET_DEBUG
+static void
+dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode)
+{
+ switch (mode->state)
+ {
+ case GRUB_EFI_DHCP4_STOPPED:
+ grub_printf ("STATE: STOPPED\n");
+ break;
+ case GRUB_EFI_DHCP4_INIT:
+ grub_printf ("STATE: INIT\n");
+ break;
+ case GRUB_EFI_DHCP4_SELECTING:
+ grub_printf ("STATE: SELECTING\n");
+ break;
+ case GRUB_EFI_DHCP4_REQUESTING:
+ grub_printf ("STATE: REQUESTING\n");
+ break;
+ case GRUB_EFI_DHCP4_BOUND:
+ grub_printf ("STATE: BOUND\n");
+ break;
+ case GRUB_EFI_DHCP4_RENEWING:
+ grub_printf ("STATE: RENEWING\n");
+ break;
+ case GRUB_EFI_DHCP4_REBINDING:
+ grub_printf ("STATE: REBINDING\n");
+ break;
+ case GRUB_EFI_DHCP4_INIT_REBOOT:
+ grub_printf ("STATE: INIT_REBOOT\n");
+ break;
+ case GRUB_EFI_DHCP4_REBOOTING:
+ grub_printf ("STATE: REBOOTING\n");
+ break;
+ default:
+ grub_printf ("STATE: UNKNOWN\n");
+ break;
+ }
+
+ grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n",
+ mode->client_address[0],
+ mode->client_address[1],
+ mode->client_address[2],
+ mode->client_address[3]);
+ grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n",
+ mode->server_address[0],
+ mode->server_address[1],
+ mode->server_address[2],
+ mode->server_address[3]);
+ grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n",
+ mode->subnet_mask[0],
+ mode->subnet_mask[1],
+ mode->subnet_mask[2],
+ mode->subnet_mask[3]);
+ grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n",
+ mode->router_address[0],
+ mode->router_address[1],
+ mode->router_address[2],
+ mode->router_address[3]);
+}
+#endif
+
+static grub_efi_ipv4_address_t *
+grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet)
+{
+ grub_efi_dhcp4_packet_option_t **option_list;
+ grub_efi_status_t status;
+ grub_efi_uint32_t option_count = 0;
+ grub_efi_uint32_t i;
+
+ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL);
+
+ if (status != GRUB_EFI_BUFFER_TOO_SMALL)
+ return NULL;
+
+ option_list = grub_malloc (option_count * sizeof(*option_list));
+ if (!option_list)
+ return NULL;
+
+ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (option_list);
+ return NULL;
+ }
+
+ for (i = 0; i < option_count; ++i)
+ {
+ if (option_list[i]->op_code == 6)
+ {
+ grub_efi_ipv4_address_t *dns_address;
+
+ if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0))
+ continue;
+
+ /* We only contact primary dns */
+ dns_address = grub_malloc (sizeof (*dns_address));
+ if (!dns_address)
+ {
+ grub_free (option_list);
+ return NULL;
+ }
+ grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address));
+ grub_free (option_list);
+ return dns_address;
+ }
+ }
+
+ grub_free (option_list);
+ return NULL;
+}
+
+#if 0
+/* Somehow this doesn't work ... */
+static grub_err_t
+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_efi_net_device *dev;
+ for (dev = net_devices; dev; dev = dev->next)
+ {
+ grub_efi_pxe_t *pxe = dev->ip4_pxe;
+ grub_efi_pxe_mode_t *mode = pxe->mode;
+ grub_efi_status_t status;
+
+ if (!mode->started)
+ {
+ status = efi_call_2 (pxe->start, pxe, 0);
+
+ if (status != GRUB_EFI_SUCCESS)
+ grub_printf ("Couldn't start PXE\n");
+ }
+
+ status = efi_call_2 (pxe->dhcp, pxe, 0);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("dhcp4 configure failed, %d\n", (int)status);
+ continue;
+ }
+
+ dev->prefer_ip6 = 0;
+ }
+
+ return GRUB_ERR_NONE;
+}
+#endif
+
+static grub_err_t
+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
+ int argc,
+ char **args)
+{
+ struct grub_efi_net_device *netdev;
+
+ for (netdev = net_devices; netdev; netdev = netdev->next)
+ {
+ grub_efi_status_t status;
+ grub_efi_dhcp4_mode_data_t mode;
+ grub_efi_dhcp4_config_data_t config;
+ grub_efi_dhcp4_packet_option_t *options;
+ grub_efi_ipv4_address_t *dns_address;
+ grub_efi_net_ip_manual_address_t net_ip;
+ grub_efi_net_ip_address_t ip_addr;
+ grub_efi_net_interface_t *inf = NULL;
+
+ if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0)
+ continue;
+
+ grub_memset (&config, 0, sizeof(config));
+
+ config.option_count = 1;
+ options = grub_malloc (sizeof(*options) + 2);
+ /* Parameter request list */
+ options->op_code = 55;
+ options->length = 3;
+ /* subnet mask */
+ options->data[0] = 1;
+ /* router */
+ options->data[1] = 3;
+ /* DNS */
+ options->data[2] = 6;
+ config.option_list = &options;
+
+ /* FIXME: What if the dhcp has bounded */
+ status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config);
+ grub_free (options);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("dhcp4 configure failed, %d\n", (int)status);
+ continue;
+ }
+
+ status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("dhcp4 start failed, %d\n", (int)status);
+ continue;
+ }
+
+ status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
+ continue;
+ }
+
+#ifdef GRUB_EFI_NET_DEBUG
+ dhcp4_mode_print (&mode);
+#endif
+
+ for (inf = netdev->net_interfaces; inf; inf = inf->next)
+ if (inf->prefer_ip6 == 0)
+ break;
+
+ grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address));
+ grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask));
+
+ if (!inf)
+ {
+ char *name = grub_xasprintf ("%s:dhcp", netdev->card_name);
+
+ net_ip.is_ip6 = 0;
+ inf = grub_efi_net_create_interface (netdev,
+ name,
+ &net_ip,
+ 1);
+ grub_free (name);
+ }
+ else
+ {
+ efi_net_interface_set_address (inf, &net_ip, 1);
+ }
+
+ grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4));
+ efi_net_interface_set_gateway (inf, &ip_addr);
+
+ dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet);
+ if (dns_address)
+ efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address);
+
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
+ int argc,
+ char **args)
+{
+ struct grub_efi_net_device *dev;
+ grub_efi_uint32_t ia_id;
+
+ for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++)
+ {
+ grub_efi_dhcp6_config_data_t config;
+ grub_efi_dhcp6_packet_option_t *option_list[1];
+ grub_efi_dhcp6_packet_option_t *opt;
+ grub_efi_status_t status;
+ grub_efi_dhcp6_mode_data_t mode;
+ grub_efi_dhcp6_retransmission_t retrans;
+ grub_efi_net_ip_manual_address_t net_ip;
+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
+ grub_efi_net_interface_t *inf = NULL;
+
+ if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0)
+ continue;
+
+ opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t));
+
+#define GRUB_EFI_DHCP6_OPT_ORO 6
+
+ opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO);
+ opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t));
+
+#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59
+#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23
+
+ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL));
+ grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t),
+ grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS));
+
+ option_list[0] = opt;
+ retrans.irt = 4;
+ retrans.mrc = 4;
+ retrans.mrt = 32;
+ retrans.mrd = 60;
+
+ config.dhcp6_callback = NULL;
+ config.callback_context = NULL;
+ config.option_count = 1;
+ config.option_list = option_list;
+ config.ia_descriptor.ia_id = ia_id;
+ config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA;
+ config.ia_info_event = NULL;
+ config.reconfigure_accept = 0;
+ config.rapid_commit = 0;
+ config.solicit_retransmission = &retrans;
+
+ status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config);
+ grub_free (opt);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("dhcp6 configure failed, %d\n", (int)status);
+ continue;
+ }
+ status = efi_call_1 (dev->dhcp6->start, dev->dhcp6);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("dhcp6 start failed, %d\n", (int)status);
+ continue;
+ }
+
+ status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
+ continue;
+ }
+
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ if (inf->prefer_ip6 == 1)
+ break;
+
+ grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address));
+ net_ip.ip6.prefix_length = 64;
+ net_ip.ip6.is_anycast = 0;
+ net_ip.is_ip6 = 1;
+
+ if (!inf)
+ {
+ char *name = grub_xasprintf ("%s:dhcp", dev->card_name);
+
+ inf = grub_efi_net_create_interface (dev,
+ name,
+ &net_ip,
+ 1);
+ grub_free (name);
+ }
+ else
+ {
+ efi_net_interface_set_address (inf, &net_ip, 1);
+ }
+
+ {
+ grub_efi_uint32_t count = 0;
+ grub_efi_dhcp6_packet_option_t **options = NULL;
+ grub_efi_uint32_t i;
+
+ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL);
+
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL && count)
+ {
+ options = grub_malloc (count * sizeof(*options));
+ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
+ }
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ if (options)
+ grub_free (options);
+ continue;
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS))
+ {
+ grub_efi_net_ip_address_t dns;
+ grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6));
+ efi_net_interface_set_dns (inf, &dns);
+ break;
+ }
+ }
+
+ if (options)
+ grub_free (options);
+ }
+
+ efi_call_1 (b->free_pool, mode.client_id);
+ efi_call_1 (b->free_pool, mode.ia);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp;
+grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6;
diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c
new file mode 100644
index 0000000..ef371d8
--- /dev/null
+++ b/grub-core/net/efi/efi_netfs.c
@@ -0,0 +1,57 @@
+#include <grub/dl.h>
+#include <grub/env.h>
+#define EFI_NET_CMD_PREFIX "net_efi"
+#include <grub/net/efi.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_command_t cmd_efi_lsroutes;
+static grub_command_t cmd_efi_lscards;
+static grub_command_t cmd_efi_lsaddrs;
+static grub_command_t cmd_efi_addaddr;
+static grub_command_t cmd_efi_bootp;
+static grub_command_t cmd_efi_bootp6;
+
+static int initialized;
+
+GRUB_MOD_INIT(efi_netfs)
+{
+ if (grub_net_open)
+ return;
+
+ if (grub_efi_net_fs_init ())
+ {
+ cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes,
+ "", N_("list network routes"));
+ cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards,
+ "", N_("list network cards"));
+ cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs,
+ "", N_("list network addresses"));
+ cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr,
+ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
+ N_("Add a network address."));
+ cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp,
+ N_("[CARD]"),
+ N_("perform a bootp autoconfiguration"));
+ cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6,
+ N_("[CARD]"),
+ N_("perform a bootp autoconfiguration"));
+ initialized = 1;
+ }
+}
+
+GRUB_MOD_FINI(efi_netfs)
+{
+ if (initialized)
+ {
+ grub_unregister_command (cmd_efi_lsroutes);
+ grub_unregister_command (cmd_efi_lscards);
+ grub_unregister_command (cmd_efi_lsaddrs);
+ grub_unregister_command (cmd_efi_addaddr);
+ grub_unregister_command (cmd_efi_bootp);
+ grub_unregister_command (cmd_efi_bootp6);
+ grub_efi_net_fs_fini ();
+ initialized = 0;
+ return;
+ }
+}
diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
new file mode 100644
index 0000000..3f61fd2
--- /dev/null
+++ b/grub-core/net/efi/http.c
@@ -0,0 +1,419 @@
+
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/misc.h>
+#include <grub/net/efi.h>
+#include <grub/charset.h>
+
+static void
+http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
+{
+ grub_efi_http_config_data_t http_config;
+ grub_efi_httpv4_access_point_t httpv4_node;
+ grub_efi_httpv6_access_point_t httpv6_node;
+ grub_efi_status_t status;
+
+ grub_efi_http_t *http = dev->http;
+
+ grub_memset (&http_config, 0, sizeof(http_config));
+ http_config.http_version = GRUB_EFI_HTTPVERSION11;
+ http_config.timeout_millisec = 5000;
+
+ if (prefer_ip6)
+ {
+ grub_efi_uintn_t sz;
+ grub_efi_ip6_config_manual_address_t manual_address;
+
+ http_config.local_address_is_ipv6 = 1;
+ sz = sizeof (manual_address);
+ status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
+ &sz, &manual_address);
+
+ if (status == GRUB_EFI_NOT_FOUND)
+ {
+ grub_printf ("The MANUAL ADDRESS is not found\n");
+ }
+
+ /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_printf ("??? %d\n",(int) status);
+ return;
+ }
+
+ grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address));
+ httpv6_node.local_port = 0;
+ http_config.access_point.ipv6_node = &httpv6_node;
+ }
+ else
+ {
+ http_config.local_address_is_ipv6 = 0;
+ grub_memset (&httpv4_node, 0, sizeof(httpv4_node));
+ httpv4_node.use_default_address = 1;
+
+ /* Use random port here */
+ /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */
+ httpv4_node.local_port = 0;
+ http_config.access_point.ipv4_node = &httpv4_node;
+ }
+
+ status = efi_call_2 (http->configure, http, &http_config);
+
+ if (status == GRUB_EFI_ALREADY_STARTED)
+ {
+ /* XXX: This hangs HTTPS boot */
+#if 0
+ if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS)
+ {
+ grub_error (GRUB_ERR_IO, N_("couldn't reset http instance"));
+ grub_print_error ();
+ return;
+ }
+ status = efi_call_2 (http->configure, http, &http_config);
+#endif
+ return;
+ }
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status);
+ grub_print_error ();
+ return ;
+ }
+}
+
+static grub_efi_boolean_t request_callback_done;
+static grub_efi_boolean_t response_callback_done;
+
+static void
+grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)),
+ void *context __attribute__ ((unused)))
+{
+ request_callback_done = 1;
+}
+
+static void
+grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)),
+ void *context __attribute__ ((unused)))
+{
+ response_callback_done = 1;
+}
+
+static grub_err_t
+efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size)
+{
+ grub_efi_http_request_data_t request_data;
+ grub_efi_http_message_t request_message;
+ grub_efi_http_token_t request_token;
+ grub_efi_http_response_data_t response_data;
+ grub_efi_http_message_t response_message;
+ grub_efi_http_token_t response_token;
+ grub_efi_http_header_t request_headers[3];
+
+ grub_efi_status_t status;
+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
+ char *url = NULL;
+
+ request_headers[0].field_name = (grub_efi_char8_t *)"Host";
+ request_headers[0].field_value = (grub_efi_char8_t *)server;
+ request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
+ request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
+ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
+ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
+
+ {
+ grub_efi_ipv6_address_t address;
+ const char *rest;
+ grub_efi_char16_t *ucs2_url;
+ grub_size_t url_len, ucs2_url_len;
+ const char *protocol = (use_https == 1) ? "https" : "http";
+
+ if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
+ url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
+ else
+ url = grub_xasprintf ("%s://%s%s", protocol, server, name);
+
+ if (!url)
+ {
+ return grub_errno;
+ }
+
+ url_len = grub_strlen (url);
+ ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8;
+ ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0]));
+
+ if (!ucs2_url)
+ {
+ grub_free (url);
+ return grub_errno;
+ }
+
+ ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */
+ ucs2_url[ucs2_url_len] = 0;
+ grub_free (url);
+ request_data.url = ucs2_url;
+ }
+
+ request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
+
+ request_message.data.request = &request_data;
+ request_message.header_count = 3;
+ request_message.headers = request_headers;
+ request_message.body_length = 0;
+ request_message.body = NULL;
+
+ /* request token */
+ request_token.event = NULL;
+ request_token.status = GRUB_EFI_NOT_READY;
+ request_token.message = &request_message;
+
+ request_callback_done = 0;
+ status = efi_call_5 (b->create_event,
+ GRUB_EFI_EVT_NOTIFY_SIGNAL,
+ GRUB_EFI_TPL_CALLBACK,
+ grub_efi_http_request_callback,
+ NULL,
+ &request_token.event);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (request_data.url);
+ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
+ }
+
+ status = efi_call_2 (http->request, http, &request_token);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ efi_call_1 (b->close_event, request_token.event);
+ grub_free (request_data.url);
+ return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status);
+ }
+ /* TODO: Add Timeout */
+ while (!request_callback_done)
+ efi_call_1(http->poll, http);
+
+ response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS;
+ response_message.data.response = &response_data;
+ /* herader_count will be updated by the HTTP driver on response */
+ response_message.header_count = 0;
+ /* headers will be populated by the driver on response */
+ response_message.headers = NULL;
+ /* use zero BodyLength to only receive the response headers */
+ response_message.body_length = 0;
+ response_message.body = NULL;
+ response_token.event = NULL;
+
+ status = efi_call_5 (b->create_event,
+ GRUB_EFI_EVT_NOTIFY_SIGNAL,
+ GRUB_EFI_TPL_CALLBACK,
+ grub_efi_http_response_callback,
+ NULL,
+ &response_token.event);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ efi_call_1 (b->close_event, request_token.event);
+ grub_free (request_data.url);
+ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
+ }
+
+ response_token.status = GRUB_EFI_SUCCESS;
+ response_token.message = &response_message;
+
+ /* wait for HTTP response */
+ response_callback_done = 0;
+ status = efi_call_2 (http->response, http, &response_token);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ efi_call_1 (b->close_event, response_token.event);
+ efi_call_1 (b->close_event, request_token.event);
+ grub_free (request_data.url);
+ return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status);
+ }
+
+ /* TODO: Add Timeout */
+ while (!response_callback_done)
+ efi_call_1 (http->poll, http);
+
+ if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK)
+ {
+ grub_efi_http_status_code_t status_code = response_message.data.response->status_code;
+
+ if (response_message.headers)
+ efi_call_1 (b->free_pool, response_message.headers);
+ efi_call_1 (b->close_event, response_token.event);
+ efi_call_1 (b->close_event, request_token.event);
+ grub_free (request_data.url);
+ if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND)
+ {
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name);
+ }
+ else
+ {
+ return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR,
+ _("unsupported uefi http status code 0x%x"), status_code);
+ }
+ }
+
+ if (file_size)
+ {
+ int i;
+ /* parse the length of the file from the ContentLength header */
+ for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i)
+ {
+ if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length"))
+ {
+ *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10);
+ break;
+ }
+ }
+ }
+
+ if (response_message.headers)
+ efi_call_1 (b->free_pool, response_message.headers);
+ efi_call_1 (b->close_event, response_token.event);
+ efi_call_1 (b->close_event, request_token.event);
+ grub_free (request_data.url);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+efihttp_read (struct grub_efi_net_device *dev,
+ char *buf,
+ grub_size_t len)
+{
+ grub_efi_http_message_t response_message;
+ grub_efi_http_token_t response_token;
+
+ grub_efi_status_t status;
+ grub_size_t sum = 0;
+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
+ grub_efi_http_t *http = dev->http;
+
+ if (!len)
+ {
+ grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read");
+ return -1;
+ }
+
+ efi_call_5 (b->create_event,
+ GRUB_EFI_EVT_NOTIFY_SIGNAL,
+ GRUB_EFI_TPL_CALLBACK,
+ grub_efi_http_response_callback,
+ NULL,
+ &response_token.event);
+
+ while (len)
+ {
+ response_message.data.response = NULL;
+ response_message.header_count = 0;
+ response_message.headers = NULL;
+ response_message.body_length = len;
+ response_message.body = buf;
+
+ response_token.message = &response_message;
+ response_token.status = GRUB_EFI_NOT_READY;
+
+ response_callback_done = 0;
+
+ status = efi_call_2 (http->response, http, &response_token);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ efi_call_1 (b->close_event, response_token.event);
+ grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status);
+ return -1;
+ }
+
+ while (!response_callback_done)
+ efi_call_1(http->poll, http);
+
+ sum += response_message.body_length;
+ buf += response_message.body_length;
+ len -= response_message.body_length;
+ }
+
+ efi_call_1 (b->close_event, response_token.event);
+
+ return sum;
+}
+
+static grub_err_t
+grub_efihttp_open (struct grub_efi_net_device *dev,
+ int prefer_ip6 __attribute__ ((unused)),
+ grub_file_t file,
+ const char *filename __attribute__ ((unused)),
+ int type)
+{
+ grub_err_t err;
+ grub_off_t size;
+ char *buf;
+
+ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ buf = grub_malloc (size);
+ efihttp_read (dev, buf, size);
+
+ file->size = size;
+ file->data = buf;
+ file->not_easily_seekable = 0;
+ file->device->net->offset = 0;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)),
+ int prefer_ip6 __attribute__ ((unused)),
+ grub_file_t file)
+{
+ if (file->data)
+ grub_free (file->data);
+
+ file->data = 0;
+ file->offset = 0;
+ file->size = 0;
+ file->device->net->offset = 0;
+ return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)),
+ int prefer_ip6 __attribute__((unused)),
+ grub_file_t file,
+ char *buf,
+ grub_size_t len)
+{
+ grub_size_t r = len;
+
+ if (!file->data || !buf || !len)
+ return 0;
+
+ if ((file->device->net->offset + len) > file->size)
+ r = file->size - file->device->net->offset;
+
+ if (r)
+ {
+ grub_memcpy (buf, (char *)file->data + file->device->net->offset, r);
+ file->device->net->offset += r;
+ }
+
+ return r;
+}
+
+struct grub_efi_net_io io_http =
+ {
+ .configure = http_configure,
+ .open = grub_efihttp_open,
+ .read = grub_efihttp_read,
+ .close = grub_efihttp_close
+ };
diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
new file mode 100644
index 0000000..b711a5d
--- /dev/null
+++ b/grub-core/net/efi/ip4_config.c
@@ -0,0 +1,398 @@
+
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/misc.h>
+#include <grub/net/efi.h>
+#include <grub/charset.h>
+
+char *
+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address)
+{
+ char *hw_addr, *p;
+ int sz, s;
+ int i;
+
+ sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1;
+
+ hw_addr = grub_malloc (sz);
+ if (!hw_addr)
+ return NULL;
+
+ p = hw_addr;
+ s = sz;
+ for (i = 0; i < (int)hw_address_size; i++)
+ {
+ grub_snprintf (p, sz, "%02x:", hw_address[i]);
+ p += sizeof ("XX:") - 1;
+ s -= sizeof ("XX:") - 1;
+ }
+
+ hw_addr[sz - 2] = '\0';
+ return hw_addr;
+}
+
+char *
+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address)
+{
+ char *addr;
+
+ addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX"));
+ if (!addr)
+ return NULL;
+
+ /* FIXME: Use grub_xasprintf ? */
+ grub_snprintf (addr,
+ sizeof ("XXX.XXX.XXX.XXX"),
+ "%u.%u.%u.%u",
+ (*address)[0],
+ (*address)[1],
+ (*address)[2],
+ (*address)[3]);
+
+ return addr;
+}
+
+int
+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
+{
+ grub_uint32_t newip = 0;
+ int i;
+ const char *ptr = val;
+
+ for (i = 0; i < 4; i++)
+ {
+ unsigned long t;
+ t = grub_strtoul (ptr, (char **) &ptr, 0);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (*ptr != '.' && i == 0)
+ {
+ /* XXX: t is in host byte order */
+ newip = t;
+ break;
+ }
+ if (t & ~0xff)
+ return 0;
+ newip <<= 8;
+ newip |= t;
+ if (i != 3 && *ptr != '.')
+ return 0;
+ ptr++;
+ }
+
+ newip = grub_cpu_to_be32 (newip);
+
+ grub_memcpy (address, &newip, sizeof(*address));
+
+ if (rest)
+ *rest = (ptr - 1);
+ return 1;
+}
+
+static grub_efi_ip4_config2_interface_info_t *
+efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config)
+{
+ grub_efi_uintn_t sz;
+ grub_efi_status_t status;
+ grub_efi_ip4_config2_interface_info_t *interface_info;
+
+ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
+ interface_info = grub_malloc (sz);
+ if (!interface_info)
+ return NULL;
+
+ status = efi_call_4 (ip4_config->get_data, ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
+ &sz, interface_info);
+
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL)
+ {
+ grub_free (interface_info);
+ interface_info = grub_malloc (sz);
+ status = efi_call_4 (ip4_config->get_data, ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
+ &sz, interface_info);
+ }
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (interface_info);
+ return NULL;
+ }
+
+ return interface_info;
+}
+
+static grub_efi_ip4_config2_manual_address_t *
+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
+{
+ grub_efi_uintn_t sz;
+ grub_efi_status_t status;
+ grub_efi_ip4_config2_manual_address_t *manual_address;
+
+ sz = sizeof (*manual_address);
+ manual_address = grub_malloc (sz);
+ if (!manual_address)
+ return NULL;
+
+ status = efi_call_4 (ip4_config->get_data, ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ &sz, manual_address);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (manual_address);
+ return NULL;
+ }
+
+ return manual_address;
+}
+
+char *
+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip4_config2_interface_info_t *interface_info;
+ char *name;
+
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config);
+
+ if (!interface_info)
+ return NULL;
+
+ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
+ * GRUB_MAX_UTF8_PER_UTF16 + 1);
+ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
+ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
+ grub_free (interface_info);
+ return name;
+}
+
+static char *
+grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip4_config2_interface_info_t *interface_info;
+ char *hw_addr;
+
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config);
+
+ if (!interface_info)
+ return NULL;
+
+ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
+ grub_free (interface_info);
+
+ return hw_addr;
+}
+
+static char *
+grub_efi_ip4_interface_address (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip4_config2_manual_address_t *manual_address;
+ char *addr;
+
+ manual_address = efi_ip4_config_manual_address (dev->ip4_config);
+
+ if (!manual_address)
+ return NULL;
+
+ addr = grub_efi_ip4_address_to_string (&manual_address->address);
+ grub_free (manual_address);
+ return addr;
+}
+
+
+static int
+address_mask_size (grub_efi_ipv4_address_t *address)
+{
+ grub_uint8_t i;
+ grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address));
+
+ if (u32_addr == 0)
+ return 0;
+
+ for (i = 0; i < 32 ; ++i)
+ {
+ if (u32_addr == ((0xffffffff >> i) << i))
+ return (32 - i);
+ }
+
+ return -1;
+}
+
+static char **
+grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip4_config2_interface_info_t *interface_info;
+ char **ret;
+ int i, id;
+
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config);
+ if (!interface_info)
+ return NULL;
+
+ ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1));
+
+ if (!ret)
+ {
+ grub_free (interface_info);
+ return NULL;
+ }
+
+ id = 0;
+ for (i = 0; i < (int)interface_info->route_table_size; i++)
+ {
+ char *subnet, *gateway, *mask;
+ grub_uint32_t u32_subnet, u32_gateway;
+ int mask_size;
+ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
+ grub_efi_net_interface_t *inf;
+ char *interface_name = NULL;
+
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ if (!inf->prefer_ip6)
+ interface_name = inf->name;
+
+ u32_gateway = grub_get_unaligned32 (&route_table->gateway_address);
+ gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address);
+ u32_subnet = grub_get_unaligned32 (&route_table->subnet_address);
+ subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address);
+ mask_size = address_mask_size (&route_table->subnet_mask);
+ mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask);
+ if (u32_subnet && !u32_gateway && interface_name)
+ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name);
+ else if (u32_subnet && u32_gateway)
+ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
+ else if (!u32_subnet && u32_gateway)
+ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
+ grub_free (subnet);
+ grub_free (gateway);
+ grub_free (mask);
+ }
+
+ ret[id] = NULL;
+ grub_free (interface_info);
+ return ret;
+}
+
+static grub_efi_net_interface_t *
+grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
+{
+ grub_efi_ip4_config2_interface_info_t *interface_info;
+ grub_efi_net_interface_t *inf;
+ int i;
+ grub_efi_ipv4_address_t *address = &ip_address->ip4;
+
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config);
+ if (!interface_info)
+ return NULL;
+
+ for (i = 0; i < (int)interface_info->route_table_size; i++)
+ {
+ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
+ grub_uint32_t u32_address, u32_mask, u32_subnet;
+
+ u32_address = grub_get_unaligned32 (address);
+ u32_subnet = grub_get_unaligned32 (route_table->subnet_address);
+ u32_mask = grub_get_unaligned32 (route_table->subnet_mask);
+
+ /* SKIP Default GATEWAY */
+ if (!u32_subnet && !u32_mask)
+ continue;
+
+ if ((u32_address & u32_mask) == u32_subnet)
+ {
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ if (!inf->prefer_ip6)
+ {
+ grub_free (interface_info);
+ return inf;
+ }
+ }
+ }
+
+ grub_free (interface_info);
+ return NULL;
+}
+
+static int
+grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev,
+ grub_efi_net_ip_manual_address_t *net_ip,
+ int with_subnet)
+{
+ grub_efi_status_t status;
+ grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4;
+
+ if (!with_subnet)
+ {
+ grub_efi_ip4_config2_manual_address_t *manual_address =
+ efi_ip4_config_manual_address (dev->ip4_config);
+
+ if (manual_address)
+ {
+ grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask));
+ grub_free (manual_address);
+ }
+ else
+ {
+ /* XXX: */
+ address->subnet_mask[0] = 0xff;
+ address->subnet_mask[1] = 0xff;
+ address->subnet_mask[2] = 0xff;
+ address->subnet_mask[3] = 0;
+ }
+ }
+
+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ sizeof(*address), address);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+
+ return 1;
+}
+
+static int
+grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev,
+ grub_efi_net_ip_address_t *address)
+{
+ grub_efi_status_t status;
+
+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
+ sizeof (address->ip4), &address->ip4);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+ return 1;
+}
+
+/* FIXME: Multiple DNS */
+static int
+grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev,
+ grub_efi_net_ip_address_t *address)
+{
+ grub_efi_status_t status;
+
+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+ sizeof (address->ip4), &address->ip4);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+ return 1;
+}
+
+grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t)
+ {
+ .get_hw_address = grub_efi_ip4_interface_hw_address,
+ .get_address = grub_efi_ip4_interface_address,
+ .get_route_table = grub_efi_ip4_interface_route_table,
+ .best_interface = grub_efi_ip4_interface_match,
+ .set_address = grub_efi_ip4_interface_set_manual_address,
+ .set_gateway = grub_efi_ip4_interface_set_gateway,
+ .set_dns = grub_efi_ip4_interface_set_dns
+ };
diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
new file mode 100644
index 0000000..017c4d0
--- /dev/null
+++ b/grub-core/net/efi/ip6_config.c
@@ -0,0 +1,422 @@
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/misc.h>
+#include <grub/net/efi.h>
+#include <grub/charset.h>
+
+char *
+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address)
+{
+ char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"));
+ char *p;
+ int i;
+ int squash;
+
+ if (!str)
+ return NULL;
+
+ p = str;
+ squash = 0;
+ for (i = 0; i < 8; ++i)
+ {
+ grub_uint16_t addr;
+
+ if (i == 7)
+ squash = 2;
+
+ addr = grub_get_unaligned16 (address->addr + i * 2);
+
+ if (grub_be_to_cpu16 (addr))
+ {
+ char buf[sizeof ("XXXX")];
+ if (i > 0)
+ *p++ = ':';
+ grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr));
+ grub_strcpy (p, buf);
+ p += grub_strlen (buf);
+
+ if (squash == 1)
+ squash = 2;
+ }
+ else
+ {
+ if (squash == 0)
+ {
+ *p++ = ':';
+ squash = 1;
+ }
+ else if (squash == 2)
+ {
+ *p++ = ':';
+ *p++ = '0';
+ }
+ }
+ }
+ *p = '\0';
+ return str;
+}
+
+int
+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest)
+{
+ grub_uint16_t newip[8];
+ const char *ptr = val;
+ int word, quaddot = -1;
+ int bracketed = 0;
+
+ if (ptr[0] == '[') {
+ bracketed = 1;
+ ptr++;
+ }
+
+ if (ptr[0] == ':' && ptr[1] != ':')
+ return 0;
+ if (ptr[0] == ':')
+ ptr++;
+
+ for (word = 0; word < 8; word++)
+ {
+ unsigned long t;
+ if (*ptr == ':')
+ {
+ quaddot = word;
+ word--;
+ ptr++;
+ continue;
+ }
+ t = grub_strtoul (ptr, (char **) &ptr, 16);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ break;
+ }
+ if (t & ~0xffff)
+ return 0;
+ newip[word] = grub_cpu_to_be16 (t);
+ if (*ptr != ':')
+ break;
+ ptr++;
+ }
+ if (quaddot == -1 && word < 7)
+ return 0;
+ if (quaddot != -1)
+ {
+ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
+ (word - quaddot + 1) * sizeof (newip[0]));
+ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
+ }
+ grub_memcpy (address, newip, 16);
+ if (bracketed && *ptr == ']') {
+ ptr++;
+ }
+ if (rest)
+ *rest = ptr;
+ return 1;
+}
+
+static grub_efi_ip6_config_interface_info_t *
+efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config)
+{
+ grub_efi_uintn_t sz;
+ grub_efi_status_t status;
+ grub_efi_ip6_config_interface_info_t *interface_info;
+
+ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
+ interface_info = grub_malloc (sz);
+
+ status = efi_call_4 (ip6_config->get_data, ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
+ &sz, interface_info);
+
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL)
+ {
+ grub_free (interface_info);
+ interface_info = grub_malloc (sz);
+ status = efi_call_4 (ip6_config->get_data, ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
+ &sz, interface_info);
+ }
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (interface_info);
+ return NULL;
+ }
+
+ return interface_info;
+}
+
+static grub_efi_ip6_config_manual_address_t *
+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
+{
+ grub_efi_uintn_t sz;
+ grub_efi_status_t status;
+ grub_efi_ip6_config_manual_address_t *manual_address;
+
+ sz = sizeof (*manual_address);
+ manual_address = grub_malloc (sz);
+ if (!manual_address)
+ return NULL;
+
+ status = efi_call_4 (ip6_config->get_data, ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
+ &sz, manual_address);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (manual_address);
+ return NULL;
+ }
+
+ return manual_address;
+}
+
+char *
+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip6_config_interface_info_t *interface_info;
+ char *name;
+
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config);
+
+ if (!interface_info)
+ return NULL;
+
+ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
+ * GRUB_MAX_UTF8_PER_UTF16 + 1);
+ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
+ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
+ grub_free (interface_info);
+ return name;
+}
+
+static char *
+grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip6_config_interface_info_t *interface_info;
+ char *hw_addr;
+
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config);
+
+ if (!interface_info)
+ return NULL;
+
+ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
+ grub_free (interface_info);
+
+ return hw_addr;
+}
+
+static char *
+grub_efi_ip6_interface_address (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip6_config_manual_address_t *manual_address;
+ char *addr;
+
+ manual_address = efi_ip6_config_manual_address (dev->ip6_config);
+
+ if (!manual_address)
+ return NULL;
+
+ addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address);
+ grub_free (manual_address);
+ return addr;
+}
+
+static char **
+grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
+{
+ grub_efi_ip6_config_interface_info_t *interface_info;
+ char **ret;
+ int i, id;
+
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config);
+ if (!interface_info)
+ return NULL;
+
+ ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1));
+
+ if (!ret)
+ {
+ grub_free (interface_info);
+ return NULL;
+ }
+
+ id = 0;
+ for (i = 0; i < (int)interface_info->route_count ; i++)
+ {
+ char *gateway, *destination;
+ grub_uint64_t u64_gateway[2];
+ grub_uint64_t u64_destination[2];
+ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
+ grub_efi_net_interface_t *inf;
+ char *interface_name = NULL;
+
+ gateway = grub_efi_ip6_address_to_string (&route_table->gateway);
+ destination = grub_efi_ip6_address_to_string (&route_table->destination);
+
+ u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr);
+ u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8);
+ u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr);
+ u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
+
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ if (inf->prefer_ip6)
+ interface_name = inf->name;
+
+ if ((!u64_gateway[0] && !u64_gateway[1])
+ && (u64_destination[0] || u64_destination[1]))
+ {
+ if (interface_name)
+ {
+ if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL)
+ && (!u64_destination[1])
+ && (route_table->prefix_length == 64))
+ ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
+ else
+ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
+ }
+ }
+ else if ((u64_gateway[0] || u64_gateway[1])
+ && (u64_destination[0] || u64_destination[1]))
+ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
+ else if ((u64_gateway[0] || u64_gateway[1])
+ && (!u64_destination[0] && !u64_destination[1]))
+ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
+
+ grub_free (gateway);
+ grub_free (destination);
+ }
+
+ ret[id] = NULL;
+ grub_free (interface_info);
+ return ret;
+}
+
+static grub_efi_net_interface_t *
+grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
+{
+ grub_efi_ip6_config_interface_info_t *interface_info;
+ grub_efi_net_interface_t *inf;
+ int i;
+ grub_efi_ipv6_address_t *address = &ip_address->ip6;
+
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config);
+ if (!interface_info)
+ return NULL;
+
+ for (i = 0; i < (int)interface_info->route_count ; i++)
+ {
+ grub_uint64_t u64_addr[2];
+ grub_uint64_t u64_subnet[2];
+ grub_uint64_t u64_mask[2];
+
+ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
+
+ /* SKIP Default GATEWAY */
+ if (route_table->prefix_length == 0)
+ continue;
+
+ u64_addr[0] = grub_get_unaligned64 (address);
+ u64_addr[1] = grub_get_unaligned64 (address + 4);
+ u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr);
+ u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
+ u64_mask[0] = (route_table->prefix_length <= 64) ?
+ 0xffffffffffffffffULL << (64 - route_table->prefix_length) :
+ 0xffffffffffffffffULL;
+ u64_mask[1] = (route_table->prefix_length <= 64) ?
+ 0 :
+ 0xffffffffffffffffULL << (128 - route_table->prefix_length);
+
+ if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0])
+ && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1]))
+ {
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ if (inf->prefer_ip6)
+ {
+ grub_free (interface_info);
+ return inf;
+ }
+ }
+ }
+
+ grub_free (interface_info);
+ return NULL;
+}
+
+static int
+grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev,
+ grub_efi_net_ip_manual_address_t *net_ip,
+ int with_subnet)
+{
+ grub_efi_status_t status;
+ grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6;
+
+ if (!with_subnet)
+ {
+ grub_efi_ip6_config_manual_address_t *manual_address =
+ efi_ip6_config_manual_address (dev->ip6_config);
+
+ if (manual_address)
+ {
+ address->prefix_length = manual_address->prefix_length;
+ grub_free (manual_address);
+ }
+ else
+ {
+ /* XXX: */
+ address->prefix_length = 64;
+ }
+ }
+
+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
+ sizeof(*address), address);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+
+ return 1;
+}
+
+static int
+grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev,
+ grub_efi_net_ip_address_t *address)
+{
+ grub_efi_status_t status;
+
+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
+ sizeof (address->ip6), &address->ip6);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+ return 1;
+}
+
+static int
+grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev,
+ grub_efi_net_ip_address_t *address)
+{
+
+ grub_efi_status_t status;
+
+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
+ sizeof (address->ip6), &address->ip6);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+ return 1;
+}
+
+grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t)
+ {
+ .get_hw_address = grub_efi_ip6_interface_hw_address,
+ .get_address = grub_efi_ip6_interface_address,
+ .get_route_table = grub_efi_ip6_interface_route_table,
+ .best_interface = grub_efi_ip6_interface_match,
+ .set_address = grub_efi_ip6_interface_set_manual_address,
+ .set_gateway = grub_efi_ip6_interface_set_gateway,
+ .set_dns = grub_efi_ip6_interface_set_dns
+ };
diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
new file mode 100644
index 0000000..86bce65
--- /dev/null
+++ b/grub-core/net/efi/net.c
@@ -0,0 +1,1428 @@
+#include <grub/net.h>
+#include <grub/env.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/i18n.h>
+#include <grub/bufio.h>
+#include <grub/efi/http.h>
+#include <grub/efi/dhcp.h>
+#include <grub/net/efi.h>
+#include <grub/charset.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define GRUB_EFI_IP6_PREFIX_LENGTH 64
+
+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
+static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
+static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID;
+static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
+static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
+static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID;
+static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
+static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID;
+
+struct grub_efi_net_device *net_devices;
+
+static char *default_server;
+static grub_efi_net_interface_t *net_interface;
+static grub_efi_net_interface_t *net_default_interface;
+
+#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6)
+#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type)
+#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz)
+#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file)
+#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__)
+
+static grub_efi_handle_t
+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
+ grub_efi_device_path_t **r_device_path)
+{
+ grub_efi_handle_t handle;
+ grub_efi_status_t status;
+
+ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
+ protocol, &device_path, &handle);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+
+ if (r_device_path)
+ *r_device_path = device_path;
+
+ return handle;
+}
+
+static int
+url_parse_fields (const char *url, char **proto, char **host, char **path)
+{
+ const char *p, *ps;
+ grub_size_t l;
+
+ *proto = *host = *path = NULL;
+ ps = p = url;
+
+ while ((p = grub_strchr (p, ':')))
+ {
+ if (grub_strlen (p) < sizeof ("://") - 1)
+ break;
+ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
+ {
+ l = p - ps;
+ *proto = grub_malloc (l + 1);
+ if (!*proto)
+ {
+ grub_print_error ();
+ return 0;
+ }
+
+ grub_memcpy (*proto, ps, l);
+ (*proto)[l] = '\0';
+ p += sizeof ("://") - 1;
+ break;
+ }
+ ++p;
+ }
+
+ if (!*proto)
+ {
+ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
+ return 0;
+ }
+
+ ps = p;
+ p = grub_strchr (p, '/');
+
+ if (!p)
+ {
+ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
+ grub_free (*proto);
+ *proto = NULL;
+ return 0;
+ }
+
+ l = p - ps;
+
+ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
+ {
+ *host = grub_malloc (l - 1);
+ if (!*host)
+ {
+ grub_print_error ();
+ grub_free (*proto);
+ *proto = NULL;
+ return 0;
+ }
+ grub_memcpy (*host, ps + 1, l - 2);
+ (*host)[l - 2] = 0;
+ }
+ else
+ {
+ *host = grub_malloc (l + 1);
+ if (!*host)
+ {
+ grub_print_error ();
+ grub_free (*proto);
+ *proto = NULL;
+ return 0;
+ }
+ grub_memcpy (*host, ps, l);
+ (*host)[l] = 0;
+ }
+
+ *path = grub_strdup (p);
+ if (!*path)
+ {
+ grub_print_error ();
+ grub_free (*host);
+ grub_free (*proto);
+ *host = NULL;
+ *proto = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+static void
+url_get_boot_location (const char *url, char **device, char **path, int is_default)
+{
+ char *protocol, *server, *file;
+ char *slash;
+
+ if (!url_parse_fields (url, &protocol, &server, &file))
+ return;
+
+ if ((slash = grub_strrchr (file, '/')))
+ *slash = 0;
+ else
+ *file = 0;
+
+ *device = grub_xasprintf ("%s,%s", protocol, server);
+ *path = grub_strdup(file);
+
+ if (is_default)
+ default_server = server;
+ else
+ grub_free (server);
+
+ grub_free (protocol);
+ grub_free (file);
+}
+
+static void
+pxe_get_boot_location (const struct grub_net_bootp_packet *bp,
+ char **device,
+ char **path,
+ int is_default)
+{
+ char *server = grub_xasprintf ("%d.%d.%d.%d",
+ ((grub_uint8_t *) &bp->server_ip)[0],
+ ((grub_uint8_t *) &bp->server_ip)[1],
+ ((grub_uint8_t *) &bp->server_ip)[2],
+ ((grub_uint8_t *) &bp->server_ip)[3]);
+
+ *device = grub_xasprintf ("tftp,%s", server);
+
+ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
+
+ if (*path)
+ {
+ char *slash;
+ slash = grub_strrchr (*path, '/');
+ if (slash)
+ *slash = 0;
+ else
+ **path = 0;
+ }
+
+ if (is_default)
+ default_server = server;
+ else
+ grub_free (server);
+}
+
+static void
+pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp,
+ grub_size_t dhcp_size,
+ char **device,
+ char **path)
+{
+
+ struct grub_net_dhcp6_option *dhcp_opt;
+ grub_size_t dhcp_remain_size;
+ *device = *path = 0;
+
+ if (dhcp_size < sizeof (*dp))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
+ return;
+ }
+
+ dhcp_remain_size = dhcp_size - sizeof (*dp);
+ dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options;
+
+ while (dhcp_remain_size)
+ {
+ grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code);
+ grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len);
+ grub_uint16_t option_size = sizeof (*dhcp_opt) + len;
+
+ if (dhcp_remain_size < option_size || code == 0)
+ break;
+
+ if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)
+ {
+ char *url = grub_malloc (len + 1);
+
+ grub_memcpy (url, dhcp_opt->data, len);
+ url[len] = 0;
+
+ url_get_boot_location ((const char *)url, device, path, 1);
+ grub_free (url);
+ break;
+ }
+
+ dhcp_remain_size -= option_size;
+ dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size);
+ }
+}
+
+static grub_efi_net_interface_t *
+grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp,
+ struct grub_efi_net_device *netdev,
+ char **device,
+ char **path)
+{
+ grub_efi_net_interface_t *inf = NULL;
+
+ while (1)
+ {
+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
+
+ if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
+ {
+ if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
+ {
+ grub_efi_uri_device_path_t *uri_dp;
+ uri_dp = (grub_efi_uri_device_path_t *) dp;
+ /* Beware that uri_dp->uri may not be null terminated */
+ url_get_boot_location ((const char *)uri_dp->uri, device, path, 1);
+ }
+ else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
+ {
+ grub_efi_net_ip_manual_address_t net_ip;
+ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp;
+
+ if (inf)
+ continue;
+ grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address));
+ grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask));
+ net_ip.is_ip6 = 0;
+ inf = grub_efi_net_create_interface (netdev,
+ netdev->card_name,
+ &net_ip,
+ 1);
+ }
+ else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
+ {
+ grub_efi_net_ip_manual_address_t net_ip;
+ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp;
+
+ if (inf)
+ continue;
+ grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address));
+ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
+ net_ip.ip6.is_anycast = 0;
+ net_ip.is_ip6 = 1;
+ inf = grub_efi_net_create_interface (netdev,
+ netdev->card_name,
+ &net_ip,
+ 1);
+ }
+ }
+
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
+ break;
+ dp = (grub_efi_device_path_t *) ((char *) dp + len);
+ }
+
+ return inf;
+}
+
+static grub_efi_net_interface_t *
+grub_efi_net_config_from_handle (grub_efi_handle_t *hnd,
+ struct grub_efi_net_device *netdev,
+ char **device,
+ char **path)
+{
+ grub_efi_pxe_t *pxe = NULL;
+
+ if (hnd == netdev->ip4_pxe_handle)
+ pxe = netdev->ip4_pxe;
+ else if (hnd == netdev->ip6_pxe_handle)
+ pxe = netdev->ip6_pxe;
+
+ if (!pxe)
+ return (grub_efi_net_config_from_device_path (
+ grub_efi_get_device_path (hnd),
+ netdev,
+ device,
+ path));
+
+ if (pxe->mode->using_ipv6)
+ {
+ grub_efi_net_ip_manual_address_t net_ip;
+
+ pxe_get_boot_location_v6 (
+ (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack,
+ sizeof (pxe->mode->dhcp_ack),
+ device,
+ path);
+
+ grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address));
+ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
+ net_ip.ip6.is_anycast = 0;
+ net_ip.is_ip6 = 1;
+ return (grub_efi_net_create_interface (netdev,
+ netdev->card_name,
+ &net_ip,
+ 1));
+ }
+ else
+ {
+ grub_efi_net_ip_manual_address_t net_ip;
+
+ pxe_get_boot_location (
+ (const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack,
+ device,
+ path,
+ 1);
+
+ grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address));
+ grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask));
+ net_ip.is_ip6 = 0;
+ return (grub_efi_net_create_interface (netdev,
+ netdev->card_name,
+ &net_ip,
+ 1));
+ }
+}
+
+static const char *
+grub_efi_net_var_get_address (struct grub_env_var *var,
+ const char *val __attribute__ ((unused)))
+{
+ struct grub_efi_net_device *dev;
+
+ for (dev = net_devices; dev; dev = dev->next)
+ {
+ grub_efi_net_interface_t *inf;
+
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ {
+ char *var_name;
+
+ var_name = grub_xasprintf ("net_%s_ip", inf->name);
+ if (grub_strcmp (var_name, var->name) == 0)
+ return efi_net_interface_get_address (inf);
+ grub_free (var_name);
+ var_name = grub_xasprintf ("net_%s_mac", inf->name);
+ if (grub_strcmp (var_name, var->name) == 0)
+ return efi_net_interface_get_hw_address (inf);
+ grub_free (var_name);
+ }
+ }
+
+ return NULL;
+}
+
+static char *
+grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ struct grub_efi_net_device *dev;
+ grub_efi_net_interface_t *inf;
+
+ for (dev = net_devices; dev; dev = dev->next)
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ if (grub_strcmp (inf->name, val) == 0)
+ {
+ net_default_interface = inf;
+ return grub_strdup (val);
+ }
+
+ return NULL;
+}
+
+static char *
+grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ grub_free (default_server);
+ default_server = grub_strdup (val);
+ return grub_strdup (val);
+}
+
+static const char *
+grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val __attribute__ ((unused)))
+{
+ return default_server ? : "";
+}
+
+static const char *
+grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val __attribute__ ((unused)))
+{
+ const char *intf = grub_env_get ("net_default_interface");
+ const char *ret = NULL;
+ if (intf)
+ {
+ char *buf = grub_xasprintf ("net_%s_ip", intf);
+ if (buf)
+ ret = grub_env_get (buf);
+ grub_free (buf);
+ }
+ return ret;
+}
+
+static const char *
+grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val __attribute__ ((unused)))
+{
+ const char *intf = grub_env_get ("net_default_interface");
+ const char *ret = NULL;
+ if (intf)
+ {
+ char *buf = grub_xasprintf ("net_%s_mac", intf);
+ if (buf)
+ ret = grub_env_get (buf);
+ grub_free (buf);
+ }
+ return ret;
+}
+
+static void
+grub_efi_net_export_interface_vars (void)
+{
+ struct grub_efi_net_device *dev;
+
+ for (dev = net_devices; dev; dev = dev->next)
+ {
+ grub_efi_net_interface_t *inf;
+
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ {
+ char *var;
+
+ var = grub_xasprintf ("net_%s_ip", inf->name);
+ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
+ grub_env_export (var);
+ grub_free (var);
+ var = grub_xasprintf ("net_%s_mac", inf->name);
+ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
+ grub_env_export (var);
+ grub_free (var);
+ }
+ }
+}
+
+static void
+grub_efi_net_unset_interface_vars (void)
+{
+ struct grub_efi_net_device *dev;
+
+ for (dev = net_devices; dev; dev = dev->next)
+ {
+ grub_efi_net_interface_t *inf;
+
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ {
+ char *var;
+
+ var = grub_xasprintf ("net_%s_ip", inf->name);
+ grub_register_variable_hook (var, 0, 0);
+ grub_env_unset (var);
+ grub_free (var);
+ var = grub_xasprintf ("net_%s_mac", inf->name);
+ grub_register_variable_hook (var, 0, 0);
+ grub_env_unset (var);
+ grub_free (var);
+ }
+ }
+}
+
+grub_efi_net_interface_t *
+grub_efi_net_create_interface (struct grub_efi_net_device *dev,
+ const char *interface_name,
+ grub_efi_net_ip_manual_address_t *net_ip,
+ int has_subnet)
+{
+ grub_efi_net_interface_t *inf;
+
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ {
+ if (inf->prefer_ip6 == net_ip->is_ip6)
+ break;
+ }
+
+ if (!inf)
+ {
+ inf = grub_malloc (sizeof(*inf));
+ inf->name = grub_strdup (interface_name);
+ inf->prefer_ip6 = net_ip->is_ip6;
+ inf->dev = dev;
+ inf->next = dev->net_interfaces;
+ inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ;
+ dev->net_interfaces = inf;
+ }
+ else
+ {
+ grub_free (inf->name);
+ inf->name = grub_strdup (interface_name);
+ }
+
+ if (!efi_net_interface_set_address (inf, net_ip, has_subnet))
+ {
+ grub_error (GRUB_ERR_BUG, N_("Set Address Failed"));
+ return NULL;
+ }
+
+ return inf;
+}
+
+static void
+grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ char **path)
+{
+ grub_efi_handle_t config_hnd;
+
+ struct grub_efi_net_device *netdev;
+ grub_efi_net_interface_t *inf;
+
+ config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL);
+
+ if (!config_hnd)
+ return;
+
+ for (netdev = net_devices; netdev; netdev = netdev->next)
+ if (netdev->handle == config_hnd)
+ break;
+
+ if (!netdev)
+ return;
+
+ if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path)))
+ return;
+
+ grub_env_set ("net_default_interface", inf->name);
+ grub_efi_net_export_interface_vars ();
+}
+
+static grub_err_t
+grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)),
+ grub_fs_dir_hook_t hook __attribute__ ((unused)),
+ void *hook_data __attribute__ ((unused)))
+{
+ if (!device->net)
+ return grub_error (GRUB_ERR_BUG, "invalid net device");
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)))
+{
+ struct grub_file *file, *bufio;
+
+ file = grub_malloc (sizeof (*file));
+ if (!file)
+ return grub_errno;
+
+ grub_memcpy (file, file_out, sizeof (struct grub_file));
+ file->device->net->name = grub_strdup (name);
+
+ if (!file->device->net->name)
+ {
+ grub_free (file);
+ return grub_errno;
+ }
+
+ efi_net_interface(open, file, name);
+ grub_print_error ();
+
+ bufio = grub_bufio_open (file, 32768);
+ if (!bufio)
+ {
+ grub_free (file->device->net->name);
+ grub_free (file);
+ return grub_errno;
+ }
+ grub_memcpy (file_out, bufio, sizeof (struct grub_file));
+ grub_free (bufio);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+grub_efihttp_chunk_read (grub_file_t file, char *buf,
+ grub_size_t len, grub_size_t chunk_size)
+{
+ char *chunk = grub_malloc (chunk_size);
+ grub_size_t sum = 0;
+
+ while (len)
+ {
+ grub_ssize_t rd;
+ grub_size_t sz = (len > chunk_size) ? chunk_size : len;
+
+ rd = efi_net_interface (read, file, chunk, sz);
+
+ if (rd <= 0)
+ return rd;
+
+ if (buf)
+ {
+ grub_memcpy (buf, chunk, rd);
+ buf += rd;
+ }
+ sum += rd;
+ len -= rd;
+ }
+
+ grub_free (chunk);
+ return sum;
+}
+
+static grub_ssize_t
+grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)),
+ char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused)))
+{
+ if (file->offset > file->device->net->offset)
+ {
+ grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240);
+ }
+ else if (file->offset < file->device->net->offset)
+ {
+ efi_net_interface (close, file);
+ efi_net_interface (open, file, file->device->net->name);
+ if (file->offset)
+ grub_efihttp_chunk_read (file, NULL, file->offset, 10240);
+ }
+
+ return efi_net_interface (read, file, buf, len);
+}
+
+static grub_err_t
+grub_efi_netfs_close (grub_file_t file)
+{
+ efi_net_interface (close, file);
+ return GRUB_ERR_NONE;
+}
+
+static grub_efi_handle_t
+grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid)
+{
+ grub_efi_service_binding_t *service;
+ grub_efi_status_t status;
+ grub_efi_handle_t child_dev = NULL;
+
+ service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!service)
+ {
+ grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol"));
+ return NULL;
+ }
+
+ status = efi_call_2 (service->create_child, service, &child_dev);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status);
+ return NULL;
+ }
+
+ return child_dev;
+}
+
+static grub_err_t
+grub_efi_net_parse_address (const char *address,
+ grub_efi_ip4_config2_manual_address_t *ip4,
+ grub_efi_ip6_config_manual_address_t *ip6,
+ int *is_ip6,
+ int *has_cidr)
+{
+ const char *rest;
+
+ if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest))
+ {
+ *is_ip6 = 0;
+ if (*rest == '/')
+ {
+ grub_uint32_t subnet_mask_size;
+
+ subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0);
+
+ if (!grub_errno && subnet_mask_size <= 32 && *rest == 0)
+ {
+ grub_uint32_t subnet_mask;
+
+ subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size)));
+ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
+ if (has_cidr)
+ *has_cidr = 1;
+ return GRUB_ERR_NONE;
+ }
+ }
+ else if (*rest == 0)
+ {
+ grub_uint32_t subnet_mask = 0xffffffffU;
+ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
+ if (has_cidr)
+ *has_cidr = 0;
+ return GRUB_ERR_NONE;
+ }
+ }
+ else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest))
+ {
+ *is_ip6 = 1;
+ if (*rest == '/')
+ {
+ grub_efi_uint8_t prefix_length;
+
+ prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0);
+ if (!grub_errno && prefix_length <= 128 && *rest == 0)
+ {
+ ip6->prefix_length = prefix_length;
+ ip6->is_anycast = 0;
+ if (has_cidr)
+ *has_cidr = 1;
+ return GRUB_ERR_NONE;
+ }
+ }
+ else if (*rest == 0)
+ {
+ ip6->prefix_length = 128;
+ ip6->is_anycast = 0;
+ if (has_cidr)
+ *has_cidr = 0;
+ return GRUB_ERR_NONE;
+ }
+ }
+
+ return grub_error (GRUB_ERR_NET_BAD_ADDRESS,
+ N_("unrecognised network address `%s'"),
+ address);
+}
+
+static grub_efi_net_interface_t *
+match_route (const char *server)
+{
+ grub_err_t err;
+ grub_efi_ip4_config2_manual_address_t ip4;
+ grub_efi_ip6_config_manual_address_t ip6;
+ grub_efi_net_interface_t *inf;
+ int is_ip6 = 0;
+
+ err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0);
+
+ if (err)
+ {
+ grub_print_error ();
+ return NULL;
+ }
+
+ if (is_ip6)
+ {
+ struct grub_efi_net_device *dev;
+ grub_efi_net_ip_address_t addr;
+
+ grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address));
+
+ for (dev = net_devices; dev; dev = dev->next)
+ if ((inf = efi_net_ip6_config->best_interface (dev, &addr)))
+ return inf;
+ }
+ else
+ {
+ struct grub_efi_net_device *dev;
+ grub_efi_net_ip_address_t addr;
+
+ grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address));
+
+ for (dev = net_devices; dev; dev = dev->next)
+ if ((inf = efi_net_ip4_config->best_interface (dev, &addr)))
+ return inf;
+ }
+
+ return 0;
+}
+
+static void
+grub_efi_net_add_pxebc_to_cards (void)
+{
+ grub_efi_uintn_t num_handles;
+ grub_efi_handle_t *handles;
+ grub_efi_handle_t *handle;
+
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid,
+ 0, &num_handles);
+ if (!handles)
+ return;
+
+ for (handle = handles; num_handles--; handle++)
+ {
+ grub_efi_device_path_t *dp, *ddp, *ldp;
+ grub_efi_pxe_t *pxe;
+ struct grub_efi_net_device *d;
+ int is_ip6 = 0;
+
+ dp = grub_efi_get_device_path (*handle);
+ if (!dp)
+ continue;
+
+ ddp = grub_efi_duplicate_device_path (dp);
+ ldp = grub_efi_find_last_device_path (ddp);
+
+ if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
+ {
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ ldp->length = sizeof (*ldp);
+ }
+ else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
+ {
+ is_ip6 = 1;
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ ldp->length = sizeof (*ldp);
+ }
+
+ for (d = net_devices; d; d = d->next)
+ if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0)
+ break;
+
+ if (!d)
+ {
+ grub_free (ddp);
+ continue;
+ }
+
+ pxe = grub_efi_open_protocol (*handle, &pxe_io_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (!pxe)
+ {
+ grub_free (ddp);
+ continue;
+ }
+
+ if (is_ip6)
+ {
+ d->ip6_pxe_handle = *handle;
+ d->ip6_pxe = pxe;
+ }
+ else
+ {
+ d->ip4_pxe_handle = *handle;
+ d->ip4_pxe = pxe;
+ }
+
+ grub_free (ddp);
+ }
+
+ grub_free (handles);
+}
+
+static void
+set_ip_policy_to_static (void)
+{
+ struct grub_efi_net_device *dev;
+
+ for (dev = net_devices; dev; dev = dev->next)
+ {
+ grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC;
+
+ if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
+ sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS)
+ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name);
+
+ if (dev->ip6_config)
+ {
+ grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL;
+
+ if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
+ sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS)
+ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name);
+ }
+ }
+}
+
+/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */
+static void
+grub_efi_net_find_cards (void)
+{
+ grub_efi_uintn_t num_handles;
+ grub_efi_handle_t *handles;
+ grub_efi_handle_t *handle;
+ int id;
+
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid,
+ 0, &num_handles);
+ if (!handles)
+ return;
+
+ for (id = 0, handle = handles; num_handles--; handle++, id++)
+ {
+ grub_efi_device_path_t *dp;
+ grub_efi_ip4_config2_protocol_t *ip4_config;
+ grub_efi_ip6_config_protocol_t *ip6_config;
+ grub_efi_handle_t http_handle;
+ grub_efi_http_t *http;
+ grub_efi_handle_t dhcp4_handle;
+ grub_efi_dhcp4_protocol_t *dhcp4;
+ grub_efi_handle_t dhcp6_handle;
+ grub_efi_dhcp6_protocol_t *dhcp6;
+
+ struct grub_efi_net_device *d;
+
+ dp = grub_efi_get_device_path (*handle);
+ if (!dp)
+ continue;
+
+ ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!ip4_config)
+ continue;
+
+ ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid);
+ grub_errno = GRUB_ERR_NONE;
+ http = (http_handle)
+ ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
+ : NULL;
+
+ dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid);
+ grub_errno = GRUB_ERR_NONE;
+ dhcp4 = (dhcp4_handle)
+ ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
+ : NULL;
+
+
+ dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid);
+ grub_errno = GRUB_ERR_NONE;
+ dhcp6 = (dhcp6_handle)
+ ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
+ : NULL;
+
+ d = grub_malloc (sizeof (*d));
+ if (!d)
+ {
+ grub_free (handles);
+ while (net_devices)
+ {
+ d = net_devices->next;
+ grub_free (net_devices);
+ net_devices = d;
+ }
+ return;
+ }
+ d->handle = *handle;
+ d->ip4_config = ip4_config;
+ d->ip6_config = ip6_config;
+ d->http_handle = http_handle;
+ d->http = http;
+ d->dhcp4_handle = dhcp4_handle;
+ d->dhcp4 = dhcp4;
+ d->dhcp6_handle = dhcp6_handle;
+ d->dhcp6 = dhcp6;
+ d->next = net_devices;
+ d->card_name = grub_xasprintf ("efinet%d", id);
+ d->net_interfaces = NULL;
+ net_devices = d;
+ }
+
+ grub_efi_net_add_pxebc_to_cards ();
+ grub_free (handles);
+ set_ip_policy_to_static ();
+}
+
+static void
+listroutes_ip4 (struct grub_efi_net_device *netdev)
+{
+ char **routes;
+
+ routes = NULL;
+
+ if ((routes = efi_net_ip4_config->get_route_table (netdev)))
+ {
+ char **r;
+
+ for (r = routes; *r; ++r)
+ grub_printf ("%s\n", *r);
+ }
+
+ if (routes)
+ {
+ char **r;
+
+ for (r = routes; *r; ++r)
+ grub_free (*r);
+ grub_free (routes);
+ }
+}
+
+static void
+listroutes_ip6 (struct grub_efi_net_device *netdev)
+{
+ char **routes;
+
+ routes = NULL;
+
+ if ((routes = efi_net_ip6_config->get_route_table (netdev)))
+ {
+ char **r;
+
+ for (r = routes; *r; ++r)
+ grub_printf ("%s\n", *r);
+ }
+
+ if (routes)
+ {
+ char **r;
+
+ for (r = routes; *r; ++r)
+ grub_free (*r);
+ grub_free (routes);
+ }
+}
+
+static grub_err_t
+grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_efi_net_device *netdev;
+
+ for (netdev = net_devices; netdev; netdev = netdev->next)
+ {
+ listroutes_ip4 (netdev);
+ listroutes_ip6 (netdev);
+ }
+
+ return GRUB_ERR_NONE;
+}
+static grub_err_t
+grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_efi_net_device *dev;
+
+ for (dev = net_devices; dev; dev = dev->next)
+ {
+ char *hw_addr;
+
+ hw_addr = efi_net_ip4_config->get_hw_address (dev);
+
+ if (hw_addr)
+ {
+ grub_printf ("%s %s\n", dev->card_name, hw_addr);
+ grub_free (hw_addr);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_efi_net_device *dev;
+ grub_efi_net_interface_t *inf;
+
+ for (dev = net_devices; dev; dev = dev->next)
+ for (inf = dev->net_interfaces; inf; inf = inf->next)
+ {
+ char *hw_addr = NULL;
+ char *addr = NULL;
+
+ if ((hw_addr = efi_net_interface_get_hw_address (inf))
+ && (addr = efi_net_interface_get_address (inf)))
+ grub_printf ("%s %s %s\n", inf->name, hw_addr, addr);
+
+ if (hw_addr)
+ grub_free (hw_addr);
+ if (addr)
+ grub_free (addr);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/* FIXME: support MAC specifying. */
+static grub_err_t
+grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_efi_net_device *dev;
+ grub_err_t err;
+ grub_efi_ip4_config2_manual_address_t ip4;
+ grub_efi_ip6_config_manual_address_t ip6;
+ grub_efi_net_ip_manual_address_t net_ip;
+ int is_ip6 = 0;
+ int cidr = 0;
+
+ if (argc != 3)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected"));
+
+ for (dev = net_devices; dev; dev = dev->next)
+ {
+ if (grub_strcmp (dev->card_name, args[1]) == 0)
+ break;
+ }
+
+ if (!dev)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found"));
+
+ err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr);
+
+ if (err)
+ return err;
+
+ net_ip.is_ip6 = is_ip6;
+ if (is_ip6)
+ grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6));
+ else
+ grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4));
+
+ if (!grub_efi_net_create_interface (dev,
+ args[0],
+ &net_ip,
+ cidr))
+ return grub_errno;
+
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_fs grub_efi_netfs;
+
+static grub_net_t
+grub_net_open_real (const char *name __attribute__ ((unused)))
+{
+ grub_size_t protnamelen;
+ const char *protname, *server;
+ grub_net_t ret;
+
+ net_interface = NULL;
+
+ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
+ {
+ protname = "tftp";
+ protnamelen = sizeof ("tftp") - 1;
+ server = name + sizeof ("pxe:") - 1;
+ }
+ else if (grub_strcmp (name, "pxe") == 0)
+ {
+ protname = "tftp";
+ protnamelen = sizeof ("tftp") - 1;
+ server = default_server;
+ }
+ else
+ {
+ const char *comma;
+
+ comma = grub_strchr (name, ',');
+ if (comma)
+ {
+ protnamelen = comma - name;
+ server = comma + 1;
+ protname = name;
+ }
+ else
+ {
+ protnamelen = grub_strlen (name);
+ server = default_server;
+ protname = name;
+ }
+ }
+
+ if (!server)
+ {
+ grub_error (GRUB_ERR_NET_BAD_ADDRESS,
+ N_("no server is specified"));
+ return NULL;
+ }
+
+ /*FIXME: Use DNS translate name to address */
+ net_interface = match_route (server);
+
+ /*XXX: should we check device with default gateway ? */
+ if (!net_interface && !(net_interface = net_default_interface))
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"),
+ name);
+ return NULL;
+ }
+
+ if ((protnamelen == (sizeof ("https") - 1)
+ && grub_memcmp ("https", protname, protnamelen) == 0))
+ {
+ net_interface->io = &io_http;
+ net_interface->io_type = 1;
+ }
+ else if ((protnamelen == (sizeof ("http") - 1)
+ && grub_memcmp ("http", protname, protnamelen) == 0))
+ {
+ net_interface->io = &io_http;
+ net_interface->io_type = 0;
+ }
+ else if (protnamelen == (sizeof ("tftp") - 1)
+ && grub_memcmp ("tftp", protname, protnamelen) == 0)
+ {
+ net_interface->io = &io_pxe;
+ net_interface->io_type = 0;
+ }
+ else
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
+ name);
+ return NULL;
+ }
+
+ /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */
+ efi_net_interface (configure);
+
+ ret = grub_zalloc (sizeof (*ret));
+ if (!ret)
+ return NULL;
+
+ ret->server = grub_strdup (server);
+ if (!ret->server)
+ {
+ grub_free (ret);
+ return NULL;
+ }
+
+ ret->fs = &grub_efi_netfs;
+ return ret;
+}
+#if 0
+static grub_command_t cmd_efi_lsaddr;
+static grub_command_t cmd_efi_lscards;
+static grub_command_t cmd_efi_lsroutes;
+static grub_command_t cmd_efi_addaddr;
+#endif
+
+static struct grub_fs grub_efi_netfs =
+ {
+ .name = "efi netfs",
+ .fs_dir = grub_efi_netfs_dir,
+ .fs_open = grub_efi_netfs_open,
+ .fs_read = grub_efi_netfs_read,
+ .fs_close = grub_efi_netfs_close,
+ .fs_label = NULL,
+ .fs_uuid = NULL,
+ .fs_mtime = NULL,
+ };
+
+int
+grub_efi_net_boot_from_https (void)
+{
+ grub_efi_loaded_image_t *image = NULL;
+ grub_efi_device_path_t *dp;
+
+ image = grub_efi_get_loaded_image (grub_efi_image_handle);
+ if (!image)
+ return 0;
+
+ dp = grub_efi_get_device_path (image->device_handle);
+
+ while (1)
+ {
+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
+
+ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
+ && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ {
+ grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp;
+ return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0;
+ }
+
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
+ break;
+ dp = (grub_efi_device_path_t *) ((char *) dp + len);
+ }
+
+ return 0;
+}
+
+int
+grub_efi_net_boot_from_opa (void)
+{
+ grub_efi_loaded_image_t *image = NULL;
+ grub_efi_device_path_t *dp;
+
+ image = grub_efi_get_loaded_image (grub_efi_image_handle);
+ if (!image)
+ return 0;
+
+ dp = grub_efi_get_device_path (image->device_handle);
+
+ while (1)
+ {
+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
+
+ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
+ && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE))
+ {
+ grub_efi_mac_address_device_path_t *mac_dp = (grub_efi_mac_address_device_path_t *)dp;
+ return (mac_dp->if_type == 0xC7) ? 1 : 0;
+ }
+
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
+ break;
+ dp = (grub_efi_device_path_t *) ((char *) dp + len);
+ }
+
+ return 0;
+}
+
+static char *
+grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes;
+grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards;
+grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs;
+grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr;
+
+int
+grub_efi_net_fs_init ()
+{
+ grub_efi_net_find_cards ();
+ grub_efi_net_config = grub_efi_net_config_real;
+ grub_net_open = grub_net_open_real;
+ grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server,
+ grub_efi_net_var_set_server);
+ grub_env_export ("net_default_server");
+ grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server,
+ grub_efi_net_var_set_server);
+ grub_env_export ("pxe_default_server");
+ grub_register_variable_hook ("net_default_interface", 0,
+ grub_efi_net_var_set_interface);
+ grub_env_export ("net_default_interface");
+ grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip,
+ 0);
+ grub_env_export ("net_default_ip");
+ grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac,
+ 0);
+ grub_env_export ("net_default_mac");
+
+ grub_env_set ("grub_netfs_type", "efi");
+ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
+ grub_env_export ("grub_netfs_type");
+
+ return 1;
+}
+
+void
+grub_efi_net_fs_fini (void)
+{
+ grub_env_unset ("grub_netfs_type");
+ grub_efi_net_unset_interface_vars ();
+ grub_register_variable_hook ("net_default_server", 0, 0);
+ grub_env_unset ("net_default_server");
+ grub_register_variable_hook ("net_default_interface", 0, 0);
+ grub_env_unset ("net_default_interface");
+ grub_register_variable_hook ("pxe_default_server", 0, 0);
+ grub_env_unset ("pxe_default_server");
+ grub_register_variable_hook ("net_default_ip", 0, 0);
+ grub_env_unset ("net_default_ip");
+ grub_register_variable_hook ("net_default_mac", 0, 0);
+ grub_env_unset ("net_default_mac");
+ grub_efi_net_config = NULL;
+ grub_net_open = NULL;
+ grub_fs_unregister (&grub_efi_netfs);
+}
diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c
new file mode 100644
index 0000000..531949c
--- /dev/null
+++ b/grub-core/net/efi/pxe.c
@@ -0,0 +1,424 @@
+
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/misc.h>
+#include <grub/net/efi.h>
+#include <grub/charset.h>
+
+static grub_efi_ip6_config_manual_address_t *
+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
+{
+ grub_efi_uintn_t sz;
+ grub_efi_status_t status;
+ grub_efi_ip6_config_manual_address_t *manual_address;
+
+ sz = sizeof (*manual_address);
+ manual_address = grub_malloc (sz);
+ if (!manual_address)
+ return NULL;
+
+ status = efi_call_4 (ip6_config->get_data, ip6_config,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
+ &sz, manual_address);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (manual_address);
+ return NULL;
+ }
+
+ return manual_address;
+}
+
+static grub_efi_ip4_config2_manual_address_t *
+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
+{
+ grub_efi_uintn_t sz;
+ grub_efi_status_t status;
+ grub_efi_ip4_config2_manual_address_t *manual_address;
+
+ sz = sizeof (*manual_address);
+ manual_address = grub_malloc (sz);
+ if (!manual_address)
+ return NULL;
+
+ status = efi_call_4 (ip4_config->get_data, ip4_config,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ &sz, manual_address);
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (manual_address);
+ return NULL;
+ }
+
+ return manual_address;
+}
+
+static void
+pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6)
+{
+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
+
+ grub_efi_pxe_mode_t *mode = pxe->mode;
+
+ if (!mode->started)
+ {
+ grub_efi_status_t status;
+ status = efi_call_2 (pxe->start, pxe, prefer_ip6);
+
+ if (status != GRUB_EFI_SUCCESS)
+ grub_printf ("Couldn't start PXE\n");
+ }
+
+#if 0
+ grub_printf ("PXE STARTED: %u\n", mode->started);
+ grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6);
+#endif
+
+ if (mode->using_ipv6)
+ {
+ grub_efi_ip6_config_manual_address_t *manual_address;
+ manual_address = efi_ip6_config_manual_address (dev->ip6_config);
+
+ if (manual_address &&
+ grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0)
+ {
+ grub_efi_status_t status;
+ grub_efi_pxe_ip_address_t station_ip;
+
+ grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr));
+ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL);
+
+ if (status != GRUB_EFI_SUCCESS)
+ grub_printf ("Couldn't set station ip\n");
+
+ grub_free (manual_address);
+ }
+ }
+ else
+ {
+ grub_efi_ip4_config2_manual_address_t *manual_address;
+ manual_address = efi_ip4_config_manual_address (dev->ip4_config);
+
+ if (manual_address &&
+ grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0)
+ {
+ grub_efi_status_t status;
+ grub_efi_pxe_ip_address_t station_ip;
+ grub_efi_pxe_ip_address_t subnet_mask;
+
+ grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr));
+ grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr));
+
+ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask);
+
+ if (status != GRUB_EFI_SUCCESS)
+ grub_printf ("Couldn't set station ip\n");
+
+ grub_free (manual_address);
+ }
+ }
+
+#if 0
+ if (mode->using_ipv6)
+ {
+ grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+ mode->station_ip.v6.addr[0],
+ mode->station_ip.v6.addr[1],
+ mode->station_ip.v6.addr[2],
+ mode->station_ip.v6.addr[3],
+ mode->station_ip.v6.addr[4],
+ mode->station_ip.v6.addr[5],
+ mode->station_ip.v6.addr[6],
+ mode->station_ip.v6.addr[7],
+ mode->station_ip.v6.addr[8],
+ mode->station_ip.v6.addr[9],
+ mode->station_ip.v6.addr[10],
+ mode->station_ip.v6.addr[11],
+ mode->station_ip.v6.addr[12],
+ mode->station_ip.v6.addr[13],
+ mode->station_ip.v6.addr[14],
+ mode->station_ip.v6.addr[15]);
+ }
+ else
+ {
+ grub_printf ("PXE STATION IP: %d.%d.%d.%d\n",
+ mode->station_ip.v4.addr[0],
+ mode->station_ip.v4.addr[1],
+ mode->station_ip.v4.addr[2],
+ mode->station_ip.v4.addr[3]);
+ grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n",
+ mode->subnet_mask.v4.addr[0],
+ mode->subnet_mask.v4.addr[1],
+ mode->subnet_mask.v4.addr[2],
+ mode->subnet_mask.v4.addr[3]);
+ }
+#endif
+
+ /* TODO: Set The Station IP to the IP2 Config */
+}
+
+static int
+parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+{
+ grub_uint16_t newip[8];
+ const char *ptr = val;
+ int word, quaddot = -1;
+ int bracketed = 0;
+
+ if (ptr[0] == '[') {
+ bracketed = 1;
+ ptr++;
+ }
+
+ if (ptr[0] == ':' && ptr[1] != ':')
+ return 0;
+ if (ptr[0] == ':')
+ ptr++;
+
+ for (word = 0; word < 8; word++)
+ {
+ unsigned long t;
+ if (*ptr == ':')
+ {
+ quaddot = word;
+ word--;
+ ptr++;
+ continue;
+ }
+ t = grub_strtoul (ptr, (char **) &ptr, 16);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ break;
+ }
+ if (t & ~0xffff)
+ return 0;
+ newip[word] = grub_cpu_to_be16 (t);
+ if (*ptr != ':')
+ break;
+ ptr++;
+ }
+ if (quaddot == -1 && word < 7)
+ return 0;
+ if (quaddot != -1)
+ {
+ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
+ (word - quaddot + 1) * sizeof (newip[0]));
+ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
+ }
+ grub_memcpy (ip, newip, 16);
+ if (bracketed && *ptr == ']') {
+ ptr++;
+ }
+ if (rest)
+ *rest = ptr;
+ return 1;
+}
+
+static grub_err_t
+pxe_open (struct grub_efi_net_device *dev,
+ int prefer_ip6,
+ grub_file_t file,
+ const char *filename,
+ int type __attribute__((unused)))
+{
+ int i;
+ char *p;
+ grub_efi_status_t status;
+ grub_efi_pxe_ip_address_t server_ip;
+ grub_efi_uint64_t file_size = 0;
+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
+
+ if (pxe->mode->using_ipv6)
+ {
+ const char *rest;
+ grub_uint64_t ip6[2];
+ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
+ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
+ /* TODO: ERROR Handling Here */
+#if 0
+ grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+ server_ip.v6.addr[0],
+ server_ip.v6.addr[1],
+ server_ip.v6.addr[2],
+ server_ip.v6.addr[3],
+ server_ip.v6.addr[4],
+ server_ip.v6.addr[5],
+ server_ip.v6.addr[6],
+ server_ip.v6.addr[7],
+ server_ip.v6.addr[8],
+ server_ip.v6.addr[9],
+ server_ip.v6.addr[10],
+ server_ip.v6.addr[11],
+ server_ip.v6.addr[12],
+ server_ip.v6.addr[13],
+ server_ip.v6.addr[14],
+ server_ip.v6.addr[15]);
+#endif
+ }
+ else
+ {
+ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
+ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
+ }
+
+ status = efi_call_10 (pxe->mtftp,
+ pxe,
+ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ NULL,
+ 0,
+ &file_size,
+ NULL,
+ &server_ip,
+ (grub_efi_char8_t *)filename,
+ NULL,
+ 0);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return grub_error (GRUB_ERR_IO, "Couldn't get file size");
+
+ file->size = (grub_off_t)file_size;
+ file->not_easily_seekable = 0;
+ file->data = 0;
+ file->device->net->offset = 0;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+pxe_close (struct grub_efi_net_device *dev __attribute__((unused)),
+ int prefer_ip6 __attribute__((unused)),
+ grub_file_t file __attribute__((unused)))
+{
+ file->offset = 0;
+ file->size = 0;
+ file->device->net->offset = 0;
+
+ if (file->data)
+ {
+ grub_free (file->data);
+ file->data = NULL;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+pxe_read (struct grub_efi_net_device *dev,
+ int prefer_ip6,
+ grub_file_t file,
+ char *buf,
+ grub_size_t len)
+{
+ int i;
+ char *p;
+ grub_efi_status_t status;
+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
+ grub_efi_uint64_t bufsz = len;
+ grub_efi_pxe_ip_address_t server_ip;
+ char *buf2 = NULL;
+
+ if (file->data)
+ {
+ /* TODO: RANGE Check for offset and file size */
+ grub_memcpy (buf, (char*)file->data + file->device->net->offset, len);
+ file->device->net->offset += len;
+ return len;
+ }
+
+ if (file->device->net->offset)
+ {
+ grub_error (GRUB_ERR_BUG, "No Offet Read Possible");
+ grub_print_error ();
+ return 0;
+ }
+
+ if (pxe->mode->using_ipv6)
+ {
+ const char *rest;
+ grub_uint64_t ip6[2];
+ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
+ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
+ /* TODO: ERROR Handling Here */
+ }
+ else
+ {
+ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
+ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
+ }
+
+ status = efi_call_10 (pxe->mtftp,
+ pxe,
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ buf,
+ 0,
+ &bufsz,
+ NULL,
+ &server_ip,
+ (grub_efi_char8_t *)file->device->net->name,
+ NULL,
+ 0);
+
+ if (bufsz != file->size)
+ {
+ grub_error (GRUB_ERR_BUG, "Short read should not happen here");
+ grub_print_error ();
+ return 0;
+ }
+
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL)
+ {
+
+ buf2 = grub_malloc (bufsz);
+
+ if (!buf2)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY");
+ grub_print_error ();
+ return 0;
+ }
+
+ status = efi_call_10 (pxe->mtftp,
+ pxe,
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ buf2,
+ 0,
+ &bufsz,
+ NULL,
+ &server_ip,
+ (grub_efi_char8_t *)file->device->net->name,
+ NULL,
+ 0);
+ }
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ if (buf2)
+ grub_free (buf2);
+
+ grub_error (GRUB_ERR_IO, "Failed to Read File");
+ grub_print_error ();
+ return 0;
+ }
+
+ if (buf2)
+ grub_memcpy (buf, buf2, len);
+
+ file->device->net->offset = len;
+
+ if (buf2)
+ file->data = buf2;
+
+ return len;
+}
+
+struct grub_efi_net_io io_pxe =
+ {
+ .configure = pxe_configure,
+ .open = pxe_open,
+ .read = pxe_read,
+ .close = pxe_close
+ };
+
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 2734f70..27a0a1d 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -32,6 +32,9 @@
#include <grub/loader.h>
#include <grub/bufio.h>
#include <grub/kernel.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/net/efi.h>
+#endif
GRUB_MOD_LICENSE ("GPLv3+");
@@ -2025,8 +2028,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
static grub_command_t cmd_lsroutes, cmd_lscards;
static grub_command_t cmd_lsaddr, cmd_slaac;
+#ifdef GRUB_MACHINE_EFI
+
+static enum {
+ INIT_MODE_NONE,
+ INIT_MODE_GRUB,
+ INIT_MODE_EFI
+} init_mode;
+
+static grub_command_t cmd_bootp, cmd_bootp6;
+
+#endif
+
GRUB_MOD_INIT(net)
{
+#ifdef GRUB_MACHINE_EFI
+ if (grub_net_open)
+ return;
+
+ if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ())
+ && grub_efi_net_fs_init ())
+ {
+ cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes,
+ "", N_("list network routes"));
+ cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards,
+ "", N_("list network cards"));
+ cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs,
+ "", N_("list network addresses"));
+ cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr,
+ /* TRANSLATORS: HWADDRESS stands for
+ "hardware address". */
+ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
+ N_("Add a network address."));
+ cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp,
+ N_("[CARD]"),
+ N_("perform a bootp autoconfiguration"));
+ cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6,
+ N_("[CARD]"),
+ N_("perform a bootp autoconfiguration"));
+ init_mode = INIT_MODE_EFI;
+ return;
+ }
+#endif
+
grub_register_variable_hook ("net_default_server", defserver_get_env,
defserver_set_env);
grub_env_export ("net_default_server");
@@ -2074,10 +2118,37 @@ GRUB_MOD_INIT(net)
grub_net_restore_hw,
GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
+
+#ifdef GRUB_MACHINE_EFI
+ grub_env_set ("grub_netfs_type", "grub");
+ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
+ grub_env_export ("grub_netfs_type");
+ init_mode = INIT_MODE_GRUB;
+#endif
+
}
GRUB_MOD_FINI(net)
{
+
+#ifdef GRUB_MACHINE_EFI
+ if (init_mode == INIT_MODE_NONE)
+ return;
+
+ if (init_mode == INIT_MODE_EFI)
+ {
+ grub_unregister_command (cmd_lsroutes);
+ grub_unregister_command (cmd_lscards);
+ grub_unregister_command (cmd_lsaddr);
+ grub_unregister_command (cmd_addaddr);
+ grub_unregister_command (cmd_bootp);
+ grub_unregister_command (cmd_bootp6);
+ grub_efi_net_fs_fini ();
+ init_mode = INIT_MODE_NONE;
+ return;
+ }
+#endif
+
grub_register_variable_hook ("net_default_server", 0, 0);
grub_register_variable_hook ("pxe_default_server", 0, 0);
@@ -2096,4 +2167,7 @@ GRUB_MOD_FINI(net)
grub_net_fini_hw (0);
grub_loader_unregister_preboot_hook (fini_hnd);
grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
+#ifdef GRUB_MACHINE_EFI
+ init_mode = INIT_MODE_NONE;
+#endif
}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 716f121..2ed9c26 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -602,6 +602,23 @@ typedef union
typedef grub_efi_uint64_t grub_efi_physical_address_t;
typedef grub_efi_uint64_t grub_efi_virtual_address_t;
+typedef struct {
+ grub_uint8_t addr[4];
+} grub_efi_pxe_ipv4_address_t;
+
+typedef struct {
+ grub_uint8_t addr[16];
+} grub_efi_pxe_ipv6_address_t;
+
+typedef struct {
+ grub_uint8_t addr[32];
+} grub_efi_pxe_mac_address_t;
+
+typedef union {
+ grub_uint32_t addr[4];
+ grub_efi_pxe_ipv4_address_t v4;
+ grub_efi_pxe_ipv6_address_t v6;
+} grub_efi_pxe_ip_address_t;
struct grub_efi_guid
{
@@ -865,6 +882,8 @@ struct grub_efi_ipv6_device_path
grub_efi_uint16_t remote_port;
grub_efi_uint16_t protocol;
grub_efi_uint8_t static_ip_address;
+ grub_efi_uint8_t prefix_length;
+ grub_efi_ipv6_address_t gateway_ip_address;
} GRUB_PACKED;
typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t;
@@ -914,6 +933,15 @@ struct grub_efi_uri_device_path
} GRUB_PACKED;
typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
+#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE 31
+struct grub_efi_dns_device_path
+{
+ grub_efi_device_path_t header;
+ grub_efi_uint8_t is_ipv6;
+ grub_efi_pxe_ip_address_t dns_server_ip[0];
+} GRUB_PACKED;
+typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t;
+
#define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10
/* Media Device Path. */
@@ -996,6 +1024,23 @@ struct grub_efi_bios_device_path
} GRUB_PACKED;
typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t;
+/* Service Binding definitions */
+struct grub_efi_service_binding;
+
+typedef grub_efi_status_t
+(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this,
+ grub_efi_handle_t *child_handle);
+
+typedef grub_efi_status_t
+(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this,
+ grub_efi_handle_t *child_handle);
+
+typedef struct grub_efi_service_binding
+{
+ grub_efi_service_binding_create_child create_child;
+ grub_efi_service_binding_destroy_child destroy_child;
+} grub_efi_service_binding_t;
+
struct grub_efi_open_protocol_information_entry
{
grub_efi_handle_t agent_handle;
@@ -1545,23 +1590,27 @@ typedef struct grub_efi_pxe_tftp_error
grub_efi_char8_t error_string[127];
} grub_efi_pxe_tftp_error_t;
-typedef struct {
- grub_uint8_t addr[4];
-} grub_efi_pxe_ipv4_address_t;
+typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t;
-typedef struct {
- grub_uint8_t addr[16];
-} grub_efi_pxe_ipv6_address_t;
+typedef enum {
+ GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST,
+ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY,
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE,
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE,
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY,
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST
+} grub_efi_pxe_base_code_tftp_opcode_t;
typedef struct {
- grub_uint8_t addr[32];
-} grub_efi_pxe_mac_address_t;
-
-typedef union {
- grub_uint32_t addr[4];
- grub_efi_pxe_ipv4_address_t v4;
- grub_efi_pxe_ipv6_address_t v6;
-} grub_efi_pxe_ip_address_t;
+ grub_efi_ip_address_t mcast_ip;
+ grub_efi_pxe_base_code_udp_port_t c_port;
+ grub_efi_pxe_base_code_udp_port_t s_port;
+ grub_efi_uint16_t listen_timeout;
+ grub_efi_uint16_t transmit_timeout;
+} grub_efi_pxe_base_code_mtftp_info_t;
#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
typedef struct grub_efi_pxe_ip_filter
@@ -1628,17 +1677,31 @@ typedef struct grub_efi_pxe_mode
typedef struct grub_efi_pxe
{
grub_uint64_t rev;
- void (*start) (void);
+ grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6);
void (*stop) (void);
- void (*dhcp) (void);
+ grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this,
+ grub_efi_boolean_t sort_offers);
void (*discover) (void);
- void (*mftp) (void);
+ grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this,
+ grub_efi_pxe_base_code_tftp_opcode_t operation,
+ void *buffer_ptr,
+ grub_efi_boolean_t overwrite,
+ grub_efi_uint64_t *buffer_size,
+ grub_efi_uintn_t *block_size,
+ grub_efi_pxe_ip_address_t *server_ip,
+ //grub_efi_ip_address_t *server_ip,
+ grub_efi_char8_t *filename,
+ grub_efi_pxe_base_code_mtftp_info_t *info,
+ grub_efi_boolean_t dont_use_buffer);
void (*udpwrite) (void);
void (*udpread) (void);
void (*setipfilter) (void);
void (*arp) (void);
void (*setparams) (void);
- void (*setstationip) (void);
+ grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this,
+ grub_efi_pxe_ip_address_t *new_station_ip,
+ grub_efi_pxe_ip_address_t *new_subnet_mask);
+ //void (*setstationip) (void);
void (*setpackets) (void);
struct grub_efi_pxe_mode *mode;
} grub_efi_pxe_t;
@@ -1880,6 +1943,44 @@ struct grub_efi_ip4_config2_protocol
};
typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
+struct grub_efi_ip4_route_table {
+ grub_efi_ipv4_address_t subnet_address;
+ grub_efi_ipv4_address_t subnet_mask;
+ grub_efi_ipv4_address_t gateway_address;
+};
+
+typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t;
+
+#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32
+
+struct grub_efi_ip4_config2_interface_info {
+ grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE];
+ grub_efi_uint8_t if_type;
+ grub_efi_uint32_t hw_address_size;
+ grub_efi_mac_address_t hw_address;
+ grub_efi_ipv4_address_t station_address;
+ grub_efi_ipv4_address_t subnet_mask;
+ grub_efi_uint32_t route_table_size;
+ grub_efi_ip4_route_table_t *route_table;
+};
+
+typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t;
+
+enum grub_efi_ip4_config2_policy {
+ GRUB_EFI_IP4_CONFIG2_POLICY_STATIC,
+ GRUB_EFI_IP4_CONFIG2_POLICY_DHCP,
+ GRUB_EFI_IP4_CONFIG2_POLICY_MAX
+};
+
+typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t;
+
+struct grub_efi_ip4_config2_manual_address {
+ grub_efi_ipv4_address_t address;
+ grub_efi_ipv4_address_t subnet_mask;
+};
+
+typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t;
+
enum grub_efi_ip6_config_data_type {
GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
@@ -1914,6 +2015,49 @@ struct grub_efi_ip6_config_protocol
};
typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
+enum grub_efi_ip6_config_policy {
+ GRUB_EFI_IP6_CONFIG_POLICY_MANUAL,
+ GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC
+};
+typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t;
+
+struct grub_efi_ip6_address_info {
+ grub_efi_ipv6_address_t address;
+ grub_efi_uint8_t prefix_length;
+};
+typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t;
+
+struct grub_efi_ip6_route_table {
+ grub_efi_pxe_ipv6_address_t gateway;
+ grub_efi_pxe_ipv6_address_t destination;
+ grub_efi_uint8_t prefix_length;
+};
+typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t;
+
+struct grub_efi_ip6_config_interface_info {
+ grub_efi_char16_t name[32];
+ grub_efi_uint8_t if_type;
+ grub_efi_uint32_t hw_address_size;
+ grub_efi_mac_address_t hw_address;
+ grub_efi_uint32_t address_info_count;
+ grub_efi_ip6_address_info_t *address_info;
+ grub_efi_uint32_t route_count;
+ grub_efi_ip6_route_table_t *route_table;
+};
+typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t;
+
+struct grub_efi_ip6_config_dup_addr_detect_transmits {
+ grub_efi_uint32_t dup_addr_detect_transmits;
+};
+typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t;
+
+struct grub_efi_ip6_config_manual_address {
+ grub_efi_ipv6_address_t address;
+ grub_efi_boolean_t is_anycast;
+ grub_efi_uint8_t prefix_length;
+};
+typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t;
+
#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
|| defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
|| defined(__riscv)
diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h
new file mode 100644
index 0000000..fdb88eb
--- /dev/null
+++ b/include/grub/efi/dhcp.h
@@ -0,0 +1,343 @@
+#ifndef GRUB_EFI_DHCP_HEADER
+#define GRUB_EFI_DHCP_HEADER 1
+
+#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \
+ { 0x9d9a39d8, 0xbd42, 0x4a73, \
+ { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \
+ }
+
+#define GRUB_EFI_DHCP4_PROTOCOL_GUID \
+ { 0x8a219718, 0x4ef5, 0x4761, \
+ { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \
+ }
+
+#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \
+ { 0x9fb9a8a1, 0x2f4a, 0x43a6, \
+ { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \
+ }
+
+#define GRUB_EFI_DHCP6_PROTOCOL_GUID \
+ { 0x87c8bad7, 0x595, 0x4053, \
+ { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \
+ }
+
+typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t;
+
+enum grub_efi_dhcp4_state {
+ GRUB_EFI_DHCP4_STOPPED,
+ GRUB_EFI_DHCP4_INIT,
+ GRUB_EFI_DHCP4_SELECTING,
+ GRUB_EFI_DHCP4_REQUESTING,
+ GRUB_EFI_DHCP4_BOUND,
+ GRUB_EFI_DHCP4_RENEWING,
+ GRUB_EFI_DHCP4_REBINDING,
+ GRUB_EFI_DHCP4_INIT_REBOOT,
+ GRUB_EFI_DHCP4_REBOOTING
+};
+
+typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t;
+
+struct grub_efi_dhcp4_header {
+ grub_efi_uint8_t op_code;
+ grub_efi_uint8_t hw_type;
+ grub_efi_uint8_t hw_addr_len;
+ grub_efi_uint8_t hops;
+ grub_efi_uint32_t xid;
+ grub_efi_uint16_t seconds;
+ grub_efi_uint16_t reserved;
+ grub_efi_ipv4_address_t client_addr;
+ grub_efi_ipv4_address_t your_addr;
+ grub_efi_ipv4_address_t server_addr;
+ grub_efi_ipv4_address_t gateway_addr;
+ grub_efi_uint8_t client_hw_addr[16];
+ grub_efi_char8_t server_name[64];
+ grub_efi_char8_t boot_file_name[128];
+} GRUB_PACKED;
+
+typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t;
+
+struct grub_efi_dhcp4_packet {
+ grub_efi_uint32_t size;
+ grub_efi_uint32_t length;
+ struct {
+ grub_efi_dhcp4_header_t header;
+ grub_efi_uint32_t magik;
+ grub_efi_uint8_t option[1];
+ } dhcp4;
+} GRUB_PACKED;
+
+typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t;
+
+struct grub_efi_dhcp4_listen_point {
+ grub_efi_ipv4_address_t listen_address;
+ grub_efi_ipv4_address_t subnet_mask;
+ grub_efi_uint16_t listen_port;
+};
+
+typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t;
+
+struct grub_efi_dhcp4_transmit_receive_token {
+ grub_efi_status_t status;
+ grub_efi_event_t completion_event;
+ grub_efi_ipv4_address_t remote_address;
+ grub_efi_uint16_t remote_port;
+ grub_efi_ipv4_address_t gateway_address;
+ grub_efi_uint32_t listen_point_count;
+ grub_efi_dhcp4_listen_point_t *listen_points;
+ grub_efi_uint32_t timeout_value;
+ grub_efi_dhcp4_packet_t *packet;
+ grub_efi_uint32_t response_count;
+ grub_efi_dhcp4_packet_t *response_list;
+};
+
+typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t;
+
+enum grub_efi_dhcp4_event {
+ GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01,
+ GRUB_EFI_DHCP4_RCVD_OFFER,
+ GRUB_EFI_DHCP4_SELECT_OFFER,
+ GRUB_EFI_DHCP4_SEND_REQUEST,
+ GRUB_EFI_DHCP4_RCVD_ACK,
+ GRUB_EFI_DHCP4_RCVD_NAK,
+ GRUB_EFI_DHCP4_SEND_DECLINE,
+ GRUB_EFI_DHCP4_BOUND_COMPLETED,
+ GRUB_EFI_DHCP4_ENTER_RENEWING,
+ GRUB_EFI_DHCP4_ENTER_REBINDING,
+ GRUB_EFI_DHCP4_ADDRESS_LOST,
+ GRUB_EFI_DHCP4_FAIL
+};
+
+typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t;
+
+struct grub_efi_dhcp4_packet_option {
+ grub_efi_uint8_t op_code;
+ grub_efi_uint8_t length;
+ grub_efi_uint8_t data[1];
+} GRUB_PACKED;
+
+typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t;
+
+struct grub_efi_dhcp4_config_data {
+ grub_efi_uint32_t discover_try_count;
+ grub_efi_uint32_t *discover_timeout;
+ grub_efi_uint32_t request_try_count;
+ grub_efi_uint32_t *request_timeout;
+ grub_efi_ipv4_address_t client_address;
+ grub_efi_status_t (*dhcp4_callback) (
+ grub_efi_dhcp4_protocol_t *this,
+ void *context,
+ grub_efi_dhcp4_state_t current_state,
+ grub_efi_dhcp4_event_t dhcp4_event,
+ grub_efi_dhcp4_packet_t *packet,
+ grub_efi_dhcp4_packet_t **new_packet
+ );
+ void *callback_context;
+ grub_efi_uint32_t option_count;
+ grub_efi_dhcp4_packet_option_t **option_list;
+};
+
+typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t;
+
+struct grub_efi_dhcp4_mode_data {
+ grub_efi_dhcp4_state_t state;
+ grub_efi_dhcp4_config_data_t config_data;
+ grub_efi_ipv4_address_t client_address;
+ grub_efi_mac_address_t client_mac_address;
+ grub_efi_ipv4_address_t server_address;
+ grub_efi_ipv4_address_t router_address;
+ grub_efi_ipv4_address_t subnet_mask;
+ grub_efi_uint32_t lease_time;
+ grub_efi_dhcp4_packet_t *reply_packet;
+};
+
+typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t;
+
+struct grub_efi_dhcp4_protocol {
+ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this,
+ grub_efi_dhcp4_mode_data_t *dhcp4_mode_data);
+ grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this,
+ grub_efi_dhcp4_config_data_t *dhcp4_cfg_data);
+ grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this,
+ grub_efi_event_t completion_event);
+ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this,
+ grub_efi_boolean_t rebind_request,
+ grub_efi_event_t completion_event);
+ grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this);
+ grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this);
+ grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this,
+ grub_efi_dhcp4_packet_t *seed_packet,
+ grub_efi_uint32_t delete_count,
+ grub_efi_uint8_t *delete_list,
+ grub_efi_uint32_t append_count,
+ grub_efi_dhcp4_packet_option_t *append_list[],
+ grub_efi_dhcp4_packet_t **new_packet);
+ grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this,
+ grub_efi_dhcp4_transmit_receive_token_t *token);
+ grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this,
+ grub_efi_dhcp4_packet_t *packet,
+ grub_efi_uint32_t *option_count,
+ grub_efi_dhcp4_packet_option_t *packet_option_list[]);
+};
+
+typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t;
+
+struct grub_efi_dhcp6_retransmission {
+ grub_efi_uint32_t irt;
+ grub_efi_uint32_t mrc;
+ grub_efi_uint32_t mrt;
+ grub_efi_uint32_t mrd;
+};
+
+typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t;
+
+enum grub_efi_dhcp6_event {
+ GRUB_EFI_DHCP6_SEND_SOLICIT,
+ GRUB_EFI_DHCP6_RCVD_ADVERTISE,
+ GRUB_EFI_DHCP6_SELECT_ADVERTISE,
+ GRUB_EFI_DHCP6_SEND_REQUEST,
+ GRUB_EFI_DHCP6_RCVD_REPLY,
+ GRUB_EFI_DHCP6_RCVD_RECONFIGURE,
+ GRUB_EFI_DHCP6_SEND_DECLINE,
+ GRUB_EFI_DHCP6_SEND_CONFIRM,
+ GRUB_EFI_DHCP6_SEND_RELEASE,
+ GRUB_EFI_DHCP6_SEND_RENEW,
+ GRUB_EFI_DHCP6_SEND_REBIND
+};
+
+typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t;
+
+struct grub_efi_dhcp6_packet_option {
+ grub_efi_uint16_t op_code;
+ grub_efi_uint16_t op_len;
+ grub_efi_uint8_t data[1];
+} GRUB_PACKED;
+
+typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t;
+
+struct grub_efi_dhcp6_header {
+ grub_efi_uint32_t transaction_id:24;
+ grub_efi_uint32_t message_type:8;
+} GRUB_PACKED;
+
+typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t;
+
+struct grub_efi_dhcp6_packet {
+ grub_efi_uint32_t size;
+ grub_efi_uint32_t length;
+ struct {
+ grub_efi_dhcp6_header_t header;
+ grub_efi_uint8_t option[1];
+ } dhcp6;
+} GRUB_PACKED;
+
+typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t;
+
+struct grub_efi_dhcp6_ia_address {
+ grub_efi_ipv6_address_t ip_address;
+ grub_efi_uint32_t preferred_lifetime;
+ grub_efi_uint32_t valid_lifetime;
+};
+
+typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t;
+
+enum grub_efi_dhcp6_state {
+ GRUB_EFI_DHCP6_INIT,
+ GRUB_EFI_DHCP6_SELECTING,
+ GRUB_EFI_DHCP6_REQUESTING,
+ GRUB_EFI_DHCP6_DECLINING,
+ GRUB_EFI_DHCP6_CONFIRMING,
+ GRUB_EFI_DHCP6_RELEASING,
+ GRUB_EFI_DHCP6_BOUND,
+ GRUB_EFI_DHCP6_RENEWING,
+ GRUB_EFI_DHCP6_REBINDING
+};
+
+typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t;
+
+#define GRUB_EFI_DHCP6_IA_TYPE_NA 3
+#define GRUB_EFI_DHCP6_IA_TYPE_TA 4
+
+struct grub_efi_dhcp6_ia_descriptor {
+ grub_efi_uint16_t type;
+ grub_efi_uint32_t ia_id;
+};
+
+typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t;
+
+struct grub_efi_dhcp6_ia {
+ grub_efi_dhcp6_ia_descriptor_t descriptor;
+ grub_efi_dhcp6_state_t state;
+ grub_efi_dhcp6_packet_t *reply_packet;
+ grub_efi_uint32_t ia_address_count;
+ grub_efi_dhcp6_ia_address_t ia_address[1];
+};
+
+typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t;
+
+struct grub_efi_dhcp6_duid {
+ grub_efi_uint16_t length;
+ grub_efi_uint8_t duid[1];
+};
+
+typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t;
+
+struct grub_efi_dhcp6_mode_data {
+ grub_efi_dhcp6_duid_t *client_id;
+ grub_efi_dhcp6_ia_t *ia;
+};
+
+typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t;
+
+struct grub_efi_dhcp6_config_data {
+ grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this,
+ void *context,
+ grub_efi_dhcp6_state_t current_state,
+ grub_efi_dhcp6_event_t dhcp6_event,
+ grub_efi_dhcp6_packet_t *packet,
+ grub_efi_dhcp6_packet_t **new_packet);
+ void *callback_context;
+ grub_efi_uint32_t option_count;
+ grub_efi_dhcp6_packet_option_t **option_list;
+ grub_efi_dhcp6_ia_descriptor_t ia_descriptor;
+ grub_efi_event_t ia_info_event;
+ grub_efi_boolean_t reconfigure_accept;
+ grub_efi_boolean_t rapid_commit;
+ grub_efi_dhcp6_retransmission_t *solicit_retransmission;
+};
+
+typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t;
+
+struct grub_efi_dhcp6_protocol {
+ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this,
+ grub_efi_dhcp6_mode_data_t *dhcp6_mode_data,
+ grub_efi_dhcp6_config_data_t *dhcp6_config_data);
+ grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this,
+ grub_efi_dhcp6_config_data_t *dhcp6_cfg_data);
+ grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this);
+ grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this,
+ grub_efi_boolean_t send_client_id,
+ grub_efi_dhcp6_packet_option_t *option_request,
+ grub_efi_uint32_t option_count,
+ grub_efi_dhcp6_packet_option_t *option_list[],
+ grub_efi_dhcp6_retransmission_t *retransmission,
+ grub_efi_event_t timeout_event,
+ grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this,
+ void *context,
+ grub_efi_dhcp6_packet_t *packet),
+ void *callback_context);
+ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this,
+ grub_efi_boolean_t rebind_request);
+ grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this,
+ grub_efi_uint32_t address_count,
+ grub_efi_ipv6_address_t *addresses);
+ grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this,
+ grub_efi_uint32_t address_count,
+ grub_efi_ipv6_address_t *addresses);
+ grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this);
+ grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this,
+ grub_efi_dhcp6_packet_t *packet,
+ grub_efi_uint32_t *option_count,
+ grub_efi_dhcp6_packet_option_t *packet_option_list[]);
+};
+
+#endif /* ! GRUB_EFI_DHCP_HEADER */
diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h
new file mode 100644
index 0000000..c5e9a89
--- /dev/null
+++ b/include/grub/efi/http.h
@@ -0,0 +1,215 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_EFI_HTTP_HEADER
+#define GRUB_EFI_HTTP_HEADER 1
+
+#include <grub/symbol.h>
+#include <grub/net.h>
+#include <grub/efi/api.h>
+
+#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \
+ { 0xbdc8e6af, 0xd9bc, 0x4379, \
+ { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \
+ }
+
+#define GRUB_EFI_HTTP_PROTOCOL_GUID \
+ { 0x7A59B29B, 0x910B, 0x4171, \
+ { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \
+ }
+
+#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s
+#define EFIHTTP_RX_BUF_LEN 10240
+
+//******************************************
+// Protocol Interface Structure
+//******************************************
+struct grub_efi_http;
+
+//******************************************
+// EFI_HTTP_VERSION
+//******************************************
+typedef enum {
+ GRUB_EFI_HTTPVERSION10,
+ GRUB_EFI_HTTPVERSION11,
+ GRUB_EFI_HTTPVERSIONUNSUPPORTED
+} grub_efi_http_version_t;
+
+//******************************************
+// EFI_HTTPv4_ACCESS_POINT
+//******************************************
+typedef struct {
+ grub_efi_boolean_t use_default_address;
+ grub_efi_ipv4_address_t local_address;
+ grub_efi_ipv4_address_t local_subnet;
+ grub_efi_uint16_t local_port;
+} grub_efi_httpv4_access_point_t;
+
+//******************************************
+// EFI_HTTPv6_ACCESS_POINT
+//******************************************
+typedef struct {
+ grub_efi_ipv6_address_t local_address;
+ grub_efi_uint16_t local_port;
+} grub_efi_httpv6_access_point_t;
+
+//******************************************
+// EFI_HTTP_CONFIG_DATA
+//******************************************
+typedef struct {
+ grub_efi_http_version_t http_version;
+ grub_efi_uint32_t timeout_millisec;
+ grub_efi_boolean_t local_address_is_ipv6;
+ union {
+ grub_efi_httpv4_access_point_t *ipv4_node;
+ grub_efi_httpv6_access_point_t *ipv6_node;
+ } access_point;
+} grub_efi_http_config_data_t;
+
+//******************************************
+// EFI_HTTP_METHOD
+//******************************************
+typedef enum {
+ GRUB_EFI_HTTPMETHODGET,
+ GRUB_EFI_HTTPMETHODPOST,
+ GRUB_EFI_HTTPMETHODPATCH,
+ GRUB_EFI_HTTPMETHODOPTIONS,
+ GRUB_EFI_HTTPMETHODCONNECT,
+ GRUB_EFI_HTTPMETHODHEAD,
+ GRUB_EFI_HTTPMETHODPUT,
+ GRUB_EFI_HTTPMETHODDELETE,
+ GRUB_EFI_HTTPMETHODTRACE,
+} grub_efi_http_method_t;
+
+//******************************************
+// EFI_HTTP_REQUEST_DATA
+//******************************************
+typedef struct {
+ grub_efi_http_method_t method;
+ grub_efi_char16_t *url;
+} grub_efi_http_request_data_t;
+
+typedef enum {
+ GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0,
+ GRUB_EFI_HTTP_STATUS_100_CONTINUE,
+ GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS,
+ GRUB_EFI_HTTP_STATUS_200_OK,
+ GRUB_EFI_HTTP_STATUS_201_CREATED,
+ GRUB_EFI_HTTP_STATUS_202_ACCEPTED,
+ GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION,
+ GRUB_EFI_HTTP_STATUS_204_NO_CONTENT,
+ GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT,
+ GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT,
+ GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES,
+ GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY,
+ GRUB_EFI_HTTP_STATUS_302_FOUND,
+ GRUB_EFI_HTTP_STATUS_303_SEE_OTHER,
+ GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED,
+ GRUB_EFI_HTTP_STATUS_305_USE_PROXY,
+ GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT,
+ GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST,
+ GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED,
+ GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED,
+ GRUB_EFI_HTTP_STATUS_403_FORBIDDEN,
+ GRUB_EFI_HTTP_STATUS_404_NOT_FOUND,
+ GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED,
+ GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE,
+ GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED,
+ GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT,
+ GRUB_EFI_HTTP_STATUS_409_CONFLICT,
+ GRUB_EFI_HTTP_STATUS_410_GONE,
+ GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED,
+ GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED,
+ GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE,
+ GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE,
+ GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE,
+ GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED,
+ GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED,
+ GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR,
+ GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED,
+ GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY,
+ GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE,
+ GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT,
+ GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED
+} grub_efi_http_status_code_t;
+
+//******************************************
+// EFI_HTTP_RESPONSE_DATA
+//******************************************
+typedef struct {
+ grub_efi_http_status_code_t status_code;
+} grub_efi_http_response_data_t;
+
+//******************************************
+// EFI_HTTP_HEADER
+//******************************************
+typedef struct {
+ grub_efi_char8_t *field_name;
+ grub_efi_char8_t *field_value;
+} grub_efi_http_header_t;
+
+//******************************************
+// EFI_HTTP_MESSAGE
+//******************************************
+typedef struct {
+ union {
+ grub_efi_http_request_data_t *request;
+ grub_efi_http_response_data_t *response;
+ } data;
+ grub_efi_uint32_t header_count;
+ grub_efi_http_header_t *headers;
+ grub_efi_uint32_t body_length;
+ void *body;
+} grub_efi_http_message_t;
+
+//******************************************
+// EFI_HTTP_TOKEN
+//******************************************
+typedef struct {
+ grub_efi_event_t event;
+ grub_efi_status_t status;
+ grub_efi_http_message_t *message;
+} grub_efi_http_token_t;
+
+struct grub_efi_http {
+ grub_efi_status_t
+ (*get_mode_data) (struct grub_efi_http *this,
+ grub_efi_http_config_data_t *http_config_data);
+
+ grub_efi_status_t
+ (*configure) (struct grub_efi_http *this,
+ grub_efi_http_config_data_t *http_config_data);
+
+ grub_efi_status_t
+ (*request) (struct grub_efi_http *this,
+ grub_efi_http_token_t *token);
+
+ grub_efi_status_t
+ (*cancel) (struct grub_efi_http *this,
+ grub_efi_http_token_t *token);
+
+ grub_efi_status_t
+ (*response) (struct grub_efi_http *this,
+ grub_efi_http_token_t *token);
+
+ grub_efi_status_t
+ (*poll) (struct grub_efi_http *this);
+};
+typedef struct grub_efi_http grub_efi_http_t;
+
+#endif /* !GRUB_EFI_HTTP_HEADER */
diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h
new file mode 100644
index 0000000..de90d22
--- /dev/null
+++ b/include/grub/net/efi.h
@@ -0,0 +1,144 @@
+#ifndef GRUB_NET_EFI_HEADER
+#define GRUB_NET_EFI_HEADER 1
+
+#include <grub/efi/api.h>
+#include <grub/efi/http.h>
+#include <grub/efi/dhcp.h>
+#include <grub/command.h>
+
+typedef struct grub_efi_net_interface grub_efi_net_interface_t;
+typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t;
+typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t;
+typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t;
+
+struct grub_efi_net_interface
+{
+ char *name;
+ int prefer_ip6;
+ struct grub_efi_net_device *dev;
+ struct grub_efi_net_io *io;
+ grub_efi_net_ip_config_t *ip_config;
+ int io_type;
+ struct grub_efi_net_interface *next;
+};
+
+#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev)
+#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev)
+#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev)
+#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet)
+#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr)
+#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr)
+
+struct grub_efi_net_ip_config
+{
+ char * (*get_hw_address) (struct grub_efi_net_device *dev);
+ char * (*get_address) (struct grub_efi_net_device *dev);
+ char ** (*get_route_table) (struct grub_efi_net_device *dev);
+ grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
+ int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet);
+ int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
+ int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns);
+};
+
+union grub_efi_net_ip_address
+{
+ grub_efi_ipv4_address_t ip4;
+ grub_efi_ipv6_address_t ip6;
+};
+
+struct grub_efi_net_ip_manual_address
+{
+ int is_ip6;
+ union
+ {
+ grub_efi_ip4_config2_manual_address_t ip4;
+ grub_efi_ip6_config_manual_address_t ip6;
+ };
+};
+
+struct grub_efi_net_device
+{
+ grub_efi_handle_t handle;
+ grub_efi_ip4_config2_protocol_t *ip4_config;
+ grub_efi_ip6_config_protocol_t *ip6_config;
+ grub_efi_handle_t http_handle;
+ grub_efi_http_t *http;
+ grub_efi_handle_t ip4_pxe_handle;
+ grub_efi_pxe_t *ip4_pxe;
+ grub_efi_handle_t ip6_pxe_handle;
+ grub_efi_pxe_t *ip6_pxe;
+ grub_efi_handle_t dhcp4_handle;
+ grub_efi_dhcp4_protocol_t *dhcp4;
+ grub_efi_handle_t dhcp6_handle;
+ grub_efi_dhcp6_protocol_t *dhcp6;
+ char *card_name;
+ grub_efi_net_interface_t *net_interfaces;
+ struct grub_efi_net_device *next;
+};
+
+struct grub_efi_net_io
+{
+ void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6);
+ grub_err_t (*open) (struct grub_efi_net_device *dev,
+ int prefer_ip6,
+ grub_file_t file,
+ const char *filename,
+ int type);
+ grub_ssize_t (*read) (struct grub_efi_net_device *dev,
+ int prefer_ip6,
+ grub_file_t file,
+ char *buf,
+ grub_size_t len);
+ grub_err_t (*close) (struct grub_efi_net_device *dev,
+ int prefer_ip6,
+ grub_file_t file);
+};
+
+extern struct grub_efi_net_device *net_devices;
+
+extern struct grub_efi_net_io io_http;
+extern struct grub_efi_net_io io_pxe;
+
+extern grub_efi_net_ip_config_t *efi_net_ip4_config;
+extern grub_efi_net_ip_config_t *efi_net_ip6_config;
+
+char *
+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address);
+
+char *
+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address);
+
+char *
+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address);
+
+int
+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest);
+
+int
+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest);
+
+char *
+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev);
+
+char *
+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev);
+
+grub_efi_net_interface_t *
+grub_efi_net_create_interface (struct grub_efi_net_device *dev,
+ const char *interface_name,
+ grub_efi_net_ip_manual_address_t *net_ip,
+ int has_subnet);
+
+int grub_efi_net_fs_init (void);
+void grub_efi_net_fs_fini (void);
+int grub_efi_net_boot_from_https (void);
+int grub_efi_net_boot_from_opa (void);
+
+extern grub_command_func_t grub_efi_net_list_routes;
+extern grub_command_func_t grub_efi_net_list_cards;
+extern grub_command_func_t grub_efi_net_list_addrs;
+extern grub_command_func_t grub_efi_net_add_addr;
+extern grub_command_func_t grub_efi_net_bootp;
+extern grub_command_func_t grub_efi_net_bootp6;
+
+#endif /* ! GRUB_NET_EFI_HEADER */
diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c
index 602574d..1a61e05 100644
--- a/util/grub-mknetdir.c
+++ b/util/grub-mknetdir.c
@@ -32,13 +32,15 @@
static char *rootdir = NULL, *subdir = NULL;
static char *debug_image = NULL;
+static char efi_netfs = 0;
enum
{
OPTION_NET_DIRECTORY = 0x301,
OPTION_SUBDIR,
OPTION_DEBUG,
- OPTION_DEBUG_IMAGE
+ OPTION_DEBUG_IMAGE,
+ OPTION_DEBUG_EFI_NETFS
};
static struct argp_option options[] = {
@@ -49,6 +51,7 @@ static struct argp_option options[] = {
0, N_("relative subdirectory on network server"), 2},
{"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2},
{"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2},
+ {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2},
{0, 0, 0, 0, 0, 0}
};
@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
free (subdir);
subdir = xstrdup (arg);
return 0;
+ case OPTION_DEBUG_EFI_NETFS:
+ efi_netfs = 1;
+ return 0;
/* This is an undocumented feature... */
case OPTION_DEBUG:
verbosity++;
@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state)
}
}
-
struct argp argp = {
options, argp_parser, NULL,
"\v"N_("Prepares GRUB network boot images at net_directory/subdir "
@@ -92,7 +97,7 @@ struct argp argp = {
static char *base;
-static const struct
+static struct
{
const char *mkimage_target;
const char *netmodule;
@@ -156,6 +161,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform)
grub_install_push_module (targets[platform].netmodule);
output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext);
+
grub_install_make_image_wrap (input_dir, prefix, output,
0, load_cfg,
targets[platform].mkimage_target, 0);
@@ -192,7 +198,16 @@ main (int argc, char *argv[])
grub_install_mkdir_p (base);
- grub_install_push_module ("tftp");
+ if (!efi_netfs)
+ {
+ grub_install_push_module ("tftp");
+ grub_install_push_module ("http");
+ }
+ else
+ {
+ targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs";
+ targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs";
+ }
if (!grub_install_source_directory)
{
--
1.8.3.1
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/yyangqiming/grub2.git
git@gitee.com:yyangqiming/grub2.git
yyangqiming
grub2
grub2
master

搜索帮助