Subject: rbootd works on SunOS4's NIT
To: None <port-hp300@NetBSD.ORG>
From: YAMAMORI Takenori <yamamori@kt.rim.or.jp>
List: port-hp300
Date: 05/28/1998 21:00:31
Hello, this is my first mail.

  I've just succeeded in diskless booting NetBSD/hp300 by rbootd
running on SunOS4's NIT (not BPF).

  I shall send this "rbootd on SunOS4's NIT" named "sun-rbootd.c"
for someone who might need it.

  And I made some changes on this sun-rbootd as follows:
    * not use /etc/rbootd.conf but use /etc/ethers (or NIS ethers map)
    * put SYS_UBOOT on /tftpboot instead of /usr/mdec/rbootd,
      and symlink to C0A8XXXX if client IP is 192.168.xx.xx.
      (like Sun's rarp/tftp)

  You can make sun-rbootd with some additional files.

    * etherlib.tar.gz
        This contains functions ether_open(), ether_read(), ether_write()
	etc., and I can use NIT by these.
	(Please find it by archie, ftpsearch etc.)

    * rmp.h rmp_var.h
	These are from the original rbootd source.

(This source is somewhat "quick hack" but it works fine)
Now, I can boot diskless NetBSD/hp300 by SunOS4 boot-server without BPF!!
# OpenBSD/hp300 also boots.

----- sun-rbootd.c --(begin)------------------------------------------------
/* sun-rbootd.c yamamori@kt.rim.or.jp */

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <netdb.h>

#include "ether.h"

/* typedef unsigned char u_int8_t; */
/* typedef unsigned short u_int16_t; */

#include "rmp.h"
#undef RMP_MAX_PACKET
#define RMP_MAX_PACKET 1514
#include "rmp_var.h"

#define TFTPBOOT "/tftpboot"

static union {
  char buf[2048];
  struct {
    struct hp_llc llc;
    union {
      struct rmp_raw raw;
      struct rmp_boot_req boot_req;
      struct rmp_boot_repl boot_repl;
      struct rmp_read_req read_req;
      struct rmp_read_repl read_repl;
    } proto;
  } rmp;
} pb;

static ether_addr rmp_addr = {RMP_ADDR};


static int
my_ether_write(ether_packet *packetp)
{
  int fd;

  if (
    packetp->pktlen > 1500 ||
    (fd = ether_open(0, packetp->pktlen, &rmp_addr)) < 0
  ) {
    return 1;
  }
  ether_write(fd, packetp);
  close(fd);
  return 0;
}


int
main()
{
  int fd_r, fd_boot;
  ether_packet packet;
  ether_addr dest;
  int size;
  struct hostent *hp;
  char boot_file[8+1];
  char hostname[MAXHOSTNAMELEN];

  if (chdir(TFTPBOOT) < 0) {
    perror(TFTPBOOT);
    return 1;
  }

  if ((fd_r = ether_open(0, -1, &rmp_addr)) < 0) {
    perror("ether_open");
    return 1;
  }

  packet.pktbuf = pb.buf;

  for (;;) {
    packet.pktlen = 60;
    ether_read(fd_r, &packet);

    if (
      !(
	*(unsigned short *)packet.type <= 1500 &&
	pb.rmp.llc.dsap == IEEE_DSAP_HP &&
	pb.rmp.llc.ssap == IEEE_SSAP_HP &&
	pb.rmp.llc.cntrl == IEEE_CNTL_HP &&
	pb.rmp.llc.filler == 0 &&
	pb.rmp.llc.dxsap == HPEXT_DXSAP &&
	pb.rmp.llc.sxsap == HPEXT_SXSAP
      )
    ) {
      continue;
    }

    dest = *(ether_addr *)packet.dest;
    *(ether_addr *)packet.dest = *(ether_addr *)packet.src;

    pb.rmp.llc.dxsap = HPEXT_SXSAP;
    pb.rmp.llc.sxsap = HPEXT_DXSAP;

    switch (pb.rmp.proto.raw.rmp_type) {
      case RMP_BOOT_REQ:
	pb.rmp.proto.boot_repl.rmp_type = RMP_BOOT_REPL;
	pb.rmp.proto.boot_repl.rmp_retcode = 0;
	pb.rmp.proto.boot_repl.rmp_session = 0;
	pb.rmp.proto.boot_repl.rmp_version = RMP_VERSION;

	if (memcmp(&dest, &rmp_addr, sizeof (ether_addr)) == 0) {
	  pb.rmp.proto.boot_repl.rmp_flnmsize = 6;
	  strcpy(&pb.rmp.proto.boot_repl.rmp_flnm, "server");
	} else {
	  pb.rmp.proto.boot_repl.rmp_flnmsize = 4;
	  strcpy(&pb.rmp.proto.boot_repl.rmp_flnm, "BOOT");
	}

	packet.pktlen = 46;
	my_ether_write(&packet);
	break;

      case RMP_READ_REQ:
	size = pb.rmp.proto.read_req.rmp_size;

	pb.rmp.proto.read_repl.rmp_type = RMP_READ_REPL;
	pb.rmp.proto.read_repl.rmp_retcode = 0;

	if (ether_ntohost(hostname, *(ether_addr *)packet.src) != 0) {
	  fprintf(stderr, "%x:%x:%x:%x:%x:%x unknown\n",
	    packet.src[0], packet.src[1], packet.src[2],
	    packet.src[3], packet.src[4], packet.src[5]
	  );
	  break;
	}
	if ((hp = gethostbyname(hostname)) == NULL) {
	  fprintf(stderr, "%s: unknown\n", hostname);
	  break;
	}
	sprintf(boot_file, "%08X", *(long *)hp->h_addr);

	if ((fd_boot = open(boot_file, O_RDONLY, 0)) < 0) {
	  perror(boot_file);
	  break;
	}
        lseek(fd_boot,
	  *(unsigned long *)&pb.rmp.proto.read_req.rmp_offset,
	  SEEK_SET);
	read(fd_boot, &pb.rmp.proto.read_repl.rmp_data, size);
	close(fd_boot);

	packet.pktlen = size + 18;
	my_ether_write(&packet);
	break;
    }
  }
}
----- sun-rbootd.c --(end)--------------------------------------------------

----------------------------------------
YAMAMORI Takenori  yamamori@kt.rim.or.jp
----------------------------------------