% PXE Register Program % Version 0.1 % Licensed under GNU GPL version 3 or later version \def\title{PXE Register Program} \def\pa#1{$\langle$#1$\rangle$} @mp@- ``u{YJ"@= qJA"; J"@ "@= B" { @) @s com32sys_t int @s uint32_t int @s uint16_t int @s uint8_t int @s t_PXENV_GET_CACHED_INFO int @s t_PXENV_UDP_OPEN int @s t_PXENV_UDP_WRITE int @s t_PXENV_UDP_CLOSE int @s pxe_bootp_t int @*Introduction. This program is used with the PXE Linux network boot to prompt the user to register the MAC address as a certain type of machine and to make it automatically boot. (This program does not deal with the automatic boot; it only sends the registration information.) This program was designed for Free Geek Vancouver; however, you can use it for other uses, too. @*Compile-time configuration. Change these settings to tell it what to do when sending the UDP packets to the server, and what server to send it to and what port number, how many times, and what choices should be listed on the menu. The menu items should be formatted as: ``\pa{key}\.^^7c\pa{text}\.^^7c\pa{value}'' @q Note: ^^7c is TeX trigraph for | @> @d MENU_TITLE "PXE Register - Free Geek Vancouver" @d SERVER_NAME "" @d SERVER_PORT 0 @d SERVER_COUNT 3 @= "1|RAM Test|memtest", @/ "2|Drive Wipe|utility/vmlinuz ro initrd=utility/initrd.img " "root=/dev/nfs nfsroot=10.0.5.15:/srv/netboot/lucid ip=dhcp " "diskwipe", @/ "3|System Installer|", @/ "4|LTSP Terminal|ltsp/yew/vmlinuz ro initrd=ltsp/yew/initrd.img " "acpi=off quiet splash nbdroot=10.0.5.12:2000", @/ @*Start of program. @c @@; @h @@; @@; @; @ @= #include #include #include // Provided by libutil #include #include #include #include // PXELINUX @ @-p int main(void) { int the_choice; char mac_addr_string[40]; @; @; read_choice_again: @; @; return 0; } @ The MAC address will now be stored in |cached_info.CAddr| which is an array of sixteen bytes. The string |mac_addr_string| is the text representation of the MAC address. @^MAC address@> @= { int i; get_cached_info(); for(i=0;i<16;i++) { sprintf(mac_addr_string+i+i,"%02X",cached_info.CAddr[i]); } } @*Menu. @= const char*menu_items[]= @+{@@;0@;}@+; @ @= { console_ansi_raw(); @; @; @; } @ @= { printf("\e[m\e[2J"); @q]@> } @ @= { printf("\e[1;5f\e[7m %s \e[m",MENU_TITLE); @q]]]@> printf("\e[2;5fMAC Address: %s",mac_addr_string); @q]@> } @ @= { int i; const char*c; for(i=0;(c=menu_items[i]);i++) { printf("\e[%d;6f\e[7m %c \e[m ",i+5,*c); @q]]]@> @; } } @ @= { c+=2; while(*c!='|') putc(*c++,stdout); } @ The key numbers are the same as in QBASIC; either the ASCII character code or zero followed by the scancode number. This function converts extended codes to negative numbers instead. @= { do { the_choice=fgetc(stdin); if(!the_choice) the_choice=-fgetc(stdin); } while(the_choice==-1); } @*Action. This part is sending action to the server |SERVER_NAME| on port number |SERVER_PORT| by UDP. The variable |the_choice| indicates character of key pushed on the keyboard. @d KEY_ESCAPE 27 @= { if(the_choice==KEY_ESCAPE) return 0; printf("%d",the_choice); goto read_choice_again; } @*System calls. SYSLINUX requires use of interrupts for system calls. (This program requires x86 systems.) @^system dependencies@> @^interrupt@> @^registers@> @d clear_reg() memset(®,0,sizeof(reg))@; @d perform_call(_1) do{ AX=(_1); __intcall(0x22,®,®); }while(0)@; @d sys_string(_1,_2,_3) do{ strcpy((char*)__com32.cs_bounce,_1); _2=SEG(__com32.cs_bounce); _3=OFFS(__com32.cs_bounce); }while(0)@; @d sys_struct(_1,_2,_3) do{ memcpy((void*)__com32.cs_bounce,(_1),sizeof(*(_1))); _2=SEG(__com32.cs_bounce); _3=OFFS(__com32.cs_bounce); }while(0)@; @d successful (reg.eflags.l&EFLAGS_CF) @# @d AL reg.eax.b[0] @d AH reg.eax.b[1] @d BL reg.ebx.b[0] @d BH reg.ebx.b[1] @d CL reg.ecx.b[0] @d CH reg.ecx.b[1] @d DL reg.edx.b[0] @d DH reg.edx.b[1] @d AX reg.eax.w[0] @d BX reg.ebx.w[0] @d CX reg.ecx.w[0] @d DX reg.edx.w[0] @d BP reg.ebp.w[0] @d SP reg._usused_esp.w[0] @d SI reg.esi.w[0] @d DI reg.edi.w[0] @d DS reg.ds @d ES reg.es @d FS reg.fs @d GS reg.gs @d EAX reg.eax.l @d EBX reg.ebx.l @d ECX reg.ecx.l @d EDX reg.edx.l @d EBP reg.ebp.l @d ESP reg._usused_esp.l @d ESI reg.esi.l @d EDI reg.edi.l @= com32sys_t reg; pxe_bootp_t cached_info; @ @-p uint32_t resolve_hostname(char*name) { clear_reg(); sys_string(name,ES,BX); perform_call(0x0010); return EAX; } @ @-p uint16_t get_cached_info(void) { t_PXENV_GET_CACHED_INFO in_par; clear_reg(); BX=0x0071; // Get cached info in_par.PacketType=PXENV_PACKET_TYPE_DHCP_ACK; in_par.Buffer=FAR_PTR(&cached_info); in_par.BufferSize=in_par.BufferLimit=sizeof(cached_info); sys_struct(&in_par,ES,DI); perform_call(0x0009); return AX; } @ @-p void send_packet(uint32_t target,uint32_t port,char*data) { @; @; @; } @ @= { t_PXENV_UDP_OPEN in_par; in_par.src_ip=cached_info.cip; BX=0x0030; sys_struct(&in_par,ES,DI); perform_call(0x0009); } @ @= { t_PXENV_UDP_WRITE in_par; in_par.ip=target; in_par.gw=0; in_par.src_port=0; in_par.dst_port=port; in_par.buffer=FAR_PTR(data); in_par.buffer_size=strlen(data); BX=0x0033; sys_struct(&in_par,ES,DI); perform_call(0x0009); } @ @= { t_PXENV_UDP_CLOSE in_par; BX=0x0031; sys_struct(&in_par,ES,DI); perform_call(0x0009); } @*Index.