All pastes #1967236 Raw Edit

Anonymous

public text v1 · immutable
#1967236 ·published 2010-10-19 19:22 UTC
rendered paste body
% 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"@<Predeclaration of procedures@>=
qJA";
J"@
"@<Procedure codes@>=
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

@<Menu items@>=
  "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
@<Include files@>@;
@h
@<Global variables@>@;
@<Predeclaration of procedures@>@;
@<Procedure codes@>;

@ @<Include files@>=
#include <string.h>
#include <stdio.h>
#include <consoles.h> // Provided by libutil
#include <com32.h>
#include <stdlib.h>
#include <getkey.h>
#include <syslinux/pxe.h> // PXELINUX

@ @-p int main(void) {
  int the_choice;
  char mac_addr_string[40];
  @<Read the MAC address@>;
  @<Display the main menu@>;
  read_choice_again:
  @<Read the choice from the user@>;
  @<Do the action according to choice@>;
  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@>

@<Read the 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.

@<Global variables@>=
const char*menu_items[]= {@<Menu items@>@;0@;};

@ @<Display the main menu@>= {
  console_ansi_raw();
  @<Clear the screen@>;
  @<Display the header and footer@>;
  @<Display the menu items@>;
}

@ @<Clear the screen@>= {
  printf("\e[m\e[2J"); @q]@>
}

@ @<Display the header and footer@>= {
  printf("\e[1;5f\e[7m %s \e[m",MENU_TITLE); @q]]]@>
  printf("\e[2;5fMAC Address: %s",mac_addr_string); @q]@>
}

@ @<Display the menu items@>= {
  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]]]@>
    @<Display the text for this menu item@>;
  }
}

@ @<Display the text for this menu item@>= {
  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.

@<Read the choice from the user@>= {
  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

@<Do the action according to choice@>= {
  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(&reg,0,sizeof(reg))@;

@d perform_call(_1) do{
  AX=(_1);
  __intcall(0x22,&reg,&reg);
}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

@<Global variables@>=
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=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) {
  @<Open the UDP connection@>;
  @<Send the UDP data@>;
  @<Close the UDP connection@>;
}

@ @<Open the UDP connection@>= {
  t_PXENV_UDP_OPEN in_par;
  in_par.src_ip=cached_info.cip;
  BX=0x0030;
  sys_struct(&in_par,ES,DI);
  perform_call(0x0009);
}

@ @<Send the UDP data@>= {
  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);
}

@ @<Close the UDP connection@>= {
  t_PXENV_UDP_CLOSE in_par;
  BX=0x0031;
  sys_struct(&in_par,ES,DI);
  perform_call(0x0009);
}

@*Index.