#if 0 /* -*- mode: c; c-file-style: "linux"; tab-width: 8; -*- set -euf; trg=${0##*''/}; trg=${trg%.c}; test ! -e "$trg" || rm "$trg" test $# -ge 2 || { echo usage: $0 ndk-path netinclude-path [vc opts];exit 1; } ndk_path=$1 neti_path=$2; shift 2 case ${1-} in '') set x -O1; shift; esac set -x; exec ${CC:-vc} -c99 +aos68k -o "$trg" "$0" "$@" \ -I'$VBCC/targets/m68k-amigaos/include' \ -I"$ndk_path"/Include/include_h -I"$neti_path" # -lauto exit $? */ #endif // Last Modified: Tue 29 May 2018 20:49:04 +0300 too /* The best parts of this sw were taken from http://core.suckless.org/sdhcp (git://git.2f30.org/sdhcp.git), and then modified to work on Amiga. The file astart-dhcpconfig.c is initial version of this, for *nix. This program code can be executed as shell script on unix-like systems where "vc" cross-compiler for amiga has been built. This software has the same MIT/X Consortium License as sdhcp: (C) 2012 David Galos (galosd83 (at) students.rowan.edu) (C) 2014-2015 Hiltjo Posthuma (C) 2015 Michael Forney Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2017 Tomi Ollila -- too a"t iki piste fi */ #define FD_SETSIZE 32 /* now fd_set -type is only one (32bit) longword */ #include #define _TIME_T 1 // for e.g. amitcp/types.h not to redefine this #include #include #include #include #include #include #include //#include //#include //#include #include #include #include #include #include #include // amiga -- deliberately low-level... extern struct ExecBase * SysBase; extern struct DosLibrary * DOSBase; struct Library * SocketBase; #include #include #include #include #include #include #include #include #if 0 #include #include #include #endif typedef LONG socklen_t; // LONG for amiga, vbcc type checking #define ioctl(f, r, d) IoctlSocket((f), (r), (char*)(d)) // vbcc type checking // end amiga, part zwo // -- MIN() from sdhcp util.h -- // #define MIN(a,b) (((a)<(b))?(a):(b)) #define null ((void*)0) // (variable) block begin/end -- explicit liveness... #define BB { #define BE } #include static const char * get_net_fault(int errno) { struct TagItem taglist[2]; taglist[0].ti_Tag = SBTM_GETVAL(SBTC_ERRNOSTRPTR); taglist[0].ti_Data = errno; taglist[1].ti_Tag = TAG_END; SocketBaseTagList((void*)taglist); // XXX return (const char *)taglist[0].ti_Data; } static void xstrlcpy(char *dst, const char * src, size_t siz) { strncpy(dst, src, siz); dst[siz - 1] = '\0'; } #include static void die(const char * format, ...) { int err = errno; //va_list ap; //va_start(ap, format); VPrintf(format, (long*)((long)(&format) + 4));//, ap); //va_end(ap); if (format[strlen(format) - 1] == ':') Printf(" %s.\n", get_net_fault(err)); exit(1); } int xgettimeofday(struct timeval * tv, ...) { // simple made complex ?! int rv = -1; struct MsgPort *timer_msgport = CreateMsgPort(); struct timerequest * timer_ioreq = CreateIORequest(timer_msgport, sizeof (*timer_ioreq)); struct Library *TimerBase = null; if (timer_ioreq) { if (OpenDevice("timer.device", UNIT_VBLANK, (APTR) timer_ioreq, 0) == 0) { TimerBase = (APTR) timer_ioreq->tr_node.io_Device; } } if (TimerBase) { GetSysTime(tv); rv = 0; } if (TimerBase) CloseDevice((APTR) timer_ioreq); if (timer_ioreq) DeleteIORequest(timer_ioreq); // we trust creating msgport always worked DeleteMsgPort(timer_msgport); return rv; } time_t xtime(void) { struct timeval tv; (void)xgettimeofday(&tv); return tv.tv_sec; } // end extras typedef struct bootp { unsigned char op [1]; unsigned char htype [1]; unsigned char hlen [1]; unsigned char hops [1]; unsigned char xid [4]; unsigned char secs [2]; unsigned char flags [2]; unsigned char ciaddr [4]; unsigned char yiaddr [4]; unsigned char siaddr [4]; unsigned char giaddr [4]; unsigned char chaddr [16]; unsigned char sname [64]; unsigned char file [128]; unsigned char magic [4]; unsigned char optdata [312-4]; } Bootp; enum { DHCPdiscover = 1, DHCPoffer, DHCPrequest, DHCPdecline, DHCPack, DHCPnak, DHCPrelease, DHCPinform, Timeout = 200, Bootrequest = 1, Bootreply = 2, /* bootp flags */ Fbroadcast = 1 << 15, OBpad = 0, OBmask = 1, OBrouter = 3, OBnameserver = 5, OBdnsserver = 6, OBhostname = 12, OBdomain = 15, OBbaddr = 28, ODipaddr = 50, /* 0x32 */ ODlease = 51, ODoverload = 52, ODtype = 53, /* 0x35 */ ODserverid = 54, /* 0x36 */ ODparams = 55, /* 0x37 */ ODmessage = 56, ODmaxmsg = 57, ODrenewaltime = 58, ODrebindingtime = 59, ODvendorclass = 60, ODclientid = 61, /* 0x3d */ ODtftpserver = 66, ODbootfile = 67, OBend = 255, }; enum { Broadcast, Unicast}; Bootp bp; static const unsigned char magic[] = {99, 130, 83, 99}; /* conf */ static unsigned char xid[sizeof bp.xid]; static unsigned char hwaddr[16]; static time_t starttime; //static char * ifname; static unsigned char cid[16]; static unsigned char hostname[128]; static int sock; /* sav */ static unsigned char server[4]; static unsigned char client[4]; static unsigned char mask[4]; static unsigned char router[4]; static unsigned char dns[12]; static int dnslen; static char domain[80]; static uint32_t t1; //static char dflag = 1; /* change DNS in /etc/resolv.conf ? */ //static char iflag = 1; /* set IP ? */ static char rflag = 0; /* release at exit */ #define IP(a,b,c,d) (unsigned char[4]){a,b,c,d} static void hnput(unsigned char *dst, uint32_t src, size_t n) { for (unsigned int i = 0; n--; i++) dst[i] = (src >> (n * 8)) & 0xff; } static struct sockaddr * iptoaddr(struct sockaddr *ifaddr, unsigned char ip[4], int port) { struct sockaddr_in *in = (struct sockaddr_in *)ifaddr; in->sin_family = AF_INET; in->sin_port = htons(port); memcpy(&(in->sin_addr), ip, sizeof in->sin_addr); return ifaddr; } #define ssize_t int32_t // some problems with typedef'd ssize_t... /* sendto UDP wrapper */ static ssize_t udpsend(unsigned char ip[4], int fd, void *data, size_t n) { struct sockaddr addr; socklen_t addrlen = sizeof addr; ssize_t sent; iptoaddr(&addr, ip, 67); /* bootp server */ if ((sent = sendto(fd, data, n, 0, &addr, addrlen)) == -1) die("sendto:"); return sent; } /* recvfrom UDP wrapper */ static ssize_t udprecv(unsigned char ip[4], int fd, void *data, size_t n) { struct sockaddr addr; socklen_t addrlen = sizeof addr; ssize_t r; iptoaddr(&addr, ip, 68); /* bootp client */ if ((r = recvfrom(fd, data, n, 0, &addr, &addrlen)) == -1) die("recvfrom:"); return r; } union { char name[IFNAMSIZ]; struct ifreq ifr; struct ifaliasreq ifra; } ifrs; #define IFR ifrs.ifr #define IFRA ifrs.ifra static void _xioctl(int fd, ULONG request, const char *rn, void * p) { if (IoctlSocket(fd, request, (char *)p) < 0) die("ioctl(%ls):", rn); } #define xioctl(fd, request, p) _xioctl(fd, request, #request, p) int isock; static void handle_brhost_route(int on) { struct ortentry rte = { //.rt_flags = RTF_UP | RTF_HOST, // compiler failed with this ! .rt_dst.sa_family = AF_INET, .rt_dst.sa_len = sizeof (rte.rt_dst), /* not sure if these are necessary */ .rt_gateway.sa_family = AF_INET, .rt_gateway.sa_len = sizeof (rte.rt_gateway) }; rte.rt_flags = RTF_UP | RTF_HOST; ((struct sockaddr_in *)&rte.rt_dst)->sin_addr.s_addr = 0xffffffff; //((struct sockaddr_in *)&rte.rt_gateway)->sin_addr.s_addr = 0; // XXX should report failure (if ever) so users won't be so confused... ioctl(isock, on? SIOCADDRT: SIOCDELRT, (char *)&rte); } static uint32_t prev_ip = 1; // not zero... and 0.1 is invalid static void may_delete_brhost_route(void) { if (prev_ip != 0) return; isock = socket(AF_INET, SOCK_DGRAM, 0); if (isock < 0) return; handle_brhost_route(0); CloseSocket(isock); } static void setflags(void) { xioctl(isock, SIOCGIFFLAGS, &IFR); //printf("%s %lx\n", IFR.ifr_name, IFR.ifr_flags); IFR.ifr_flags |= IFF_UP | IFF_RUNNING | IFF_BROADCAST; xioctl(isock, SIOCSIFFLAGS, &IFR); //printf("%s %lx\n", IFR.ifr_name, IFR.ifr_flags); } static void setip0(uint32_t ip, uint32_t mask, uint32_t gw) { static uint32_t prev_mask = 0xffffffff; static uint32_t prev_gw = 0xffffffff; // if new reply is the same as previous, just return if (prev_ip == ip && prev_mask == mask && prev_gw == gw) return; #define DIP(a) \ ((uint8_t*)&a)[0],((uint8_t*)&a)[1],((uint8_t*)&a)[2],((uint8_t*)&a)[3] Printf("ip: %lu.%lu.%lu.%lu, mask: %lu.%lu.%lu.%lu, " "gw: %lu.%lu.%lu.%lu\n", DIP(ip), DIP(mask), DIP(gw)); // clear ifrs, keep (current) interface name memset((char *)&ifrs + sizeof ifrs.name, 0, sizeof ifrs - sizeof ifrs.name); /* * Delete the old configuration */ IFR.ifr_addr.sa_family = AF_INET; IFR.ifr_addr.sa_len = sizeof(IFR.ifr_addr); ((struct sockaddr_in *)&IFR.ifr_addr)->sin_addr.s_addr = prev_ip; if (ioctl(isock, SIOCDIFADDR, (char *)&IFR) < 0) { if (errno != EADDRNOTAVAIL) { /* no previous address ? */ syslog(LOG_ERR, "iface_config: SIOCDIFADDR: %m"); prev_ip = 0; return; } } /* * Build request to add new config */ /* address */ IFRA.ifra_addr.sa_family = AF_INET; IFRA.ifra_addr.sa_len = sizeof (IFRA.ifra_addr); ((struct sockaddr_in *)&IFRA.ifra_addr)->sin_addr.s_addr = ip; /* netmask */ if (mask != INADDR_ANY) { /* leave 'empty' if not avail */ IFRA.ifra_mask.sa_family = 0; /* no family for masks */ IFRA.ifra_mask.sa_len = sizeof (IFRA.ifra_mask); ((struct sockaddr_in *)&IFRA.ifra_mask)->sin_addr.s_addr = mask; } if (ip == INADDR_ANY) { IFRA.ifra_broadaddr.sa_family = AF_INET; IFRA.ifra_broadaddr.sa_len = sizeof (IFRA.ifra_broadaddr); ((struct sockaddr_in *)&IFRA.ifra_broadaddr)->sin_addr.s_addr = 0xffffffff; } if (ioctl(isock, SIOCAIFADDR, (char *)&IFRA) < 0) { syslog(LOG_ERR, "iface_config: SIOCAIFADDR: %m"); prev_ip = 0; return; } #if 0 // with this netmask is 0x00000000 instead of 0xff000000 // but still packets to 255.255.255.255 gets 'no route to host' if (mask == INADDR_ANY) { IFR.ifr_addr.sa_family = AF_INET; IFR.ifr_addr.sa_len = sizeof (IFR.ifr_addr); ((struct sockaddr_in *)&IFR.ifr_addr)->sin_addr.s_addr = 0; // XXX report failure ioctl(isock, SIOCSIFNETMASK, &IFR); } #endif #if 1 // ... so ... // route to 255.255.255.255 when initial ip 0... if (ip == 0) handle_brhost_route(1); else if (prev_ip == 0) handle_brhost_route(0); #endif struct ortentry rte = { .rt_flags = RTF_UP | RTF_GATEWAY }; rte.rt_dst.sa_family = AF_INET; rte.rt_dst.sa_len = sizeof (rte.rt_dst); rte.rt_gateway.sa_family = AF_INET; rte.rt_gateway.sa_len = sizeof (rte.rt_gateway); ((struct sockaddr_in *)&rte.rt_gateway)->sin_addr.s_addr = gw; // ignore failure ioctl(isock, SIOCDELRT, &rte); if (gw != INADDR_ANY) { if (ioctl(isock, SIOCADDRT, &rte) < 0) { syslog(LOG_ERR, "route_add: SIOCADDRT: %m"); return; } } prev_ip = ip; prev_mask = mask; prev_gw = gw; } static void setip(uint8_t * ip_s, uint8_t * mask_s, uint8_t * gateway_s) { isock = socket(AF_INET, SOCK_DGRAM, 0); if (isock < 0) die("socket:"); // we expect these to be aligned (remember to test using 68000 code) uint32_t ip = *(uint32_t*)ip_s; uint32_t mask = *(uint32_t*)mask_s; uint32_t gw = *(uint32_t*)gateway_s; setip0(ip, mask, gw); CloseSocket(isock); } static void lookup_hwaddr(void); static void init_if(void) { isock = socket(AF_INET, SOCK_DGRAM, 0); if (isock < 0) die("socket:"); //xstrlcpy(IFR.ifr_name, ifname, sizeof (IFR.ifr_name)); if (ioctl(isock, SIOCGIFADDR, (caddr_t)&IFR) < 0) { if (errno != EADDRNOTAVAIL) die("ioctl (SIOCGIFADDR):"); } lookup_hwaddr(); prev_ip = ((struct sockaddr_in *)&IFR.ifr_addr)->sin_addr.s_addr; if (prev_ip == 0) setip0(0, 0, 0); // remember: 0 == INADDR_ANY setflags(); CloseSocket(isock); } #if 0 // NOT USED -- not needed /* * Send a command to AMITCP rexx port * * Returns an DOS style success code (0 - OK, 5, 10, 20 - errors) */ LONG amitcp_rexx_command(const char * fmt, ...) { static const STRPTR AMITCP = "AMITCP"; char buf[256]; va_list ap; struct MsgPort *port; /* our reply port */ struct MsgPort *AmiTCP_Port; struct RexxMsg *rmsg; LONG rc = 20; /* fail */ struct Library * RexxSysBase = OpenLibrary("rexxsyslib.library", 0L); if (RexxSysBase == null) { PrintFault(IoErr(), "OpenLibrary(rexxsyslib.library)"); return 20; } /* * Format the command to buf */ va_start(ap, fmt); vsnprintf(buf, sizeof buf, fmt, ap); va_end(ap); Printf("AmiTCP ARexx Command: %s\n", buf); /* DEBUGGING */ /* * Create reply port and the rexx message */ if (port = CreateMsgPort()) { if (rmsg = CreateRexxMsg(port, null, AMITCP)) { rmsg->rm_Action = RXCOMM; #if 0 /* not yet */ rmsg->rm_Action |= RXFF_RESULT; /* return result string */ #endif rmsg->rm_Args[0] = (STRPTR)buf; if (FillRexxMsg(rmsg, 1, 0)) { /* send the message */ /* * We need to find the AmiTCP/IP ARexx port and this * must be done in a Forbid() */ Forbid(); if (AmiTCP_Port = FindPort(AMITCP)) { /* * We found the port, so put the message */ PutMsg(AmiTCP_Port, (struct Message *)rmsg); Permit(); /* * Succeeded, wait for reply */ do { WaitPort(port); } while (GetMsg(port) != (struct Message *)rmsg); /* * extract return code */ rc = rmsg->rm_Result1; } else Permit(); ClearRexxMsg(rmsg, 1); } DeleteRexxMsg(rmsg); } DeleteMsgPort(port); } CloseLibrary(RexxSysBase); /* * Should get the result string below */ if (rc != 0) Printf("AmiTCP/IP ARexx command \"%s\" failed: %ld\n", buf, rc); return (rc); } #endif /* 0 */ const char resolv_conf[] = "AmiTCP:db/resolv.conf"; #define _WriteCS(f, b) Write(f, b, sizeof (b) - 1) static void setdns(unsigned char * dns, int dnslen, unsigned char * domain) { if (dnslen < 4) return; dnslen -= 3; int file = Open(resolv_conf, MODE_NEWFILE); if (file == 0) return; _WriteCS(file, "; This file is built dynamically - do not edit\n"); _WriteCS(file, "; Name Servers\n"); for (int i = 0; i < dnslen; i+= 4) { FPrintf(file, "NAMESERVER %s\n", Inet_NtoA(*(ULONG*)(dns + i))); } if (domain[0]) FPrintf(file, "; Domain Name\nDOMAIN %s\n", domain); Close(file); #if 0 amitcp_rexx_command("RESET RESOLV"); for (int i = 0; i < dnslen; i+= 4) { amitcp_rexx_command("ADD START NAMESERVER %s", Inet_NtoA(*(ULONG*)(dns + i))); } #endif #if 0 while (dnslen > 0) { fprintf(stderr, "dns: %d.%d.%d.%d (unset)\n", (int)dns[0], (int)dns[1], (int)dns[2], (int)dns[3]); dns += 4; dnslen -= 4; } #endif } static int optget(Bootp *bp, void *data, int opt, int n) { unsigned char *p = bp->optdata; unsigned char *top = ((unsigned char *)bp) + sizeof *bp; int code, len; int rlen = 0; while (p < top) { code = *p++; if (code == OBpad) continue; if (code == OBend || p == top) break; len = *p++; if (len > top - p) break; if (code == opt) { rlen = MIN(len, n); memcpy(data, p, rlen); break; } p += len; } return rlen; } static unsigned char * optput(unsigned char *p, int opt, unsigned char *data, size_t len) { *p++ = opt; *p++ = (unsigned char)len; memcpy(p, data, len); return p + len; } static unsigned char * hnoptput(unsigned char *p, int opt, uint32_t data, size_t len) { *p++ = opt; *p++ = (unsigned char)len; hnput(p, data, len); return p + len; } //static const char params_request[] = // { 55, 4, 1, 3, 15, 6 }; // subnet, router, domain, dns //static const char params_request[] = // { 55, 5, 1, 3, 15, 6, 12 }; // subnet, router, domain, dns, hostname // params_request[1] = 4 set later if not hostname[0] static char params_request[7] = { 55, 5, 1, 3, 15, 6, 12 }; // subnet, router, domain, dns, hostname static void dhcpsend(int type, int how) { unsigned char *ip, *p; memset(&bp, 0, sizeof bp); hnput(bp.op, Bootrequest, 1); hnput(bp.htype, 1, 1); hnput(bp.hlen, 6, 1); memcpy(bp.xid, xid, sizeof xid); hnput(bp.flags, Fbroadcast, sizeof bp.flags); hnput(bp.secs, xtime() - starttime, sizeof bp.secs); memcpy(bp.magic, magic, sizeof bp.magic); memcpy(bp.chaddr, hwaddr, sizeof bp.chaddr); p = bp.optdata; p = hnoptput(p, ODtype, type, 1); if (hostname[0]) p = optput(p, OBhostname, hostname, strlen(hostname)); if (cid[1]) { if (cid[0] == 0) // set from command line p = optput(p, ODclientid, cid, strlen(cid + 1) + 1); else // kinda hax. set in lookup_hwaddr() p = optput(p, ODclientid, cid + 1, cid[0]); } int pr_len = params_request[1] + 2; switch (type) { case DHCPdiscover: memcpy(p, params_request, pr_len); p += pr_len; break; case DHCPrequest: /* memcpy(bp.ciaddr, client, sizeof bp.ciaddr); */ p = hnoptput(p, ODlease, t1, sizeof t1); p = optput(p, ODipaddr, client, sizeof client); p = optput(p, ODserverid, server, sizeof server); memcpy(p, params_request, pr_len); p += pr_len; break; case DHCPrelease: memcpy(bp.ciaddr, client, sizeof client); p = optput(p, ODipaddr, client, sizeof client); p = optput(p, ODserverid, server, sizeof server); break; } *p++ = OBend; ip = (how == Broadcast) ? IP(255, 255, 255, 255) : server; udpsend(ip, sock, &bp, p - (unsigned char *)&bp); } #define select(n, r, w, e, t) WaitSelect(n, r, w, e, t, null) static int wait_secs = 0; static int dhcprecv(void) { unsigned char type; struct timeval timeout = { wait_secs, 0 }; ULONG sigs = SIGBREAKF_CTRL_F; // to signal dhcprequest manually fd_set readfds = { 0 }; //FD_ZERO(&readfds); FD_SET(sock, &readfds); if (WaitSelect(sock + 1, &readfds, null, null, &timeout, &sigs) == 0) return Timeout; udprecv(IP(255, 255, 255, 255), sock, &bp, sizeof bp); optget(&bp, &type, ODtype, sizeof type); return type; } static void acceptlease(void) { /*if (iflag)*/ setip(client, mask, router); /*if (dflag)*/ setdns(dns, dnslen, domain); wait_secs = t1; //printf("wait_secs: %d\n", wait_secs); } static void portpong(void) { struct MsgPort * port = CreateMsgPort(); if (port == null) return; port->mp_Node.ln_Name = "DHCPCONFIG"; port->mp_Node.ln_Pri = 0; AddPort(port); struct timeval timeout = { 2, 0 }; select(0, NULL, null, null, &timeout); RemPort(port); struct Message * msg; while ((msg = GetMsg(port)) != null) ReplyMsg(msg); DeleteMsgPort(port); if (t1 > 2) wait_secs = t1 - 2; } unsigned char waits[] = { 1, 1, 2, 3, 4, 5, 7, 10 }; static void run(void) { int first = 1; int cnt = 0; Init: if (cnt < sizeof waits) wait_secs = waits[cnt++]; else wait_secs = 15; dhcpsend(DHCPdiscover, Broadcast); goto Selecting; Selecting: switch (dhcprecv()) { case DHCPoffer: memcpy(client, bp.yiaddr, sizeof client); optget(&bp, server, ODserverid, sizeof server); optget(&bp, mask, OBmask, sizeof mask); optget(&bp, router, OBrouter, sizeof router); dnslen = optget(&bp, dns, OBdnsserver, sizeof dns); optget(&bp, domain, OBdomain, sizeof domain); optget(&bp, &t1, ODlease, sizeof t1); // t1 = ntohl(t1); t1 used elsewhere w/o this and we have BE dhcpsend(DHCPrequest, Broadcast); goto Requesting; case Timeout: goto Init; default: goto Selecting; } Requesting: wait_secs = 15; switch (dhcprecv()) { case DHCPoffer: goto Requesting; /* ignore other offers. */ case DHCPack: acceptlease(); goto Bound; default: goto Init; } Bound: rflag = 1; cnt = 0; if (first) { //fputs("Congrats! You should be on the 'net.\n", stdout); first = 0; portpong(); } switch (dhcprecv()) { case DHCPoffer: case DHCPack: case DHCPnak: goto Bound; /* discard offer, ACK or NAK */ case Timeout: dhcpsend(DHCPrequest, Unicast); goto Renewing; } Renewing: wait_secs = 15; switch (dhcprecv()) { case DHCPack: acceptlease(); goto Bound; case DHCPnak: goto Init; #if 0 case Timeout: dhcpsend(DHCPrequest, Broadcast); goto Rebinding; #endif default: dhcpsend(DHCPrequest, Broadcast); goto Renewing; } #if 0 Rebinding: switch (dhcprecv()) { case DHCPnak: /* lease expired */ goto Init; case DHCPack: acceptlease(); goto Bound; } #endif } static void cleanexit(void) { if (SocketBase != null) { if (rflag) dhcpsend(DHCPrelease, Unicast); may_delete_brhost_route(); CloseLibrary(SocketBase); } //CloseLibrary((struct Library *)DOSBase); } static void lookup_hwaddr(void) { struct ifconf ifconf; struct ifreq ibuf[16]; int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) die("socket:"); ifconf.ifc_len = sizeof (ibuf); ifconf.ifc_buf = (caddr_t)ibuf; if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) die("ioctl: (SIOCGIFCONF):"); CloseSocket(s); struct ifreq *ifrp, *ifend; ifrp = (struct ifreq *) ifconf.ifc_buf; ifend = (struct ifreq *) ((char *) ifconf.ifc_buf + ifconf.ifc_len); while (ifrp < ifend) { //printf("ifname: %s\n", ifrp->ifr_name); /* Look for interface */ if (ifrp->ifr_addr.sa_family == AF_LINK) { if (strcmp(ifrp->ifr_name, IFR.ifr_name) == 0) { struct sockaddr_dl * sdl = (struct sockaddr_dl*)&ifrp->ifr_addr; uint8_t * s = sdl->sdl_data + sdl->sdl_nlen; int l = sdl->sdl_alen > 16? 16: sdl->sdl_alen; memset(hwaddr, 0, sizeof hwaddr); memcpy(hwaddr, s, l); if (cid[1] == 0) { // this starts to feel a bit // dangerous -- 2018-05-24 too if (l > 14) l = 14; cid[0] = l + 1; cid[1] = 0x01; memcpy(cid + 2, s, l); } return; } } int n = ifrp->ifr_addr.sa_len + sizeof (ifrp->ifr_name); if (n < sizeof (*ifrp)) n = sizeof (*ifrp); ifrp = (struct ifreq *) ((char *) ifrp + n); } die("Cannot find interface '%s'\n", IFR.ifr_name); } static int zstrcasecmp(const char * a, const char * b) { while (*a != 0) { /* Note: *a + 32 never 0 in our comparisons... */ if (*a != *b && *a + 32 != *b) return 1; *a++; *b++; } return !!(*b); } const char provider_conf[] = "AmiTCP:db/provider.conf"; static int readconff(int chk) { int file = Open(provider_conf, MODE_OLDFILE); if (file == 0) { // no provider.conf. base fate whether we know interface name if (IFR.ifr_name[0]) return 0; else return RETURN_WARN; } int old_fh = SelectInput(file); int state = 0; int rv = RETURN_WARN; while (1) { char line[80]; int i = ReadItem(line, sizeof line, null); int c = FGetC(file); if (c < 0) break; //printf("%2d %2d %2d %2d %s\n", i, c, state, rv, line); if (i == 0) state = 0; else UnGetC(file, c); if (i != 1) continue; switch (state) { case 0: if (!zstrcasecmp(line,"usedhcp")) {state = 1; break;} if (!zstrcasecmp(line,"usebootp")) {state = 2; break;} if (!zstrcasecmp(line,"ipdynamic")) {state = 3; break;} if (!zstrcasecmp(line,"ipaddr")) {state = 4; break;} if (!zstrcasecmp(line,"interface")) {state = 5; break;} if (!zstrcasecmp(line,"dhcpid")) {state = 6; break;} state = 99; break; case 1: // UseDHCP setting overrides everything if (line[0] == '1') rv = 0; else rv = RETURN_WARN; if (chk) goto out; break; case 2: if (line[0] == '1') rv = RETURN_WARN; else rv = 0; state = 99; break; case 3: if (line[0] == '1') rv = 0; else rv = RETURN_WARN; state = 99; break; case 4: BB; int addr = inet_addr(line); //printf("=== %x\n", addr); if (addr == 0 || addr == -1) rv = 0; else rv = RETURN_WARN; state = 99; BE; break; case 5: if (IFR.ifr_name[0] == 0) xstrlcpy(IFR.ifr_name, line, sizeof (IFR.ifr_name)); state = 99; break; case 6: if (hostname[0] == 0) xstrlcpy(hostname, line, sizeof hostname); state = 99; break; } } out: SelectInput(old_fh); Close(file); //printf("--- %d\n", rv); return rv; } int main(int argc, char *argv[]) { //SysBase = *(struct ExecBase **)4; //DOSBase = (struct DosLibrary*)OpenLibrary("dos.library", 37L); //if (DOSBase == null) exit(1); atexit(cleanexit); //printf(""); // did some vbcc magic and guru meditations stopped :O BB; char do_check = 0; int i; for (i = 1; i < argc; i++) { if (zstrcasecmp(argv[i], "debug") == 0) continue; // ignored /* else */ if (zstrcasecmp(argv[i], "check") == 0) { do_check = 1; continue; } /* else */ break; } if (i < argc) { if (strlen(argv[i]) >= sizeof ifrs.name) die("'%s': device name too long\n", argv[i]); xstrlcpy(IFR.ifr_name, argv[i++], sizeof (IFR.ifr_name)); } if (i < argc) xstrlcpy(hostname, argv[i++], sizeof hostname); if (i < argc) xstrlcpy(cid + 1, argv[i], sizeof(cid) - 1); /* client-id */ SocketBase = OpenLibrary("bsdsocket.library", 4L); if (!SocketBase) die("Cannot open 'bsdsocket.library'. Start AmiTCP/IP.\n"); SetErrnoPtr(&errno, sizeof errno); if (do_check) return readconff(1); else readconff(0); BE; if (IFR.ifr_name[0] == 0) die("Usage: %s device [hostname] [cid]\n", argv[0]); if (hostname[0] == 0) params_request[1] = 4; init_if(); if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) die("socket:"); BB; int bcast = 1; if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &bcast,sizeof bcast) < 0) die("setsockopt:"); BE; BB; struct sockaddr addr; // bind this to the address... //iptoaddr(&addr, IP(255, 255, 255, 255), 68); //iptoaddr(&addr, IP(169, 254, 37, 175), 68); iptoaddr(&addr, IP(0, 0, 0, 0), 68); if (bind(sock, (void*)&addr, sizeof addr) != 0) die("bind:"); BE; BB; struct timeval tv; xgettimeofday(&tv); //printf("%lu %lu\n", tv.tv_secs, tv.tv_micro); tv.tv_secs ^= (tv.tv_micro * 111); memcpy(xid, &tv.tv_secs, sizeof xid); BE; starttime = xtime(); run(); return 0; }