From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564438613493.19141255247325; Tue, 27 Jun 2017 04:53:58 -0700 (PDT) Received: from localhost ([::1]:51860 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp49-00049Y-37 for importer@patchew.org; Tue, 27 Jun 2017 07:53:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54750) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPoz0-0007xN-Vx for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPoyr-0003dY-Mp for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:56596) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPoyr-0003dF-6f for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:29 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2AE995AFC8; Tue, 27 Jun 2017 11:48:28 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0AF7653CE3; Tue, 27 Jun 2017 11:48:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 2AE995AFC8 Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 2AE995AFC8 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:07 +0200 Message-Id: <1498564100-10045-2-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 27 Jun 2017 11:48:28 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 01/14] pc-bios/s390-ccw: Add the libc from the SLOF firmware X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" To be able to use some more advanced libc functions in the s390-ccw firmware, like printf() and malloc(), we need a better libc here. This patch adds the C library from the SLOF firmware (taken from the SLOF commit ID 62674aabe20612a9786fa03e87cf6916ba97a99a). The files are copied without modifications here and will be adapted for the s390-ccw firmware by the next patch. I just removed the getopt() and scanf()-like functions from the libc since we likely do not need them in the s390-ccw firmware. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libc/Makefile | 61 ++++++ pc-bios/s390-ccw/libc/README.txt | 49 +++++ pc-bios/s390-ccw/libc/ctype/Makefile.inc | 20 ++ pc-bios/s390-ccw/libc/ctype/isdigit.c | 25 +++ pc-bios/s390-ccw/libc/ctype/isprint.c | 18 ++ pc-bios/s390-ccw/libc/ctype/isspace.c | 29 +++ pc-bios/s390-ccw/libc/ctype/isxdigit.c | 21 ++ pc-bios/s390-ccw/libc/ctype/tolower.c | 18 ++ pc-bios/s390-ccw/libc/ctype/toupper.c | 21 ++ pc-bios/s390-ccw/libc/include/ctype.h | 24 +++ pc-bios/s390-ccw/libc/include/errno.h | 34 ++++ pc-bios/s390-ccw/libc/include/limits.h | 32 ++++ pc-bios/s390-ccw/libc/include/stdarg.h | 22 +++ pc-bios/s390-ccw/libc/include/stdbool.h | 20 ++ pc-bios/s390-ccw/libc/include/stddef.h | 25 +++ pc-bios/s390-ccw/libc/include/stdint.h | 28 +++ pc-bios/s390-ccw/libc/include/stdio.h | 63 ++++++ pc-bios/s390-ccw/libc/include/stdlib.h | 34 ++++ pc-bios/s390-ccw/libc/include/string.h | 37 ++++ pc-bios/s390-ccw/libc/include/sys/socket.h | 53 +++++ pc-bios/s390-ccw/libc/include/unistd.h | 28 +++ pc-bios/s390-ccw/libc/stdio/Makefile.inc | 23 +++ pc-bios/s390-ccw/libc/stdio/fileno.c | 19 ++ pc-bios/s390-ccw/libc/stdio/fprintf.c | 26 +++ pc-bios/s390-ccw/libc/stdio/printf.c | 27 +++ pc-bios/s390-ccw/libc/stdio/putc.c | 25 +++ pc-bios/s390-ccw/libc/stdio/putchar.c | 21 ++ pc-bios/s390-ccw/libc/stdio/puts.c | 28 +++ pc-bios/s390-ccw/libc/stdio/setvbuf.c | 28 +++ pc-bios/s390-ccw/libc/stdio/sprintf.c | 30 +++ pc-bios/s390-ccw/libc/stdio/stdchnls.c | 23 +++ pc-bios/s390-ccw/libc/stdio/vfprintf.c | 27 +++ pc-bios/s390-ccw/libc/stdio/vsnprintf.c | 298 +++++++++++++++++++++++++= ++++ pc-bios/s390-ccw/libc/stdio/vsprintf.c | 19 ++ pc-bios/s390-ccw/libc/stdlib/Makefile.inc | 22 +++ pc-bios/s390-ccw/libc/stdlib/atoi.c | 18 ++ pc-bios/s390-ccw/libc/stdlib/atol.c | 18 ++ pc-bios/s390-ccw/libc/stdlib/error.c | 15 ++ pc-bios/s390-ccw/libc/stdlib/free.c | 26 +++ pc-bios/s390-ccw/libc/stdlib/malloc.c | 157 +++++++++++++++ pc-bios/s390-ccw/libc/stdlib/malloc_defs.h | 16 ++ pc-bios/s390-ccw/libc/stdlib/memalign.c | 26 +++ pc-bios/s390-ccw/libc/stdlib/rand.c | 29 +++ pc-bios/s390-ccw/libc/stdlib/realloc.c | 40 ++++ pc-bios/s390-ccw/libc/stdlib/strtol.c | 115 +++++++++++ pc-bios/s390-ccw/libc/stdlib/strtoul.c | 105 ++++++++++ pc-bios/s390-ccw/libc/string/Makefile.inc | 22 +++ pc-bios/s390-ccw/libc/string/memchr.c | 29 +++ pc-bios/s390-ccw/libc/string/memcmp.c | 30 +++ pc-bios/s390-ccw/libc/string/memcpy.c | 27 +++ pc-bios/s390-ccw/libc/string/memmove.c | 42 ++++ pc-bios/s390-ccw/libc/string/memset.c | 25 +++ pc-bios/s390-ccw/libc/string/strcasecmp.c | 28 +++ pc-bios/s390-ccw/libc/string/strcat.c | 24 +++ pc-bios/s390-ccw/libc/string/strchr.c | 28 +++ pc-bios/s390-ccw/libc/string/strcmp.c | 28 +++ pc-bios/s390-ccw/libc/string/strcpy.c | 25 +++ pc-bios/s390-ccw/libc/string/strlen.c | 27 +++ pc-bios/s390-ccw/libc/string/strncasecmp.c | 32 ++++ pc-bios/s390-ccw/libc/string/strncmp.c | 31 +++ pc-bios/s390-ccw/libc/string/strncpy.c | 33 ++++ pc-bios/s390-ccw/libc/string/strstr.c | 37 ++++ pc-bios/s390-ccw/libc/string/strtok.c | 45 +++++ 63 files changed, 2356 insertions(+) create mode 100644 pc-bios/s390-ccw/libc/Makefile create mode 100644 pc-bios/s390-ccw/libc/README.txt create mode 100644 pc-bios/s390-ccw/libc/ctype/Makefile.inc create mode 100644 pc-bios/s390-ccw/libc/ctype/isdigit.c create mode 100644 pc-bios/s390-ccw/libc/ctype/isprint.c create mode 100644 pc-bios/s390-ccw/libc/ctype/isspace.c create mode 100644 pc-bios/s390-ccw/libc/ctype/isxdigit.c create mode 100644 pc-bios/s390-ccw/libc/ctype/tolower.c create mode 100644 pc-bios/s390-ccw/libc/ctype/toupper.c create mode 100644 pc-bios/s390-ccw/libc/include/ctype.h create mode 100644 pc-bios/s390-ccw/libc/include/errno.h create mode 100644 pc-bios/s390-ccw/libc/include/limits.h create mode 100644 pc-bios/s390-ccw/libc/include/stdarg.h create mode 100644 pc-bios/s390-ccw/libc/include/stdbool.h create mode 100644 pc-bios/s390-ccw/libc/include/stddef.h create mode 100644 pc-bios/s390-ccw/libc/include/stdint.h create mode 100644 pc-bios/s390-ccw/libc/include/stdio.h create mode 100644 pc-bios/s390-ccw/libc/include/stdlib.h create mode 100644 pc-bios/s390-ccw/libc/include/string.h create mode 100644 pc-bios/s390-ccw/libc/include/sys/socket.h create mode 100644 pc-bios/s390-ccw/libc/include/unistd.h create mode 100644 pc-bios/s390-ccw/libc/stdio/Makefile.inc create mode 100644 pc-bios/s390-ccw/libc/stdio/fileno.c create mode 100644 pc-bios/s390-ccw/libc/stdio/fprintf.c create mode 100644 pc-bios/s390-ccw/libc/stdio/printf.c create mode 100644 pc-bios/s390-ccw/libc/stdio/putc.c create mode 100644 pc-bios/s390-ccw/libc/stdio/putchar.c create mode 100644 pc-bios/s390-ccw/libc/stdio/puts.c create mode 100644 pc-bios/s390-ccw/libc/stdio/setvbuf.c create mode 100644 pc-bios/s390-ccw/libc/stdio/sprintf.c create mode 100644 pc-bios/s390-ccw/libc/stdio/stdchnls.c create mode 100644 pc-bios/s390-ccw/libc/stdio/vfprintf.c create mode 100644 pc-bios/s390-ccw/libc/stdio/vsnprintf.c create mode 100644 pc-bios/s390-ccw/libc/stdio/vsprintf.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/Makefile.inc create mode 100644 pc-bios/s390-ccw/libc/stdlib/atoi.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/atol.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/error.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/free.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/malloc.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/malloc_defs.h create mode 100644 pc-bios/s390-ccw/libc/stdlib/memalign.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/rand.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/realloc.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/strtol.c create mode 100644 pc-bios/s390-ccw/libc/stdlib/strtoul.c create mode 100644 pc-bios/s390-ccw/libc/string/Makefile.inc create mode 100644 pc-bios/s390-ccw/libc/string/memchr.c create mode 100644 pc-bios/s390-ccw/libc/string/memcmp.c create mode 100644 pc-bios/s390-ccw/libc/string/memcpy.c create mode 100644 pc-bios/s390-ccw/libc/string/memmove.c create mode 100644 pc-bios/s390-ccw/libc/string/memset.c create mode 100644 pc-bios/s390-ccw/libc/string/strcasecmp.c create mode 100644 pc-bios/s390-ccw/libc/string/strcat.c create mode 100644 pc-bios/s390-ccw/libc/string/strchr.c create mode 100644 pc-bios/s390-ccw/libc/string/strcmp.c create mode 100644 pc-bios/s390-ccw/libc/string/strcpy.c create mode 100644 pc-bios/s390-ccw/libc/string/strlen.c create mode 100644 pc-bios/s390-ccw/libc/string/strncasecmp.c create mode 100644 pc-bios/s390-ccw/libc/string/strncmp.c create mode 100644 pc-bios/s390-ccw/libc/string/strncpy.c create mode 100644 pc-bios/s390-ccw/libc/string/strstr.c create mode 100644 pc-bios/s390-ccw/libc/string/strtok.c diff --git a/pc-bios/s390-ccw/libc/Makefile b/pc-bios/s390-ccw/libc/Makefile new file mode 100644 index 0000000..0c762ec --- /dev/null +++ b/pc-bios/s390-ccw/libc/Makefile @@ -0,0 +1,61 @@ +# ************************************************************************= ***** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ************************************************************************= ****/ + +TOPCMNDIR ?=3D ../.. + +LIBCCMNDIR =3D $(shell pwd) +STRINGCMNDIR =3D $(LIBCCMNDIR)/string +CTYPECMNDIR =3D $(LIBCCMNDIR)/ctype +STDLIBCMNDIR =3D $(LIBCCMNDIR)/stdlib +STDIOCMNDIR =3D $(LIBCCMNDIR)/stdio +GETOPTCMNDIR =3D $(LIBCCMNDIR)/getopt + +include $(TOPCMNDIR)/make.rules + + +CPPFLAGS =3D -I$(LIBCCMNDIR)/include +LDFLAGS=3D -nostdlib + +TARGET =3D ../libc.a + + +all: $(TARGET) + +# Use the following target to build a native version of the lib +# (for example for debugging purposes): +native: + $(MAKE) CROSS=3D"" CC=3D$(HOSTCC) NATIVEBUILD=3D1 + + +include $(STRINGCMNDIR)/Makefile.inc +include $(CTYPECMNDIR)/Makefile.inc +include $(STDLIBCMNDIR)/Makefile.inc +include $(STDIOCMNDIR)/Makefile.inc +include $(GETOPTCMNDIR)/Makefile.inc + +OBJS =3D $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) $(GETOP= T_OBJS) + +ifneq ($(NATIVEBUILD),1) +# These parts of the libc use assembler, so they can only be compiled when +# we are _not_ building a native version. +endif + + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean diff --git a/pc-bios/s390-ccw/libc/README.txt b/pc-bios/s390-ccw/libc/READM= E.txt new file mode 100644 index 0000000..eaafdf4 --- /dev/null +++ b/pc-bios/s390-ccw/libc/README.txt @@ -0,0 +1,49 @@ + + Standard C library for the SLOF firmware project + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +To use this library, link your target against the "libc.a" archive. + +However, there are some prerequisites before you can use certain parts of = the +library: + +1) If you want to use malloc() and the like, you have to supply an impleme= n- + tation of sbrk() in your own code. malloc() uses sbrk() to get new, free + memory regions. + =20 + Prototype: void *sbrk(int incr); + Description: sbrk() increments the available data space by incr bytes a= nd + returns a pointer to the start of the new area. + =20 + See the man-page of sbrk for details about this function. + +2) Before you can use the stdio output functions like printf(), puts() and= the + like, you have to provide a standard write() function in your code. + printf() and the like use write() to print out the strings to the stand= ard + output. + + Prototype: ssize_t write(int fd, const void *buf, size_t cnt); + Description: Write cnt byte from the buffer buf to the stream associated + with the file descriptor fd. + + The stdio functions will print their output to the stdout channel which= is + assigned with the file descriptor 1 by default. Note that the stdio + functions will not use open() before calling write(), so if the stdout + cannel needs to be opened first, you should do that in your start-up co= de + before using the libc functions for the first time. + =20 +3) Before you can use the stdio input functions like scanf() and the + like, you have to provide a standard read() function in your code. + scanf() and the like use read() to get the characters from the standard + input. + + Prototype: ssize_t read(int fd, void *buf, size_t cnt); + Description: Read cnt byte from the stream associated with the file + descriptor fd and put them into the buffer buf. + + The stdio functions will get their input from the stdin channel which is + assigned with the file descriptor 0 by default. Note that the stdio + functions will not use open() before calling read(), so if the stdin + cannel needs to be opened first, you should do that in your start-up co= de + before using the libc functions for the first time. + =20 diff --git a/pc-bios/s390-ccw/libc/ctype/Makefile.inc b/pc-bios/s390-ccw/li= bc/ctype/Makefile.inc new file mode 100644 index 0000000..25513a9 --- /dev/null +++ b/pc-bios/s390-ccw/libc/ctype/Makefile.inc @@ -0,0 +1,20 @@ +# ************************************************************************= ***** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ************************************************************************= ****/ + + +CTYPE_SRC_C =3D isdigit.c isprint.c isspace.c isxdigit.c tolower.c toupper= .c +CTYPE_SRC_ASM =3D=20 +CTYPE_SRCS =3D $(CTYPE_SRC_C:%=3D$(CTYPECMNDIR)/%) $(CTYPE_SRC_ASM:%=3D$(C= TYPECMNDIR)/%) +CTYPE_OBJS =3D $(CTYPE_SRC_C:%.c=3D%.o) $(CTYPE_SRC_ASM:%.S=3D%.o) + +%.o : $(CTYPECMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/pc-bios/s390-ccw/libc/ctype/isdigit.c b/pc-bios/s390-ccw/libc/= ctype/isdigit.c new file mode 100644 index 0000000..62d08a1 --- /dev/null +++ b/pc-bios/s390-ccw/libc/ctype/isdigit.c @@ -0,0 +1,25 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int isdigit(int ch) +{ + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return 1; +=09 + default: + return 0; + } +} diff --git a/pc-bios/s390-ccw/libc/ctype/isprint.c b/pc-bios/s390-ccw/libc/= ctype/isprint.c new file mode 100644 index 0000000..c74880f --- /dev/null +++ b/pc-bios/s390-ccw/libc/ctype/isprint.c @@ -0,0 +1,18 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int isprint(int ch) +{ + return (ch >=3D 32 && ch < 127); +} diff --git a/pc-bios/s390-ccw/libc/ctype/isspace.c b/pc-bios/s390-ccw/libc/= ctype/isspace.c new file mode 100644 index 0000000..5123019 --- /dev/null +++ b/pc-bios/s390-ccw/libc/ctype/isspace.c @@ -0,0 +1,29 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int isspace(int ch) +{ + switch (ch) { + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + return 1; +=09 + default: + return 0; + } +} diff --git a/pc-bios/s390-ccw/libc/ctype/isxdigit.c b/pc-bios/s390-ccw/libc= /ctype/isxdigit.c new file mode 100644 index 0000000..9d323f3 --- /dev/null +++ b/pc-bios/s390-ccw/libc/ctype/isxdigit.c @@ -0,0 +1,21 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int isxdigit(int ch) +{ + return (=20 + (ch >=3D '0' && ch <=3D '9') | + (ch >=3D 'A' && ch <=3D 'F') | + (ch >=3D 'a' && ch <=3D 'f') ); +} diff --git a/pc-bios/s390-ccw/libc/ctype/tolower.c b/pc-bios/s390-ccw/libc/= ctype/tolower.c new file mode 100644 index 0000000..f775e90 --- /dev/null +++ b/pc-bios/s390-ccw/libc/ctype/tolower.c @@ -0,0 +1,18 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int tolower(int c)=20 +{ + return (((c >=3D 'A') && (c <=3D 'Z')) ? (c - 'A' + 'a' ) : c); +} diff --git a/pc-bios/s390-ccw/libc/ctype/toupper.c b/pc-bios/s390-ccw/libc/= ctype/toupper.c new file mode 100644 index 0000000..9bcee52 --- /dev/null +++ b/pc-bios/s390-ccw/libc/ctype/toupper.c @@ -0,0 +1,21 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "ctype.h" + +int toupper (int cha) +{ + if((cha >=3D 'a') && (cha <=3D 'z')) + return(cha - 'a' + 'A'); + return(cha); +} diff --git a/pc-bios/s390-ccw/libc/include/ctype.h b/pc-bios/s390-ccw/libc/= include/ctype.h new file mode 100644 index 0000000..9051a75 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/ctype.h @@ -0,0 +1,24 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _CTYPE_H +#define _CTYPE_H + +int isdigit(int c); +int isxdigit(int c); +int isprint(int c); +int isspace(int c); + +int tolower(int c); +int toupper(int c); + +#endif diff --git a/pc-bios/s390-ccw/libc/include/errno.h b/pc-bios/s390-ccw/libc/= include/errno.h new file mode 100644 index 0000000..d585934 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/errno.h @@ -0,0 +1,34 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _ERRNO_H +#define _ERRNO_H + +extern int errno; + +/* + * Error number definitions + */ +#define EPERM 1 /* not permitted */ +#define ENOENT 2 /* file or directory not found */ +#define EIO 5 /* input/output error */ +#define ENOMEM 12 /* not enough space */ +#define EACCES 13 /* permission denied */ +#define EFAULT 14 /* bad address */ +#define EBUSY 16 /* resource busy */ +#define EEXIST 17 /* file already exists */ +#define ENODEV 19 /* device not found */ +#define EINVAL 22 /* invalid argument */ +#define EDOM 33 /* math argument out of domain of func */ +#define ERANGE 34 /* math result not representable */ + +#endif diff --git a/pc-bios/s390-ccw/libc/include/limits.h b/pc-bios/s390-ccw/libc= /include/limits.h new file mode 100644 index 0000000..4726835 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/limits.h @@ -0,0 +1,32 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _LIMITS_H +#define _LIMITS_H + +#define UCHAR_MAX 255 +#define SCHAR_MAX 127 +#define SCHAR_MIN (-128) + +#define USHRT_MAX 65535 +#define SHRT_MAX 32767 +#define SHRT_MIN (-32768) + +#define UINT_MAX (4294967295U) +#define INT_MAX 2147483647 +#define INT_MIN (-2147483648) + +#define ULONG_MAX ((unsigned long)-1L) +#define LONG_MAX (ULONG_MAX/2) +#define LONG_MIN ((-LONG_MAX)-1) + +#endif diff --git a/pc-bios/s390-ccw/libc/include/stdarg.h b/pc-bios/s390-ccw/libc= /include/stdarg.h new file mode 100644 index 0000000..d3d12f7 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/stdarg.h @@ -0,0 +1,22 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _STDARG_H +#define _STDARG_H + +typedef __builtin_va_list va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_end(v) __builtin_va_end(v) + +#endif diff --git a/pc-bios/s390-ccw/libc/include/stdbool.h b/pc-bios/s390-ccw/lib= c/include/stdbool.h new file mode 100644 index 0000000..5b7d36a --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/stdbool.h @@ -0,0 +1,20 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus +typedef enum { false =3D 0, true } bool; +#endif + +#endif diff --git a/pc-bios/s390-ccw/libc/include/stddef.h b/pc-bios/s390-ccw/libc= /include/stddef.h new file mode 100644 index 0000000..ba2d960 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/stddef.h @@ -0,0 +1,25 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _STDDEF_H +#define _STDDEF_H + + +#define NULL ((void *)0) + + +typedef unsigned int size_t; + + +#endif + + diff --git a/pc-bios/s390-ccw/libc/include/stdint.h b/pc-bios/s390-ccw/libc= /include/stdint.h new file mode 100644 index 0000000..518a723 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/stdint.h @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _STDINT_H +#define _STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef signed int int32_t; + +typedef unsigned long long uint64_t; +typedef signed long long int64_t; + +#endif diff --git a/pc-bios/s390-ccw/libc/include/stdio.h b/pc-bios/s390-ccw/libc/= include/stdio.h new file mode 100644 index 0000000..c54528f --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/stdio.h @@ -0,0 +1,63 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _STDIO_H +#define _STDIO_H + +#include +#include "stddef.h" + +#define EOF (-1) + +#define _IONBF 0 +#define _IOLBF 1 +#define _IOFBF 2 +#define BUFSIZ 80 + +typedef struct { + int fd; + int mode; + int pos; + char *buf; + int bufsiz; +} FILE; + +extern FILE stdin_data; +extern FILE stdout_data; +extern FILE stderr_data; + +#define stdin (&stdin_data) +#define stdout (&stdout_data) +#define stderr (&stderr_data) + +int fileno(FILE *stream); +int printf(const char *format, ...) __attribute__((format (printf, 1, 2))); +int fprintf(FILE *stream, const char *format, ...) __attribute__((format (= printf, 2, 3))); +int sprintf(char *str, const char *format, ...) __attribute__((format (pr= intf, 2, 3))); +int vfprintf(FILE *stream, const char *format, va_list); +int vsprintf(char *str, const char *format, va_list); +int vsnprintf(char *str, size_t size, const char *format, va_list); +void setbuf(FILE *stream, char *buf); +int setvbuf(FILE *stream, char *buf, int mode , size_t size); + +int putc(int ch, FILE *stream); +int putchar(int ch); +int puts(const char *str); + +int scanf(const char *format, ...) __attribute__((format (scanf, 1, 2))); +int fscanf(FILE *stream, const char *format, ...) __attribute__((format (s= canf, 2, 3))); +int vfscanf(FILE *stream, const char *format, va_list); +int vsscanf(const char *str, const char *format, va_list); +int getc(FILE *stream); +int getchar(void); + +#endif diff --git a/pc-bios/s390-ccw/libc/include/stdlib.h b/pc-bios/s390-ccw/libc= /include/stdlib.h new file mode 100644 index 0000000..5e0eda9 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/stdlib.h @@ -0,0 +1,34 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _STDLIB_H +#define _STDLIB_H + +#include "stddef.h" + +#define RAND_MAX 32767 + + +void *malloc(size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); +void *memalign(size_t boundary, size_t size); + +int atoi(const char *str); +long atol(const char *str); +unsigned long int strtoul(const char *nptr, char **endptr, int base); +long int strtol(const char *nptr, char **endptr, int base); + +int rand(void); +void srand(unsigned int seed); + +#endif diff --git a/pc-bios/s390-ccw/libc/include/string.h b/pc-bios/s390-ccw/libc= /include/string.h new file mode 100644 index 0000000..0163c9a --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/string.h @@ -0,0 +1,37 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _STRING_H +#define _STRING_H + +#include "stddef.h" + +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, size_t n); +char *strcat(char *dest, const char *src); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +int strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +size_t strlen(const char *s); +char *strstr(const char *hay, const char *needle); +char *strtok(char *src, const char *pattern); + +void *memset(void *s, int c, size_t n); +void *memchr(const void *s, int c, size_t n); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); + +#endif diff --git a/pc-bios/s390-ccw/libc/include/sys/socket.h b/pc-bios/s390-ccw/= libc/include/sys/socket.h new file mode 100644 index 0000000..e9175be --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/sys/socket.h @@ -0,0 +1,53 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#ifndef _SOCKET_H +#define _SOCKET_H +#include + +#define AF_PACKET 0 +#define AF_INET 1 +#define AF_INET6 2 + +#define SOCK_RAW 0 +#define SOCK_PACKET 1 +#define SOCK_DGRAM 2 +#define SOCK_STREAM 3 + +#define INADDR_ANY 0xFFFFFFFF + +#define IPPROTO_UDP 1 + +#define ETH_ALEN 6 /**< HW address length */ + +struct sockaddr { + uint16_t tra_port; + + uint16_t ipv4_proto; + uint32_t ipv4_addr; + + // protocol field is only used by "connect"-handler + uint16_t llc_proto; + uint8_t mac_addr[ETH_ALEN]; +}; + +int socket(int, int, int, char *); +int sendto(int, const void *, int, int, const void *, int); +int send(int, const void *, int, int); +int recv(int, void *, int, int); + +#define htonl(x) x +#define htons(x) x + +#endif + diff --git a/pc-bios/s390-ccw/libc/include/unistd.h b/pc-bios/s390-ccw/libc= /include/unistd.h new file mode 100644 index 0000000..07210d6 --- /dev/null +++ b/pc-bios/s390-ccw/libc/include/unistd.h @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include + +typedef long ssize_t; + +extern int open(const char *name, int flags); +extern int close(int fd); +extern ssize_t read(int fd, void *buf, size_t count); +extern ssize_t write(int fd, const void *buf, size_t count); +extern ssize_t lseek(int fd, long offset, int whence); + +extern void *sbrk(int increment); + +#endif diff --git a/pc-bios/s390-ccw/libc/stdio/Makefile.inc b/pc-bios/s390-ccw/li= bc/stdio/Makefile.inc new file mode 100644 index 0000000..ac5302d --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/Makefile.inc @@ -0,0 +1,23 @@ +# ************************************************************************= ***** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ************************************************************************= ****/ + + +STDIO_SRC_C =3D fscanf.c sprintf.c vfprintf.c vsnprintf.c vsprintf.c fprin= tf.c \ + printf.c setvbuf.c putc.c puts.c putchar.c scanf.c stdchnls.c \ + vfscanf.c vsscanf.c fileno.c + +STDIO_SRC_ASM =3D=20 +STDIO_SRCS =3D $(STDIO_SRC_C:%=3D$(STDIOCMNDIR)/%) $(STDIO_SRC_ASM:%=3D$(S= TDIOCMNDIR)/%) +STDIO_OBJS =3D $(STDIO_SRC_C:%.c=3D%.o) $(STDIO_SRC_ASM:%.S=3D%.o) + +%.o : $(STDIOCMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/pc-bios/s390-ccw/libc/stdio/fileno.c b/pc-bios/s390-ccw/libc/s= tdio/fileno.c new file mode 100644 index 0000000..6e23951 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/fileno.c @@ -0,0 +1,19 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int +fileno(FILE *stream) +{ + return stream->fd; +} diff --git a/pc-bios/s390-ccw/libc/stdio/fprintf.c b/pc-bios/s390-ccw/libc/= stdio/fprintf.c new file mode 100644 index 0000000..866df39 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/fprintf.c @@ -0,0 +1,26 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "stdio.h" + + +int fprintf(FILE *stream, const char* fmt, ...) +{ + int count; + va_list ap; + =20 + va_start(ap, fmt); + count =3D vfprintf(stream, fmt, ap); + va_end(ap); + =20 + return count; +} diff --git a/pc-bios/s390-ccw/libc/stdio/printf.c b/pc-bios/s390-ccw/libc/s= tdio/printf.c new file mode 100644 index 0000000..01f4592 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/printf.c @@ -0,0 +1,27 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "stdio.h" + + +int printf(const char* fmt, ...) +{ + int count; + va_list ap; + =20 + va_start(ap, fmt); + count =3D vfprintf(stdout, fmt, ap); + va_end(ap); + =20 + return count; +} + diff --git a/pc-bios/s390-ccw/libc/stdio/putc.c b/pc-bios/s390-ccw/libc/std= io/putc.c new file mode 100644 index 0000000..230e9d1 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/putc.c @@ -0,0 +1,25 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "stdio.h" +#include "unistd.h" + +int +putc(int ch, FILE *stream) +{ + unsigned char outchar =3D ch; + + if (write(stream->fd, &outchar, 1) =3D=3D 1) + return outchar; + else + return EOF; +} diff --git a/pc-bios/s390-ccw/libc/stdio/putchar.c b/pc-bios/s390-ccw/libc/= stdio/putchar.c new file mode 100644 index 0000000..5c750d9 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/putchar.c @@ -0,0 +1,21 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "stdio.h" + + +int +putchar(int ch) +{ + return putc(ch, stdout); +} diff --git a/pc-bios/s390-ccw/libc/stdio/puts.c b/pc-bios/s390-ccw/libc/std= io/puts.c new file mode 100644 index 0000000..9a93008 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/puts.c @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "stdio.h" +#include "string.h" +#include "unistd.h" + + +int +puts(const char *str) +{ + int ret; + + ret =3D write(stdout->fd, str, strlen(str)); + write(stdout->fd, "\r\n", 2); + + return ret; +} diff --git a/pc-bios/s390-ccw/libc/stdio/setvbuf.c b/pc-bios/s390-ccw/libc/= stdio/setvbuf.c new file mode 100644 index 0000000..9b62dd8 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/setvbuf.c @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int setvbuf(FILE *stream, char *buf, int mode , size_t size) +{ + if (mode !=3D _IONBF && mode !=3D _IOLBF && mode !=3D _IOFBF) + return -1; + stream->buf =3D buf; + stream->mode =3D mode; + stream->bufsiz =3D size; + return 0; +} + +void setbuf(FILE *stream, char *buf) +{ + setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ); +} diff --git a/pc-bios/s390-ccw/libc/stdio/sprintf.c b/pc-bios/s390-ccw/libc/= stdio/sprintf.c new file mode 100644 index 0000000..9c4540e --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/sprintf.c @@ -0,0 +1,30 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + + +int sprintf(char *buff, const char *format, ...) +{ + va_list ar; + int count; + + if ((buff=3D=3DNULL) || (format=3D=3DNULL)) + return(-1); + + va_start(ar, format); + count =3D vsprintf(buff, format, ar); + va_end(ar); +=09 + return(count); +} + diff --git a/pc-bios/s390-ccw/libc/stdio/stdchnls.c b/pc-bios/s390-ccw/libc= /stdio/stdchnls.c new file mode 100644 index 0000000..41ed958 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/stdchnls.c @@ -0,0 +1,23 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "stdio.h" + +static char stdin_buffer[BUFSIZ], stdout_buffer[BUFSIZ]; + +FILE stdin_data =3D { .fd =3D 0, .mode =3D _IOLBF, .pos =3D 0, + .buf =3D stdin_buffer, .bufsiz =3D BUFSIZ }; +FILE stdout_data =3D { .fd =3D 1, .mode =3D _IOLBF, .pos =3D 0, + .buf =3D stdout_buffer, .bufsiz =3D BUFSIZ }; +FILE stderr_data =3D { .fd =3D 2, .mode =3D _IONBF, .pos =3D 0, + .buf =3D NULL, .bufsiz =3D 0 }; diff --git a/pc-bios/s390-ccw/libc/stdio/vfprintf.c b/pc-bios/s390-ccw/libc= /stdio/vfprintf.c new file mode 100644 index 0000000..765feea --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/vfprintf.c @@ -0,0 +1,27 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "stdio.h" +#include "unistd.h" + + +int vfprintf(FILE *stream, const char *fmt, va_list ap) +{ + int count; + char buffer[320]; + + count =3D vsnprintf(buffer, sizeof(buffer), fmt, ap); + write(stream->fd, buffer, count); + + return count; +} + diff --git a/pc-bios/s390-ccw/libc/stdio/vsnprintf.c b/pc-bios/s390-ccw/lib= c/stdio/vsnprintf.c new file mode 100644 index 0000000..21dd04d --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/vsnprintf.c @@ -0,0 +1,298 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "ctype.h" + +static const unsigned long long convert[] =3D { + 0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFF= FFULL +}; + +static int +print_str_fill(char **buffer, size_t bufsize, char *sizec, + const char *str, char c) +{ + int i, sizei, len; + char *bstart =3D *buffer; + + sizei =3D strtoul(sizec, NULL, 10); + len =3D strlen(str); + if (sizei > len) { + for (i =3D 0; + (i < (sizei - len)) && ((*buffer - bstart) < bufsize); + i++) { + **buffer =3D c; + *buffer +=3D 1; + } + } + return 1; +} + +static int +print_str(char **buffer, size_t bufsize, const char *str) +{ + char *bstart =3D *buffer; + size_t i; + + for (i =3D 0; (i < strlen(str)) && ((*buffer - bstart) < bufsize); i++) { + **buffer =3D str[i]; + *buffer +=3D 1; + } + return 1; +} + +static unsigned int +print_intlen(unsigned long value, unsigned short int base) +{ + int i =3D 0; + + while (value > 0) { + value /=3D base; + i++; + } + if (i =3D=3D 0) + i =3D 1; + return i; +} + +static int +print_itoa(char **buffer, size_t bufsize, unsigned long value, + unsigned short base, bool upper) +{ + const char zeichen[] =3D {'0','1','2','3','4','5','6','7','8','9','a','b'= ,'c','d','e','f'}; + char c; + size_t i, len; + + if(base <=3D 2 || base > 16) + return 0; + + len =3D i =3D print_intlen(value, base); + + /* Don't print to buffer if bufsize is not enough. */ + if (len > bufsize) + return 0; + + do { + c =3D zeichen[value % base]; + if (upper) + c =3D toupper(c); + + (*buffer)[--i] =3D c; + value /=3D base; + } while(value); + + *buffer +=3D len; + + return 1; +} + + + +static int +print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size, + unsigned short int base, char c, int optlen) +{ + int i, sizei, len; + char *bstart =3D *buffer; + + sizei =3D strtoul(sizec, NULL, 10); + len =3D print_intlen(size, base) + optlen; + if (sizei > len) { + for (i =3D 0; + (i < (sizei - len)) && ((*buffer - bstart) < bufsize); + i++) { + **buffer =3D c; + *buffer +=3D 1; + } + } + + return 0; +} + + +static int +print_format(char **buffer, size_t bufsize, const char *format, void *var) +{ + char *start; + unsigned int i =3D 0, length_mod =3D sizeof(int); + unsigned long value =3D 0; + unsigned long signBit; + char *form, sizec[32]; + char sign =3D ' '; + bool upper =3D false; + + form =3D (char *) format; + start =3D *buffer; + + form++; + if(*form =3D=3D '0' || *form =3D=3D '.') { + sign =3D '0'; + form++; + } + + while ((*form !=3D '\0') && ((*buffer - start) < bufsize)) { + switch(*form) { + case 'u': + case 'd': + case 'i': + sizec[i] =3D '\0'; + value =3D (unsigned long) var; + signBit =3D 0x1ULL << (length_mod * 8 - 1); + if ((*form !=3D 'u') && (signBit & value)) { + **buffer =3D '-'; + *buffer +=3D 1; + value =3D (-(unsigned long)value) & convert[length_mod]; + } + print_fill(buffer, bufsize - (*buffer - start), + sizec, value, 10, sign, 0); + print_itoa(buffer, bufsize - (*buffer - start), + value, 10, upper); + break; + case 'X': + upper =3D true; + case 'x': + sizec[i] =3D '\0'; + value =3D (unsigned long) var & convert[length_mod]; + print_fill(buffer, bufsize - (*buffer - start), + sizec, value, 16, sign, 0); + print_itoa(buffer, bufsize - (*buffer - start), + value, 16, upper); + break; + case 'O': + case 'o': + sizec[i] =3D '\0'; + value =3D (long int) var & convert[length_mod]; + print_fill(buffer, bufsize - (*buffer - start), + sizec, value, 8, sign, 0); + print_itoa(buffer, bufsize - (*buffer - start), + value, 8, upper); + break; + case 'p': + sizec[i] =3D '\0'; + print_fill(buffer, bufsize - (*buffer - start), + sizec, (unsigned long) var, 16, ' ', 2); + print_str(buffer, bufsize - (*buffer - start), + "0x"); + print_itoa(buffer, bufsize - (*buffer - start), + (unsigned long) var, 16, upper); + break; + case 'c': + sizec[i] =3D '\0'; + print_fill(buffer, bufsize - (*buffer - start), + sizec, 1, 10, ' ', 0); + **buffer =3D (unsigned long) var; + *buffer +=3D 1; + break; + case 's': + sizec[i] =3D '\0'; + print_str_fill(buffer, + bufsize - (*buffer - start), sizec, + (char *) var, ' '); + + print_str(buffer, bufsize - (*buffer - start), + (char *) var); + break; + case 'l': + form++; + if(*form =3D=3D 'l') { + length_mod =3D sizeof(long long int); + } else { + form--; + length_mod =3D sizeof(long int); + } + break; + case 'h': + form++; + if(*form =3D=3D 'h') { + length_mod =3D sizeof(signed char); + } else { + form--; + length_mod =3D sizeof(short int); + } + break; + case 'z': + length_mod =3D sizeof(size_t); + break; + default: + if(*form >=3D '0' && *form <=3D '9') + sizec[i++] =3D *form; + } + form++; + } + +=09 + return (long int) (*buffer - start); +} + + +/* + * The vsnprintf function prints a formated strings into a buffer. + * BUG: buffer size checking does not fully work yet + */ +int +vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg) +{ + char *ptr, *bstart; + + bstart =3D buffer; + ptr =3D (char *) format; + + /* + * Return from here if size passed is zero, otherwise we would + * overrun buffer while setting NULL character at the end. + */ + if (!buffer || !bufsize) + return 0; + + /* Leave one space for NULL character */ + bufsize--; + + while(*ptr !=3D '\0' && (buffer - bstart) < bufsize) + { + if(*ptr =3D=3D '%') { + char formstr[20]; + int i=3D0; + =09 + do { + formstr[i] =3D *ptr; + ptr++; + i++; + } while(!(*ptr =3D=3D 'd' || *ptr =3D=3D 'i' || *ptr =3D=3D 'u' || *ptr= =3D=3D 'x' || *ptr =3D=3D 'X' + || *ptr =3D=3D 'p' || *ptr =3D=3D 'c' || *ptr =3D=3D 's' || *ptr =3D= =3D '%' + || *ptr =3D=3D 'O' || *ptr =3D=3D 'o' ));=20 + formstr[i++] =3D *ptr; + formstr[i] =3D '\0'; + if(*ptr =3D=3D '%') { + *buffer++ =3D '%'; + } else { + print_format(&buffer, + bufsize - (buffer - bstart), + formstr, va_arg(arg, void *)); + } + ptr++; + } else { + + *buffer =3D *ptr; + + buffer++; + ptr++; + } + } +=09 + *buffer =3D '\0'; + + return (buffer - bstart); +} diff --git a/pc-bios/s390-ccw/libc/stdio/vsprintf.c b/pc-bios/s390-ccw/libc= /stdio/vsprintf.c new file mode 100644 index 0000000..0dfd737 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdio/vsprintf.c @@ -0,0 +1,19 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "stdio.h" + +int +vsprintf(char *buffer, const char *format, va_list arg) +{ + return vsnprintf(buffer, 0x7fffffff, format, arg); +} diff --git a/pc-bios/s390-ccw/libc/stdlib/Makefile.inc b/pc-bios/s390-ccw/l= ibc/stdlib/Makefile.inc new file mode 100644 index 0000000..702f6d7 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/Makefile.inc @@ -0,0 +1,22 @@ +# ************************************************************************= ***** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ************************************************************************= ****/ + + +STDLIB_SRC_C =3D error.c atoi.c atol.c strtoul.c strtol.c rand.c \ + malloc.c memalign.c realloc.c free.c + =09 +STDLIB_SRC_ASM =3D=20 +STDLIB_SRCS =3D $(STDLIB_SRC_C:%=3D$(STDLIBCMNDIR)/%) $(STDLIB_SRC_ASM:%= =3D$(STDLIBCMNDIR)/%) +STDLIB_OBJS =3D $(STDLIB_SRC_C:%.c=3D%.o) $(STDLIB_SRC_ASM:%.S=3D%.o) + +%.o : $(STDLIBCMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/pc-bios/s390-ccw/libc/stdlib/atoi.c b/pc-bios/s390-ccw/libc/st= dlib/atoi.c new file mode 100644 index 0000000..d2fb33b --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/atoi.c @@ -0,0 +1,18 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +int atoi(const char *str) +{ + return strtol(str, NULL, 0); +} diff --git a/pc-bios/s390-ccw/libc/stdlib/atol.c b/pc-bios/s390-ccw/libc/st= dlib/atol.c new file mode 100644 index 0000000..a6aa47b --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/atol.c @@ -0,0 +1,18 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +long atol(const char *str) +{ + return strtol(str, NULL, 0); +} diff --git a/pc-bios/s390-ccw/libc/stdlib/error.c b/pc-bios/s390-ccw/libc/s= tdlib/error.c new file mode 100644 index 0000000..81020ca --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/error.c @@ -0,0 +1,15 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +int errno; + diff --git a/pc-bios/s390-ccw/libc/stdlib/free.c b/pc-bios/s390-ccw/libc/st= dlib/free.c new file mode 100644 index 0000000..9005450 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/free.c @@ -0,0 +1,26 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "stdlib.h" +#include "malloc_defs.h" + +void +free(void *ptr) +{ + struct chunk *header; + + header =3D (struct chunk *) ptr; + header--; + header->inuse =3D 0; + +} diff --git a/pc-bios/s390-ccw/libc/stdlib/malloc.c b/pc-bios/s390-ccw/libc/= stdlib/malloc.c new file mode 100644 index 0000000..b2a3138 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/malloc.c @@ -0,0 +1,157 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "stddef.h" +#include "stdlib.h" +#include "unistd.h" +#include "malloc_defs.h" + + +static int clean(void); + + +/* act points to the end of the initialized heap and the start of uninitia= lized heap */ +static char *act; + +/* Pointers to start and end of heap: */ +static char *heap_start, *heap_end; + + +/* + * Standard malloc function + */ +void * +malloc(size_t size) +{ + char *header; + void *data; + size_t blksize; /* size of memory block including the chunk */ + + blksize =3D size + sizeof(struct chunk); + + /* has malloc been called for the first time? */ + if (act =3D=3D 0) { + size_t initsize; + /* add some space so we have a good initial playground */ + initsize =3D (blksize + 0x1000) & ~0x0fff; + /* get initial memory region with sbrk() */ + heap_start =3D sbrk(initsize); + if (heap_start =3D=3D (void*)-1) + return NULL; + heap_end =3D heap_start + initsize; + act =3D heap_start; + } + + header =3D act; + data =3D act + sizeof(struct chunk); + + /* Check if there is space left in the uninitialized part of the heap */ + if (act + blksize > heap_end) { + //search at begin of heap + header =3D heap_start; + + while ((((struct chunk *) header)->inuse !=3D 0 + || ((struct chunk *) header)->length < size) + && header < act) { + header =3D header + sizeof(struct chunk) + + ((struct chunk *) header)->length; + } + + // check if heap is full + if (header >=3D act) { + if (clean()) { + // merging of free blocks succeeded, so try again + return malloc(size); + } else if (sbrk(blksize) =3D=3D heap_end) { + // succeeded to get more memory, so try again + heap_end +=3D blksize; + return malloc(size); + } else { + // No more memory available + return 0; + } + } + + // Check if we need to split this memory block into two + if (((struct chunk *) header)->length > blksize) { + //available memory is too big + int alt; + + alt =3D ((struct chunk *) header)->length; + ((struct chunk *) header)->inuse =3D 1; + ((struct chunk *) header)->length =3D size; + data =3D header + sizeof(struct chunk); + + //mark the rest of the heap + header =3D data + size; + ((struct chunk *) header)->inuse =3D 0; + ((struct chunk *) header)->length =3D + alt - blksize; + } else { + //new memory matched exactly in available memory + ((struct chunk *) header)->inuse =3D 1; + data =3D header + sizeof(struct chunk); + } + + } else { + + ((struct chunk *) header)->inuse =3D 1; + ((struct chunk *) header)->length =3D size; + + act +=3D blksize; + } + + return data; +} + + +/* + * Merge free memory blocks in initialized heap if possible + */ +static int +clean(void) +{ + char *header; + char *firstfree =3D 0; + char check =3D 0; + + header =3D heap_start; + //if (act =3D=3D 0) // This should never happen + // act =3D heap_end; + + while (header < act) { + + if (((struct chunk *) header)->inuse =3D=3D 0) { + if (firstfree =3D=3D 0) { + /* First free block in a row, only save address */ + firstfree =3D header; + + } else { + /* more than one free block in a row, merge them! */ + ((struct chunk *) firstfree)->length +=3D + ((struct chunk *) header)->length + + sizeof(struct chunk); + check =3D 1; + } + } else { + firstfree =3D 0; + + } + + header =3D header + sizeof(struct chunk) + + ((struct chunk *) header)->length; + + } + + return check; +} diff --git a/pc-bios/s390-ccw/libc/stdlib/malloc_defs.h b/pc-bios/s390-ccw/= libc/stdlib/malloc_defs.h new file mode 100644 index 0000000..1933026 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/malloc_defs.h @@ -0,0 +1,16 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +struct chunk { + unsigned inuse : 4; + unsigned length : 28; +} __attribute__((packed)); diff --git a/pc-bios/s390-ccw/libc/stdlib/memalign.c b/pc-bios/s390-ccw/lib= c/stdlib/memalign.c new file mode 100644 index 0000000..3b678aa --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/memalign.c @@ -0,0 +1,26 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "stdlib.h" + + +void * +memalign(size_t blocksize, size_t bytes) +{ + void *x; + + x =3D malloc(bytes + blocksize); + x =3D (void *) (((unsigned long) x + blocksize - 1) & ~(blocksize - 1)); + + return (void *) x; +} diff --git a/pc-bios/s390-ccw/libc/stdlib/rand.c b/pc-bios/s390-ccw/libc/st= dlib/rand.c new file mode 100644 index 0000000..39f5a9a --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/rand.c @@ -0,0 +1,29 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + + +static unsigned long _rand =3D 1; + +int +rand(void) +{ + _rand =3D _rand * 1237732973 + 34563; + + return ((unsigned int) (_rand >> 16) & RAND_MAX); +} + +void srand(unsigned int seed) +{ + _rand =3D seed; +} diff --git a/pc-bios/s390-ccw/libc/stdlib/realloc.c b/pc-bios/s390-ccw/libc= /stdlib/realloc.c new file mode 100644 index 0000000..652e900 --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/realloc.c @@ -0,0 +1,40 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#include "stdlib.h" +#include "string.h" +#include "malloc_defs.h" + +void * +realloc(void *ptr, size_t size) +{ + struct chunk *header; + char *newptr, *start; + + header =3D (struct chunk *) ptr; + header--; + + if (size <=3D header->length) + return ptr; + + newptr =3D (char *) malloc(size); + if (newptr =3D=3D NULL) + return 0; + + start =3D newptr; + memcpy((void *) newptr, (const void *) ptr, header->length); + + header->inuse =3D 0; + + return start; +} diff --git a/pc-bios/s390-ccw/libc/stdlib/strtol.c b/pc-bios/s390-ccw/libc/= stdlib/strtol.c new file mode 100644 index 0000000..474597a --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/strtol.c @@ -0,0 +1,115 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +long int strtol(const char *S, char **PTR,int BASE) +{ + long rval =3D 0; + short int negative =3D 0; + short int digit; + // *PTR is S, unless PTR is NULL, in which case i override it with my own= ptr + char* ptr; + if (PTR =3D=3D 0) + { + //override + PTR =3D &ptr; + } + // i use PTR to advance through the string + *PTR =3D (char *) S; + //check if BASE is ok + if ((BASE < 0) || BASE > 36) + { + return 0; + } + // ignore white space at beginning of S + while ((**PTR =3D=3D ' ') + || (**PTR =3D=3D '\t') + || (**PTR =3D=3D '\n') + || (**PTR =3D=3D '\r') + ) + { + (*PTR)++; + } + // check if S starts with "-" in which case the return value is negative + if (**PTR =3D=3D '-') + { + negative =3D 1; + (*PTR)++; + } + // if BASE is 0... determine the base from the first chars... + if (BASE =3D=3D 0) + { + // if S starts with "0x", BASE =3D 16, else 10 + if ((**PTR =3D=3D '0') && (*((*PTR)+1) =3D=3D 'x')) + { + BASE =3D 16; + (*PTR)++; + (*PTR)++; + } + else + { + BASE =3D 10; + } + } + if (BASE =3D=3D 16) + { + // S may start with "0x" + if ((**PTR =3D=3D '0') && (*((*PTR)+1) =3D=3D 'x')) + { + (*PTR)++; + (*PTR)++; + } + } + //until end of string + while (**PTR) + { + if (((**PTR) >=3D '0') && ((**PTR) <=3D '9')) + { + //digit (0..9) + digit =3D **PTR - '0'; + } + else if (((**PTR) >=3D 'a') && ((**PTR) <=3D'z')) + { + //alphanumeric digit lowercase(a (10) .. z (35) ) + digit =3D (**PTR - 'a') + 10; + } + else if (((**PTR) >=3D 'A') && ((**PTR) <=3D'Z')) + { + //alphanumeric digit uppercase(a (10) .. z (35) ) + digit =3D (**PTR - 'A') + 10; + } + else + { + //end of parseable number reached... + break; + } + if (digit < BASE) + { + rval =3D (rval * BASE) + digit; + } + else + { + //digit found, but its too big for current base + //end of parseable number reached... + break; + } + //next... + (*PTR)++; + } + if (negative) + { + return rval * -1; + } + //else + return rval; +} diff --git a/pc-bios/s390-ccw/libc/stdlib/strtoul.c b/pc-bios/s390-ccw/libc= /stdlib/strtoul.c new file mode 100644 index 0000000..754e7db --- /dev/null +++ b/pc-bios/s390-ccw/libc/stdlib/strtoul.c @@ -0,0 +1,105 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +unsigned long int strtoul(const char *S, char **PTR,int BASE) +{ + unsigned long rval =3D 0; + short int digit; + // *PTR is S, unless PTR is NULL, in which case i override it with my own= ptr + char* ptr; + if (PTR =3D=3D 0) + { + //override + PTR =3D &ptr; + } + // i use PTR to advance through the string + *PTR =3D (char *) S; + //check if BASE is ok + if ((BASE < 0) || BASE > 36) + { + return 0; + } + // ignore white space at beginning of S + while ((**PTR =3D=3D ' ') + || (**PTR =3D=3D '\t') + || (**PTR =3D=3D '\n') + || (**PTR =3D=3D '\r') + ) + { + (*PTR)++; + } + // if BASE is 0... determine the base from the first chars... + if (BASE =3D=3D 0) + { + // if S starts with "0x", BASE =3D 16, else 10 + if ((**PTR =3D=3D '0') && (*((*PTR)+1) =3D=3D 'x')) + { + BASE =3D 16; + (*PTR)++; + (*PTR)++; + } + else + { + BASE =3D 10; + } + } + if (BASE =3D=3D 16) + { + // S may start with "0x" + if ((**PTR =3D=3D '0') && (*((*PTR)+1) =3D=3D 'x')) + { + (*PTR)++; + (*PTR)++; + } + } + //until end of string + while (**PTR) + { + if (((**PTR) >=3D '0') && ((**PTR) <=3D'9')) + { + //digit (0..9) + digit =3D **PTR - '0'; + } + else if (((**PTR) >=3D 'a') && ((**PTR) <=3D'z')) + { + //alphanumeric digit lowercase(a (10) .. z (35) ) + digit =3D (**PTR - 'a') + 10; + } + else if (((**PTR) >=3D 'A') && ((**PTR) <=3D'Z')) + { + //alphanumeric digit uppercase(a (10) .. z (35) ) + digit =3D (**PTR - 'A') + 10; + } + else + { + //end of parseable number reached... + break; + } + if (digit < BASE) + { + rval =3D (rval * BASE) + digit; + } + else + { + //digit found, but its too big for current base + //end of parseable number reached... + break; + } + //next... + (*PTR)++; + } + //done + return rval; +} + diff --git a/pc-bios/s390-ccw/libc/string/Makefile.inc b/pc-bios/s390-ccw/l= ibc/string/Makefile.inc new file mode 100644 index 0000000..7ccf3c4 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/Makefile.inc @@ -0,0 +1,22 @@ +# ************************************************************************= ***** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ************************************************************************= ****/ + + +STRING_SRC_C =3D strcat.c strchr.c strcmp.c strcpy.c strlen.c strncmp.c \ + strncpy.c strstr.c memset.c memcpy.c memmove.c memchr.c \ + memcmp.c strcasecmp.c strncasecmp.c strtok.c +STRING_SRC_ASM =3D=20 +STRING_SRCS =3D $(STRING_SRC_C:%=3D$(STRINGCMNDIR)/%) $(STRING_SRC_ASM:%= =3D$(STRINGCMNDIR)/%) +STRING_OBJS =3D $(STRING_SRC_C:%.c=3D%.o) $(STRING_SRC_ASM:%.S=3D%.o) + +%.o : $(STRINGCMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/pc-bios/s390-ccw/libc/string/memchr.c b/pc-bios/s390-ccw/libc/= string/memchr.c new file mode 100644 index 0000000..c3fe751 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/memchr.c @@ -0,0 +1,29 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "string.h" + + +void * +memchr(const void *ptr, int c, size_t n) +{ + unsigned char ch =3D (unsigned char)c; + const unsigned char *p =3D ptr; + + while (n-- > 0) { + if (*p =3D=3D ch) + return (void *)p; + p +=3D 1; + } + + return NULL; +} diff --git a/pc-bios/s390-ccw/libc/string/memcmp.c b/pc-bios/s390-ccw/libc/= string/memcmp.c new file mode 100644 index 0000000..3b69cef --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/memcmp.c @@ -0,0 +1,30 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "string.h" + + +int +memcmp(const void *ptr1, const void *ptr2, size_t n) +{ + const unsigned char *p1 =3D ptr1; + const unsigned char *p2 =3D ptr2; + + while (n-- > 0) { + if (*p1 !=3D *p2) + return (*p1 - *p2); + p1 +=3D 1; + p2 +=3D 1; + } + + return 0; +} diff --git a/pc-bios/s390-ccw/libc/string/memcpy.c b/pc-bios/s390-ccw/libc/= string/memcpy.c new file mode 100644 index 0000000..00f419b --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/memcpy.c @@ -0,0 +1,27 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "string.h" + +void * +memcpy(void *dest, const void *src, size_t n) +{ + char *cdest; + const char *csrc =3D src; + + cdest =3D dest; + while (n-- > 0) { + *cdest++ =3D *csrc++; + } + + return dest; +} diff --git a/pc-bios/s390-ccw/libc/string/memmove.c b/pc-bios/s390-ccw/libc= /string/memmove.c new file mode 100644 index 0000000..3acf1a9 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/memmove.c @@ -0,0 +1,42 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "string.h" + + +void * +memmove(void *dest, const void *src, size_t n) +{ + char *cdest; + const char *csrc; + int i; + + /* Do the buffers overlap in a bad way? */ + if (src < dest && src + n >=3D dest) { + /* Copy from end to start */ + cdest =3D dest + n - 1; + csrc =3D src + n - 1; + for (i =3D 0; i < n; i++) { + *cdest-- =3D *csrc--; + } + } + else { + /* Normal copy is possible */ + cdest =3D dest; + csrc =3D src; + for (i =3D 0; i < n; i++) { + *cdest++ =3D *csrc++; + } + } + + return dest; +} diff --git a/pc-bios/s390-ccw/libc/string/memset.c b/pc-bios/s390-ccw/libc/= string/memset.c new file mode 100644 index 0000000..f8dfbf5 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/memset.c @@ -0,0 +1,25 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include "string.h" + +void * +memset(void *dest, int c, size_t size) +{ + unsigned char *d =3D (unsigned char *)dest; + + while (size-- > 0) { + *d++ =3D (unsigned char)c; + } + + return dest; +} diff --git a/pc-bios/s390-ccw/libc/string/strcasecmp.c b/pc-bios/s390-ccw/l= ibc/string/strcasecmp.c new file mode 100644 index 0000000..f75294f --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strcasecmp.c @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include + +int +strcasecmp(const char *s1, const char *s2) +{ + while (*s1 !=3D 0 && *s2 !=3D 0) { + if (toupper(*s1) !=3D toupper(*s2)) + break; + ++s1; + ++s2; + } + + return *s1 - *s2; +} + diff --git a/pc-bios/s390-ccw/libc/string/strcat.c b/pc-bios/s390-ccw/libc/= string/strcat.c new file mode 100644 index 0000000..eb597a0 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strcat.c @@ -0,0 +1,24 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +char * +strcat(char *dst, const char *src) +{ + int p; + + p =3D strlen(dst); + strcpy(&dst[p], src); + + return dst; +} diff --git a/pc-bios/s390-ccw/libc/string/strchr.c b/pc-bios/s390-ccw/libc/= string/strchr.c new file mode 100644 index 0000000..528a319 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strchr.c @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +char * +strchr(const char *s, int c) +{ + char cb =3D c; + + while (*s !=3D 0) { + if (*s =3D=3D cb) { + return (char *)s; + } + s +=3D 1; + } + + return NULL; +} diff --git a/pc-bios/s390-ccw/libc/string/strcmp.c b/pc-bios/s390-ccw/libc/= string/strcmp.c new file mode 100644 index 0000000..48eaed2 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strcmp.c @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + + +int +strcmp(const char *s1, const char *s2) +{ + while (*s1 !=3D 0 && *s2 !=3D 0) { + if (*s1 !=3D *s2) + break; + s1 +=3D 1; + s2 +=3D 1; + } + + return *s1 - *s2; +} + diff --git a/pc-bios/s390-ccw/libc/string/strcpy.c b/pc-bios/s390-ccw/libc/= string/strcpy.c new file mode 100644 index 0000000..48eb62c --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strcpy.c @@ -0,0 +1,25 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +char * +strcpy(char *dst, const char *src) +{ + char *ptr =3D dst; + + do { + *ptr++ =3D *src; + } while (*src++ !=3D 0); + + return dst; +} diff --git a/pc-bios/s390-ccw/libc/string/strlen.c b/pc-bios/s390-ccw/libc/= string/strlen.c new file mode 100644 index 0000000..37a1b78 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strlen.c @@ -0,0 +1,27 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +size_t +strlen(const char *s) +{ + int len =3D 0; + + while (*s !=3D 0) { + len +=3D 1; + s +=3D 1; + } + + return len; +} + diff --git a/pc-bios/s390-ccw/libc/string/strncasecmp.c b/pc-bios/s390-ccw/= libc/string/strncasecmp.c new file mode 100644 index 0000000..4140931 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strncasecmp.c @@ -0,0 +1,32 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include + + +int +strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n < 1) + return 0; + + while (*s1 !=3D 0 && *s2 !=3D 0 && --n > 0) { + if (toupper(*s1) !=3D toupper(*s2)) + break; + ++s1; + ++s2; + } + + return toupper(*s1) - toupper(*s2); +} + diff --git a/pc-bios/s390-ccw/libc/string/strncmp.c b/pc-bios/s390-ccw/libc= /string/strncmp.c new file mode 100644 index 0000000..a886736 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strncmp.c @@ -0,0 +1,31 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + if (n < 1) + return 0; + + while (*s1 !=3D 0 && *s2 !=3D 0 && --n > 0) { + if (*s1 !=3D *s2) + break; + s1 +=3D 1; + s2 +=3D 1; + } + + return *s1 - *s2; +} + diff --git a/pc-bios/s390-ccw/libc/string/strncpy.c b/pc-bios/s390-ccw/libc= /string/strncpy.c new file mode 100644 index 0000000..0f41f93 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strncpy.c @@ -0,0 +1,33 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +char * +strncpy(char *dst, const char *src, size_t n) +{ + char *ret =3D dst; + + /* Copy string */ + while (*src !=3D 0 && n > 0) { + *dst++ =3D *src++; + n -=3D 1; + } + + /* strncpy always clears the rest of destination string... */ + while (n > 0) { + *dst++ =3D 0; + n -=3D 1; + } + + return ret; +} diff --git a/pc-bios/s390-ccw/libc/string/strstr.c b/pc-bios/s390-ccw/libc/= string/strstr.c new file mode 100644 index 0000000..3e090d2 --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strstr.c @@ -0,0 +1,37 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +char * +strstr(const char *hay, const char *needle) +{ + char *pos; + int hlen, nlen; + + if (hay =3D=3D NULL || needle =3D=3D NULL) + return NULL; +=09 + hlen =3D strlen(hay); + nlen =3D strlen(needle); + if (nlen < 1) + return (char *)hay; + + for (pos =3D (char *)hay; pos < hay + hlen; pos++) { + if (strncmp(pos, needle, nlen) =3D=3D 0) { + return pos; + } + } + + return NULL; +} + diff --git a/pc-bios/s390-ccw/libc/string/strtok.c b/pc-bios/s390-ccw/libc/= string/strtok.c new file mode 100644 index 0000000..665c08d --- /dev/null +++ b/pc-bios/s390-ccw/libc/string/strtok.c @@ -0,0 +1,45 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +char * +strtok(char *src, const char *pattern) +{ + static char *nxtTok; + char *retVal =3D NULL; + + if (!src) + src =3D nxtTok; + + while (*src) { + const char *pp =3D pattern; + while (*pp) { + if (*pp =3D=3D *src) { + break; + } + pp++; + } + if (!*pp) { + if (!retVal) + retVal =3D src; + else if (!src[-1]) + break; + } else + *src =3D '\0'; + src++; + } + + nxtTok =3D src; + + return retVal; +} --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564203576690.7414789350485; Tue, 27 Jun 2017 04:50:03 -0700 (PDT) Received: from localhost ([::1]:51842 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp0L-0000WQ-K4 for importer@patchew.org; Tue, 27 Jun 2017 07:50:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54682) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPoyv-0007rk-E4 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPoyt-0003dw-Nm for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60608) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPoyt-0003dq-FC for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:31 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 60D902B0A81; Tue, 27 Jun 2017 11:48:30 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7A33C53CF7; Tue, 27 Jun 2017 11:48:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 60D902B0A81 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 60D902B0A81 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:08 +0200 Message-Id: <1498564100-10045-3-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 27 Jun 2017 11:48:30 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 02/14] pc-bios/s390-ccw: Start using the libc from SLOF X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Change the Makefiles to make the libc compilable within the s390-ccw firmware build system, link it and start using it by switching the implementations of the memset() and memcpy() functions to the ones from the libc. Signed-off-by: Thomas Huth --- configure | 5 ++-- pc-bios/s390-ccw/Makefile | 8 ++++++- pc-bios/s390-ccw/bootmap.h | 1 + pc-bios/s390-ccw/libc/Makefile | 38 ++++++++++-----------------= ---- pc-bios/s390-ccw/libc/ctype/Makefile.inc | 3 ++- pc-bios/s390-ccw/libc/stdio/Makefile.inc | 9 ++++---- pc-bios/s390-ccw/libc/stdlib/Makefile.inc | 3 ++- pc-bios/s390-ccw/libc/string/Makefile.inc | 3 ++- pc-bios/s390-ccw/s390-ccw.h | 30 +++--------------------- 9 files changed, 37 insertions(+), 63 deletions(-) diff --git a/configure b/configure index c571ad1..954c286 100755 --- a/configure +++ b/configure @@ -6377,7 +6377,8 @@ fi # build tree in object directory in case the source is not in the current = directory DIRS=3D"tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/q= api-schema tests/tcg/xtensa tests/qemu-iotests" DIRS=3D"$DIRS docs docs/interop fsdev" -DIRS=3D"$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" +DIRS=3D"$DIRS pc-bios/optionrom pc-bios/spapr-rtas" +DIRS=3D"$DIRS pc-bios/s390-ccw pc-bios/s390-ccw/libc" DIRS=3D"$DIRS roms/seabios roms/vgabios" DIRS=3D"$DIRS qapi-generated" FILES=3D"Makefile tests/tcg/Makefile qdict-test-data.txt" @@ -6385,7 +6386,7 @@ FILES=3D"$FILES tests/tcg/cris/Makefile tests/tcg/cri= s/.gdbinit" FILES=3D"$FILES tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makef= ile" FILES=3D"$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES=3D"$FILES pc-bios/spapr-rtas/Makefile" -FILES=3D"$FILES pc-bios/s390-ccw/Makefile" +FILES=3D"$FILES pc-bios/s390-ccw/Makefile pc-bios/s390-ccw/libc/Makefile" FILES=3D"$FILES roms/seabios/Makefile roms/vgabios/Makefile" FILES=3D"$FILES pc-bios/qemu-icon.bmp" FILES=3D"$FILES .gdbinit scripts" # scripts needed by relative path in .gd= binit diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index fb88c13..3371c5b 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -7,12 +7,14 @@ include $(SRC_PATH)/rules.mak =20 $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) =20 -.PHONY : all clean build-all +.PHONY : all clean build-all libc.a =20 OBJECTS =3D start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o +OBJECTS +=3D libc.a QEMU_CFLAGS :=3D $(filter -W%, $(QEMU_CFLAGS)) QEMU_CFLAGS +=3D -ffreestanding -fno-delete-null-pointer-checks -msoft-flo= at QEMU_CFLAGS +=3D -march=3Dz900 -fPIE -fno-strict-aliasing +QEMU_CFLAGS +=3D -I$(SRC_PATH)/pc-bios/s390-ccw/libc/include QEMU_CFLAGS +=3D $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector) LDFLAGS +=3D -Wl,-pie -nostdlib =20 @@ -21,6 +23,9 @@ build-all: s390-ccw.img s390-ccw.elf: $(OBJECTS) $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_= DIR)$@") =20 +libc.a: + @$(MAKE) -C libc V=3D"$(V)" + STRIP ?=3D strip =20 s390-ccw.img: s390-ccw.elf @@ -30,3 +35,4 @@ $(OBJECTS): Makefile =20 clean: rm -f *.o *.d *.img *.elf *~ + @$(MAKE) -C libc clean diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h index 7f36782..608bb5d 100644 --- a/pc-bios/s390-ccw/bootmap.h +++ b/pc-bios/s390-ccw/bootmap.h @@ -11,6 +11,7 @@ #ifndef _PC_BIOS_S390_CCW_BOOTMAP_H #define _PC_BIOS_S390_CCW_BOOTMAP_H =20 +#include #include "s390-ccw.h" #include "virtio.h" =20 diff --git a/pc-bios/s390-ccw/libc/Makefile b/pc-bios/s390-ccw/libc/Makefile index 0c762ec..12f57e8 100644 --- a/pc-bios/s390-ccw/libc/Makefile +++ b/pc-bios/s390-ccw/libc/Makefile @@ -10,52 +10,38 @@ # * IBM Corporation - initial implementation # ************************************************************************= ****/ =20 -TOPCMNDIR ?=3D ../.. +include ../../../config-host.mak +include $(SRC_PATH)/rules.mak =20 -LIBCCMNDIR =3D $(shell pwd) +LIBCCMNDIR =3D $(SRC_PATH)/pc-bios/s390-ccw/libc STRINGCMNDIR =3D $(LIBCCMNDIR)/string CTYPECMNDIR =3D $(LIBCCMNDIR)/ctype STDLIBCMNDIR =3D $(LIBCCMNDIR)/stdlib STDIOCMNDIR =3D $(LIBCCMNDIR)/stdio -GETOPTCMNDIR =3D $(LIBCCMNDIR)/getopt =20 -include $(TOPCMNDIR)/make.rules - - -CPPFLAGS =3D -I$(LIBCCMNDIR)/include -LDFLAGS=3D -nostdlib +QEMU_CFLAGS :=3D $(filter -W%, $(QEMU_CFLAGS)) +QEMU_CFLAGS +=3D -ffreestanding -fno-delete-null-pointer-checks -msoft-flo= at +QEMU_CFLAGS +=3D -march=3Dz900 -fPIE -fno-strict-aliasing +QEMU_CFLAGS +=3D $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector) +QEMU_CFLAGS +=3D -I$(LIBCCMNDIR)/include +LDFLAGS +=3D -Wl,-pie -nostdlib =20 TARGET =3D ../libc.a =20 - all: $(TARGET) =20 -# Use the following target to build a native version of the lib -# (for example for debugging purposes): -native: - $(MAKE) CROSS=3D"" CC=3D$(HOSTCC) NATIVEBUILD=3D1 - - include $(STRINGCMNDIR)/Makefile.inc include $(CTYPECMNDIR)/Makefile.inc include $(STDLIBCMNDIR)/Makefile.inc include $(STDIOCMNDIR)/Makefile.inc -include $(GETOPTCMNDIR)/Makefile.inc - -OBJS =3D $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) $(GETOP= T_OBJS) =20 -ifneq ($(NATIVEBUILD),1) -# These parts of the libc use assembler, so they can only be compiled when -# we are _not_ building a native version. -endif +OBJS =3D $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) =20 =20 $(TARGET): $(OBJS) - $(AR) -rc $@ $(OBJS) - $(RANLIB) $@ - + $(call quiet-command,$(AR) -rc $@ $(OBJS),"AR","$(TARGET_DIR)$@") =20 clean: - $(RM) $(TARGET) $(OBJS) + rm -f $(TARGET) $(OBJS) =20 distclean: clean diff --git a/pc-bios/s390-ccw/libc/ctype/Makefile.inc b/pc-bios/s390-ccw/li= bc/ctype/Makefile.inc index 25513a9..6d4bec3 100644 --- a/pc-bios/s390-ccw/libc/ctype/Makefile.inc +++ b/pc-bios/s390-ccw/libc/ctype/Makefile.inc @@ -17,4 +17,5 @@ CTYPE_SRCS =3D $(CTYPE_SRC_C:%=3D$(CTYPECMNDIR)/%) $(CTYP= E_SRC_ASM:%=3D$(CTYPECMNDIR)/ CTYPE_OBJS =3D $(CTYPE_SRC_C:%.c=3D%.o) $(CTYPE_SRC_ASM:%.S=3D%.o) =20 %.o : $(CTYPECMNDIR)/%.c - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $($@-cflags) \ + -c -o $@ $<,"CC","$(TARGET_DIR)$@") diff --git a/pc-bios/s390-ccw/libc/stdio/Makefile.inc b/pc-bios/s390-ccw/li= bc/stdio/Makefile.inc index ac5302d..1281b57 100644 --- a/pc-bios/s390-ccw/libc/stdio/Makefile.inc +++ b/pc-bios/s390-ccw/libc/stdio/Makefile.inc @@ -11,13 +11,14 @@ # ************************************************************************= ****/ =20 =20 -STDIO_SRC_C =3D fscanf.c sprintf.c vfprintf.c vsnprintf.c vsprintf.c fprin= tf.c \ - printf.c setvbuf.c putc.c puts.c putchar.c scanf.c stdchnls.c \ - vfscanf.c vsscanf.c fileno.c +STDIO_SRC_C =3D sprintf.c vfprintf.c vsnprintf.c vsprintf.c fprintf.c \ + printf.c setvbuf.c putc.c puts.c putchar.c stdchnls.c \ + fileno.c =20 STDIO_SRC_ASM =3D=20 STDIO_SRCS =3D $(STDIO_SRC_C:%=3D$(STDIOCMNDIR)/%) $(STDIO_SRC_ASM:%=3D$(S= TDIOCMNDIR)/%) STDIO_OBJS =3D $(STDIO_SRC_C:%.c=3D%.o) $(STDIO_SRC_ASM:%.S=3D%.o) =20 %.o : $(STDIOCMNDIR)/%.c - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $($@-cflags) \ + -c -o $@ $<,"CC","$(TARGET_DIR)$@") diff --git a/pc-bios/s390-ccw/libc/stdlib/Makefile.inc b/pc-bios/s390-ccw/l= ibc/stdlib/Makefile.inc index 702f6d7..4b3cd67 100644 --- a/pc-bios/s390-ccw/libc/stdlib/Makefile.inc +++ b/pc-bios/s390-ccw/libc/stdlib/Makefile.inc @@ -19,4 +19,5 @@ STDLIB_SRCS =3D $(STDLIB_SRC_C:%=3D$(STDLIBCMNDIR)/%) $(S= TDLIB_SRC_ASM:%=3D$(STDLIBCMN STDLIB_OBJS =3D $(STDLIB_SRC_C:%.c=3D%.o) $(STDLIB_SRC_ASM:%.S=3D%.o) =20 %.o : $(STDLIBCMNDIR)/%.c - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $($@-cflags) \ + -c -o $@ $<,"CC","$(TARGET_DIR)$@") diff --git a/pc-bios/s390-ccw/libc/string/Makefile.inc b/pc-bios/s390-ccw/l= ibc/string/Makefile.inc index 7ccf3c4..82cc734 100644 --- a/pc-bios/s390-ccw/libc/string/Makefile.inc +++ b/pc-bios/s390-ccw/libc/string/Makefile.inc @@ -19,4 +19,5 @@ STRING_SRCS =3D $(STRING_SRC_C:%=3D$(STRINGCMNDIR)/%) $(S= TRING_SRC_ASM:%=3D$(STRINGCMN STRING_OBJS =3D $(STRING_SRC_C:%.c=3D%.o) $(STRING_SRC_ASM:%.S=3D%.o) =20 %.o : $(STRINGCMNDIR)/%.c - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $($@-cflags) \ + -c -o $@ $<,"CC","$(TARGET_DIR)$@") diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 2089274..410d9ac 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -11,6 +11,8 @@ #ifndef S390_CCW_H #define S390_CCW_H =20 +#include + /* #define DEBUG */ =20 typedef unsigned char u8; @@ -18,7 +20,6 @@ typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; typedef unsigned long ulong; -typedef long size_t; typedef int bool; typedef unsigned char uint8_t; typedef unsigned short uint16_t; @@ -39,9 +40,7 @@ typedef unsigned long long __u64; #ifndef EBUSY #define EBUSY 2 #endif -#ifndef NULL -#define NULL 0 -#endif + #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif @@ -88,18 +87,6 @@ ulong get_second(void); /* bootmap.c */ void zipl_load(void); =20 -static inline void *memset(void *s, int c, size_t n) -{ - int i; - unsigned char *p =3D s; - - for (i =3D 0; i < n; i++) { - p[i] =3D c; - } - - return s; -} - static inline void fill_hex(char *out, unsigned char val) { const char hex[] =3D "0123456789abcdef"; @@ -169,17 +156,6 @@ static inline void sleep(unsigned int seconds) } } =20 -static inline void *memcpy(void *s1, const void *s2, size_t n) -{ - uint8_t *p1 =3D s1; - const uint8_t *p2 =3D s2; - - while (n--) { - p1[n] =3D p2[n]; - } - return s1; -} - static inline void IPL_assert(bool term, const char *message) { if (!term) { --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564328992109.74243895597169; Tue, 27 Jun 2017 04:52:08 -0700 (PDT) Received: from localhost ([::1]:51852 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp2N-0002Gx-5X for importer@patchew.org; Tue, 27 Jun 2017 07:52:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54704) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPoyw-0007s5-Kg for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPoyv-0003g3-S0 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:34 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33606) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPoyv-0003eT-M9 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:33 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9D6897D0E7; Tue, 27 Jun 2017 11:48:32 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id B832353CE3; Tue, 27 Jun 2017 11:48:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 9D6897D0E7 Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 9D6897D0E7 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:09 +0200 Message-Id: <1498564100-10045-4-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Tue, 27 Jun 2017 11:48:32 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 03/14] pc-bios/s390-ccw: Add a write() function for stdio X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The stdio functions from the SLOF libc need a write() function for printing text to stdout/stderr. Let's implement this function by refactoring the code from sclp_print(). Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/sclp.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c index a1639ba..a23bdd3 100644 --- a/pc-bios/s390-ccw/sclp.c +++ b/pc-bios/s390-ccw/sclp.c @@ -8,6 +8,7 @@ * directory. */ =20 +#include #include "s390-ccw.h" #include "sclp.h" =20 @@ -51,34 +52,29 @@ void sclp_setup(void) sclp_set_write_mask(); } =20 -static int _strlen(const char *str) +ssize_t write(int fd, const void *buf, size_t len) { - int i; - for (i =3D 0; *str; i++) - str++; - return i; -} - -static void _memcpy(char *dest, const char *src, int len) -{ - int i; - for (i =3D 0; i < len; i++) - dest[i] =3D src[i]; -} - -void sclp_print(const char *str) -{ - int len =3D _strlen(str); WriteEventData *sccb =3D (void *)_sccb; =20 + if (fd !=3D 1 && fd !=3D 2) { + return -EIO; + } + sccb->h.length =3D sizeof(WriteEventData) + len; sccb->h.function_code =3D SCLP_FC_NORMAL_WRITE; sccb->ebh.length =3D sizeof(EventBufferHeader) + len; sccb->ebh.type =3D SCLP_EVENT_ASCII_CONSOLE_DATA; sccb->ebh.flags =3D 0; - _memcpy(sccb->data, str, len); + memcpy(sccb->data, buf, len); =20 sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); + + return len; +} + +void sclp_print(const char *str) +{ + write(1, str, strlen(str)); } =20 void sclp_get_loadparm_ascii(char *loadparm) --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564433028885.6571988708188; Tue, 27 Jun 2017 04:53:53 -0700 (PDT) Received: from localhost ([::1]:51859 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp43-00046T-Q6 for importer@patchew.org; Tue, 27 Jun 2017 07:53:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54724) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPoyy-0007uW-Vt for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPoyx-0003hY-Vk for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:37 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60354) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPoyx-0003gr-NE for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:35 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AA0878E254; Tue, 27 Jun 2017 11:48:34 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 01C2717DE7; Tue, 27 Jun 2017 11:48:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com AA0878E254 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com AA0878E254 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:10 +0200 Message-Id: <1498564100-10045-5-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 27 Jun 2017 11:48:34 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 04/14] pc-bios/s390-ccw: Add implementation of sbrk() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" To be able to use malloc() and friends from the SLOF libc, we need to provide an implementation of the sbrk() function. This patch adds such an implemenation, which has been taken from the SLOF firmware, too. Since the sbrk() function uses a big array as the heap, we now also have got to lower the fwbase in hw/s390x/ipl.c accordingly. Signed-off-by: Thomas Huth --- hw/s390x/ipl.c | 2 +- pc-bios/s390-ccw/Makefile | 2 +- pc-bios/s390-ccw/sbrk.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 pc-bios/s390-ccw/sbrk.c diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 4e6469d..913eee5 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -113,7 +113,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **= errp) * even if an external kernel has been defined. */ if (!ipl->kernel || ipl->enforce_bios) { - uint64_t fwbase =3D (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xf= fffUL; + uint64_t fwbase =3D (MIN(ram_size, 0x80000000U) - 0x400000) & ~0xf= fffUL; =20 if (bios_name =3D=3D NULL) { bios_name =3D ipl->firmware; diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 3371c5b..8fbefe8 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -10,7 +10,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) .PHONY : all clean build-all libc.a =20 OBJECTS =3D start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o -OBJECTS +=3D libc.a +OBJECTS +=3D libc.a sbrk.o QEMU_CFLAGS :=3D $(filter -W%, $(QEMU_CFLAGS)) QEMU_CFLAGS +=3D -ffreestanding -fno-delete-null-pointer-checks -msoft-flo= at QEMU_CFLAGS +=3D -march=3Dz900 -fPIE -fno-strict-aliasing diff --git a/pc-bios/s390-ccw/sbrk.c b/pc-bios/s390-ccw/sbrk.c new file mode 100644 index 0000000..2ec1b5f --- /dev/null +++ b/pc-bios/s390-ccw/sbrk.c @@ -0,0 +1,39 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include + +#define HEAP_SIZE 0x200000 + + +static char heap[HEAP_SIZE]; +static char *actptr; + +void *sbrk(int increment) +{ + char *oldptr; + + /* Called for the first time? Then init the actual pointer */ + if (!actptr) { + actptr =3D heap; + } + + if (actptr + increment > heap + HEAP_SIZE) { + /* Out of memory */ + return (void *)-1; + } + + oldptr =3D actptr; + actptr +=3D increment; + + return oldptr; +} --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564664051662.6674450493903; Tue, 27 Jun 2017 04:57:44 -0700 (PDT) Received: from localhost ([::1]:51879 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp7m-0006fq-1x for importer@patchew.org; Tue, 27 Jun 2017 07:57:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54999) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozL-0008Ij-3k for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPoz1-0003km-EB for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:59 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33890) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPoz0-0003jp-Kd for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:39 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8A253FEEE9; Tue, 27 Jun 2017 11:48:37 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 050EF60600; Tue, 27 Jun 2017 11:48:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8A253FEEE9 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 8A253FEEE9 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:11 +0200 Message-Id: <1498564100-10045-6-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 27 Jun 2017 11:48:37 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 05/14] pc-bios/s390-ccw: Add the TFTP network loading stack from SLOF X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add the files for TFTP network loading from SLOF to the s390-ccw firmware. The files have been copied unmodified from SLOF commit ID 62674aabe20612a9786fa03e87cf6916ba97a99a an will be adjusted for the s390-ccw firmware by the following commits. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libnet/Makefile | 50 ++ pc-bios/s390-ccw/libnet/args.c | 179 +++++++ pc-bios/s390-ccw/libnet/args.h | 23 + pc-bios/s390-ccw/libnet/dhcp.c | 955 +++++++++++++++++++++++++++++++++= ++++ pc-bios/s390-ccw/libnet/dhcp.h | 49 ++ pc-bios/s390-ccw/libnet/dhcpv6.c | 212 ++++++++ pc-bios/s390-ccw/libnet/dhcpv6.h | 154 ++++++ pc-bios/s390-ccw/libnet/dns.c | 526 ++++++++++++++++++++ pc-bios/s390-ccw/libnet/dns.h | 28 ++ pc-bios/s390-ccw/libnet/ethernet.c | 189 ++++++++ pc-bios/s390-ccw/libnet/ethernet.h | 47 ++ pc-bios/s390-ccw/libnet/icmpv6.c | 409 ++++++++++++++++ pc-bios/s390-ccw/libnet/icmpv6.h | 135 ++++++ pc-bios/s390-ccw/libnet/ipv4.c | 898 ++++++++++++++++++++++++++++++++++ pc-bios/s390-ccw/libnet/ipv4.h | 97 ++++ pc-bios/s390-ccw/libnet/ipv6.c | 774 ++++++++++++++++++++++++++++++ pc-bios/s390-ccw/libnet/ipv6.h | 188 ++++++++ pc-bios/s390-ccw/libnet/ndp.c | 184 +++++++ pc-bios/s390-ccw/libnet/ndp.h | 72 +++ pc-bios/s390-ccw/libnet/netapps.h | 28 ++ pc-bios/s390-ccw/libnet/netload.c | 868 +++++++++++++++++++++++++++++++++ pc-bios/s390-ccw/libnet/tcp.c | 46 ++ pc-bios/s390-ccw/libnet/tcp.h | 27 ++ pc-bios/s390-ccw/libnet/tftp.c | 594 +++++++++++++++++++++++ pc-bios/s390-ccw/libnet/tftp.h | 52 ++ pc-bios/s390-ccw/libnet/time.h | 6 + pc-bios/s390-ccw/libnet/udp.c | 115 +++++ pc-bios/s390-ccw/libnet/udp.h | 53 ++ 28 files changed, 6958 insertions(+) create mode 100644 pc-bios/s390-ccw/libnet/Makefile create mode 100644 pc-bios/s390-ccw/libnet/args.c create mode 100644 pc-bios/s390-ccw/libnet/args.h create mode 100644 pc-bios/s390-ccw/libnet/dhcp.c create mode 100644 pc-bios/s390-ccw/libnet/dhcp.h create mode 100644 pc-bios/s390-ccw/libnet/dhcpv6.c create mode 100644 pc-bios/s390-ccw/libnet/dhcpv6.h create mode 100644 pc-bios/s390-ccw/libnet/dns.c create mode 100644 pc-bios/s390-ccw/libnet/dns.h create mode 100644 pc-bios/s390-ccw/libnet/ethernet.c create mode 100644 pc-bios/s390-ccw/libnet/ethernet.h create mode 100644 pc-bios/s390-ccw/libnet/icmpv6.c create mode 100644 pc-bios/s390-ccw/libnet/icmpv6.h create mode 100644 pc-bios/s390-ccw/libnet/ipv4.c create mode 100644 pc-bios/s390-ccw/libnet/ipv4.h create mode 100644 pc-bios/s390-ccw/libnet/ipv6.c create mode 100644 pc-bios/s390-ccw/libnet/ipv6.h create mode 100644 pc-bios/s390-ccw/libnet/ndp.c create mode 100644 pc-bios/s390-ccw/libnet/ndp.h create mode 100644 pc-bios/s390-ccw/libnet/netapps.h create mode 100644 pc-bios/s390-ccw/libnet/netload.c create mode 100644 pc-bios/s390-ccw/libnet/tcp.c create mode 100644 pc-bios/s390-ccw/libnet/tcp.h create mode 100644 pc-bios/s390-ccw/libnet/tftp.c create mode 100644 pc-bios/s390-ccw/libnet/tftp.h create mode 100644 pc-bios/s390-ccw/libnet/time.h create mode 100644 pc-bios/s390-ccw/libnet/udp.c create mode 100644 pc-bios/s390-ccw/libnet/udp.h diff --git a/pc-bios/s390-ccw/libnet/Makefile b/pc-bios/s390-ccw/libnet/Mak= efile new file mode 100644 index 0000000..83ac1e5 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/Makefile @@ -0,0 +1,50 @@ +# ************************************************************************= ***** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ************************************************************************= ****/ + +ifndef TOP + TOP =3D $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +CFLAGS +=3D -I. -I.. -I../libc/include -I$(TOP)/include + +SRCS =3D ethernet.c ipv4.c udp.c tcp.c dns.c bootp.c dhcp.c tftp.c \ + ipv6.c dhcpv6.c icmpv6.c ndp.c netload.c ping.c args.c + +OBJS =3D $(SRCS:%.c=3D%.o) + +TARGET =3D ../libnet.a + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/pc-bios/s390-ccw/libnet/args.c b/pc-bios/s390-ccw/libnet/args.c new file mode 100644 index 0000000..3f057c3 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/args.c @@ -0,0 +1,179 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include +#include +#include +#include "args.h" + +/** + * Returns pointer of the n'th argument within a string. + * + * @param arg_str string with arguments, separated with ',' + * @param index index of the requested arguments within arg_str + * @return pointer of argument[index] on success + * NULL if index is out of range + */ +const char * +get_arg_ptr(const char *arg_str, unsigned int index) +{ + unsigned int i; + + for (i =3D 0; i < index; ++i) { + for (; *arg_str !=3D ',' && *arg_str !=3D 0; ++arg_str); + if (*arg_str =3D=3D 0) + return 0; + ++arg_str; + } + return arg_str; +} + +/** + * Returns number of arguments within a string. + * + * @param arg_str string with arguments, separated with ',' + * @return number of arguments + */ +unsigned int +get_args_count(const char *arg_str) +{ + unsigned int count =3D 1; + + while ((arg_str =3D get_arg_ptr(arg_str, 1)) !=3D 0) + ++count; + return count; +} + +/** + * Returns the length of the first argument. + * + * @param arg_str string with arguments, separated with ',' + * @return length of first argument + */ +unsigned int +get_arg_length(const char *arg_str) +{ + unsigned int i; + + for (i =3D 0; *arg_str !=3D ',' && *arg_str !=3D 0; ++i) + ++arg_str; + return i; +} + +/** + * Copy the n'th argument within a string into a buffer in respect + * to a limited buffer size + * + * @param arg_str string with arguments, separated with ',' + * @param index index of the requested arguments within arg_str + * @param buffer pointer to the buffer + * @param length size of the buffer + * @return pointer of buffer on success + * NULL if index is out of range. + */ +char * +argncpy(const char *arg_str, unsigned int index, char *buffer, + unsigned int length) +{ + const char *ptr =3D get_arg_ptr(arg_str, index); + unsigned int len; + + if (!ptr) + return 0; + len =3D get_arg_length(ptr); + if (!strncpy(buffer, ptr, length)) + return 0; + buffer[len] =3D 0; + return buffer; +} + +/** + * Converts "255.255.255.255\nn" -> char[4] =3D { 0xff, 0xff, 0xff, 0xff } + * *netmask =3D subnet_netmask(nn) + * + * @param str string to be converted + * @param ip in case of SUCCESS - 32-bit long IP + * in case of FAULT - zero + * @param netmask return netmask if there is a valid /nn encoding in IP + * @return TRUE - IP converted successfully; + * FALSE - error condition occurs (e.g. bad format) + */ +int +strtoip_netmask(const char *str, char ip[4], unsigned int *netmask) +{ + char octet[10]; + int res; + unsigned int i =3D 0, len, has_nn =3D 0; + + while (*str !=3D 0) { + if (i > 3 || !isdigit(*str)) + return 0; + if (strstr(str, ".") !=3D NULL) { + len =3D (int16_t) (strstr(str, ".") - str); + if (len >=3D 10) + return 0; + strncpy(octet, str, len); + octet[len] =3D 0; + str +=3D len; + } else if (strchr(str, '\\') !=3D NULL) { + len =3D (short) (strchr(str, '\\') - str); + if (len >=3D 10) + return 0; + strncpy(octet, str, len); + octet[len] =3D 0; + str +=3D len; + has_nn =3D 1; + } else { + strncpy(octet, str, 9); + octet[9] =3D 0; + str +=3D strlen(octet); + } + res =3D strtol(octet, NULL, 10); + if ((res > 255) || (res < 0)) + return 0; + ip[i] =3D (char) res; + i++; + if (*str =3D=3D '.') + str++; + if(has_nn) { + str++; + strncpy(octet, str, 9); + octet[9] =3D 0; + res =3D strtol(octet, NULL, 10); + str +=3D strlen(octet); + if (res > 31 || res < 1) + return 0; + if (netmask) + *netmask =3D 0xFFFFFFFF << (32 - res); + } + } + + if (i !=3D 4) + return 0; + return -1; +} + +/** + * Converts "255.255.255.255" -> char[4] =3D { 0xff, 0xff, 0xff, 0xff } + * + * @param str string to be converted + * @param ip in case of SUCCESS - 32-bit long IP + * in case of FAULT - zero + * @return TRUE - IP converted successfully; + * FALSE - error condition occurs (e.g. bad format) + */ +int +strtoip(const char *str, char ip[4]) +{ + return strtoip_netmask(str, ip, NULL); +} diff --git a/pc-bios/s390-ccw/libnet/args.h b/pc-bios/s390-ccw/libnet/args.h new file mode 100644 index 0000000..1ede9a8 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/args.h @@ -0,0 +1,23 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _ARGS_H +#define _ARGS_H + +const char *get_arg_ptr(const char *, unsigned int); +unsigned int get_args_count(const char *); +unsigned int get_arg_length(const char *); +char *argncpy(const char *, unsigned int, char *, unsigned int); +int strtoip(const char *, char[4]); +int strtoip_netmask(const char *, char[4], unsigned int *netmask); + +#endif /* _ARGS_H */ diff --git a/pc-bios/s390-ccw/libnet/dhcp.c b/pc-bios/s390-ccw/libnet/dhcp.c new file mode 100644 index 0000000..0cb4fa4 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/dhcp.c @@ -0,0 +1,955 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +/******************************* ALGORITHMS ******************************/ + +/** \file dhcp.c
+ * **************** State-transition diagram for DHCP client  *************
+ *
+ *   +---------+                  Note: DHCP-server msg / DHCP-client msg
+ *   |  INIT   |
+ *   +---------+
+ *        |
+ *        |  - / Discover
+ *        V
+ *   +---------+
+ *   | SELECT  |                     Timeout
+ *   +---------+                        |
+ *        |                             |
+ *        |  Offer / Request            |
+ *        |                             |
+ *        V                             V
+ *   +---------+     NACK / -      ***********
+ *   | REQUEST | ----------------> *  FAULT  *
+ *   +---------+                   ***********
+ *        |
+ *        |          ACK / -       ***********
+ *        +----------------------> * SUCCESS *
+ *                                 ***********
+ *
+ * ************************************************************************
+ * 
*/ + + +/********************** DEFINITIONS & DECLARATIONS ***********************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* DHCP Message Types */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNACK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +/* DHCP Option Codes */ +#define DHCP_MASK 1 +#define DHCP_ROUTER 3 +#define DHCP_DNS 6 +#define DHCP_REQUESTED_IP 50 +#define DHCP_OVERLOAD 52 +#define DHCP_MSG_TYPE 53 +#define DHCP_SERVER_ID 54 +#define DHCP_REQUEST_LIST 55 +#define DHCP_TFTP_SERVER 66 +#define DHCP_BOOTFILE 67 +#define DHCP_CLIENT_ARCH 93 +#define DHCP_ENDOPT 0xFF +#define DHCP_PADOPT 0x00 + +/* "file/sname" overload option values */ +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_BOTH 3 + +/* DHCP states codes */ +#define DHCP_STATE_SELECT 1 +#define DHCP_STATE_REQUEST 2 +#define DHCP_STATE_SUCCESS 3 +#define DHCP_STATE_FAULT 4 + +/* DHCP Client Architecture */ +#ifndef DHCPARCH +#define USE_DHCPARCH 0 +#define DHCPARCH 0 +#else +#define USE_DHCPARCH 1 +#endif + +static uint8_t dhcp_magic[] =3D {0x63, 0x82, 0x53, 0x63}; +/**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */ + +/** \struct dhcp_options_t + * This structure is used to fill options in DHCP-msg during transmitting + * or to retrieve options from DHCP-msg during receiving. + *

+ * If flag[i] =3D=3D TRUE then field for i-th option retains valid value = and + * information from this field may retrived (in case of receiving) or will + * be transmitted (in case of transmitting). + * + */ +typedef struct { + uint8_t flag[256]; /**< Show if corresponding opt. is valid */ + uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th + option will be requested from server */ + uint32_t server_ID; /**< o.54 Identifies DHCP-server */ + uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */ + uint32_t dns_IP; /**< o. 6 DNS IP */ + uint32_t router_IP; /**< o. 3 Router IP */ + uint32_t subnet_mask; /**< o. 1 Subnet mask */ + uint8_t msg_type; /**< o.53 DHCP-message type */ + uint8_t overload; /**< o.52 Overload sname/file fields */ + int8_t tftp_server[256]; /**< o.66 TFTP server name */ + int8_t bootfile[256]; /**< o.67 Boot file name */ + uint16_t client_arch; /**< o.93 Client architecture type */ +} dhcp_options_t; + +/** Stores state of DHCP-client (refer to State-transition diagram) */ +static uint8_t dhcp_state; + + +/***************************** PROTOTYPES ********************************/ + +static int32_t dhcp_attempt(int fd); + +static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * o= pt_struct); + +static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, + dhcp_options_t * opt_struct); + +static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, + uint8_t src_options[], uint32_t src_len); + +static int8_t dhcp_find_option(uint8_t options[], uint32_t len, + uint8_t op_code, uint32_t * op_offset); + +static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, + uint8_t * new_option); + +static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, + uint32_t dst_offset, uint8_t * new_option); + +static void dhcp_send_discover(int fd); + +static void dhcp_send_request(int fd); + +/***************************** LOCAL VARIABLES ***************************/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static uint32_t dhcp_own_ip =3D 0; +static uint32_t dhcp_server_ip =3D 0; +static uint32_t dhcp_siaddr_ip =3D 0; +static char dhcp_filename[256]; +static char dhcp_tftp_name[256]; +static uint32_t dhcp_xid; + +static char * response_buffer; + +/***************************** IMPLEMENTATION ****************************/ + +void dhcpv4_generate_transaction_id(void) +{ + dhcp_xid =3D (rand() << 16) ^ rand(); +} + +int32_t dhcpv4(char *ret_buffer, filename_ip_t *fn_ip) +{ + uint32_t dhcp_tftp_ip =3D 0; + int fd =3D fn_ip->fd; + + strcpy(dhcp_filename, ""); + strcpy(dhcp_tftp_name, ""); + + response_buffer =3D ret_buffer; + + if (dhcp_attempt(fd) =3D=3D 0) + return -1; + + if (fn_ip->own_ip) { + dhcp_own_ip =3D fn_ip->own_ip; + } + if (fn_ip->server_ip) { + dhcp_siaddr_ip =3D fn_ip->server_ip; + } + if(fn_ip->filename[0] !=3D 0) { + strcpy(dhcp_filename, (char *) fn_ip->filename); + } + + // TFTP SERVER + if (!strlen(dhcp_tftp_name)) { + if (!dhcp_siaddr_ip) { + // ERROR: TFTP name is not presented + return -3; + } + + // take TFTP-ip from siaddr field + dhcp_tftp_ip =3D dhcp_siaddr_ip; + } + else { + // TFTP server defined by its name + if (!strtoip(dhcp_tftp_name, (char *)&dhcp_tftp_ip)) { + if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&dhcp_tftp_ip, 4)) { + // DNS error - can't obtain TFTP-server name + // Use TFTP-ip from siaddr field, if presented + if (dhcp_siaddr_ip) { + dhcp_tftp_ip =3D dhcp_siaddr_ip; + } + else { + // ERROR: Can't obtain TFTP server IP + return -4; + } + } + } + } + + // Store configuration info into filename_ip strucutre + fn_ip -> own_ip =3D dhcp_own_ip; + fn_ip -> server_ip =3D dhcp_tftp_ip; + strcpy((char *) fn_ip -> filename, dhcp_filename); + + return 0; +} + +/** + * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram + */ +static int32_t dhcp_attempt(int fd) +{ + int sec; + + // Send DISCOVER message and switch DHCP-client to SELECT state + dhcp_send_discover(fd); + + dhcp_state =3D DHCP_STATE_SELECT; + + // setting up a timer with a timeout of two seconds + for (sec =3D 0; sec < 2; sec++) { + set_timer(TICKS_SEC); + do { + receive_ether(fd); + + // Wait until client will switch to Final state or Timeout occurs + switch (dhcp_state) { + case DHCP_STATE_SUCCESS : + return 1; + case DHCP_STATE_FAULT : + return 0; + } + } while (get_timer() > 0); + } + + // timeout + return 0; +} + +/** + * DHCP: Supplements DHCP-message with options stored in structure. + * For more information about option coding see dhcp_options_t. + * + * @param opt_field Points to the "vend" field of DHCP-message + * (destination) + * @param opt_struct this structure stores info about the options which + * will be added to DHCP-message (source) + * @return TRUE - options packed; + * FALSE - error condition occurs. + * @see dhcp_options_t + */ +static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * o= pt_struct) +{ + uint8_t * options =3D opt_field; + uint16_t i, sum; // used to define is any options set + + // magic + memcpy(options, dhcp_magic, 4); + options +=3D 4; + + // fill message type + switch (opt_struct -> msg_type) { + case DHCPDISCOVER : + case DHCPREQUEST : + case DHCPDECLINE : + case DHCPINFORM : + case DHCPRELEASE : + options[0] =3D DHCP_MSG_TYPE; + options[1] =3D 1; + options[2] =3D opt_struct -> msg_type; + options +=3D 3; + break; + default : + return 0; // Unsupported DHCP-message + } + + if (opt_struct -> overload) { + options[0] =3D DHCP_OVERLOAD; + options[1] =3D 0x01; + options[2] =3D opt_struct -> overload; + options +=3D3; + } + + if (opt_struct -> flag[DHCP_REQUESTED_IP]) { + options[0] =3D DHCP_REQUESTED_IP; + options[1] =3D 0x04; + * (uint32_t *) (options + 2) =3D htonl (opt_struct -> requested_IP); + options +=3D6; + } + + if (opt_struct -> flag[DHCP_SERVER_ID]) { + options[0] =3D DHCP_SERVER_ID; + options[1] =3D 0x04; + * (uint32_t *) (options + 2) =3D htonl (opt_struct -> server_ID); + options +=3D6; + } + + sum =3D 0; + for (i =3D 0; i < 256; i++) + sum +=3D opt_struct -> request_list[i]; + + if (sum) { + options[0] =3D DHCP_REQUEST_LIST; + options[1] =3D sum; + options +=3D 2; + for (i =3D 0; i < 256; i++) { + if (opt_struct -> request_list[i]) { + options[0] =3D i; options++; + } + } + } + + if (opt_struct -> flag[DHCP_TFTP_SERVER]) { + options[0] =3D DHCP_TFTP_SERVER; + options[1] =3D strlen((char *) opt_struct -> tftp_server) + 1; + memcpy(options + 2, opt_struct -> tftp_server, options[1]); + options +=3D options[1] + 2; + } + + if (opt_struct -> flag[DHCP_BOOTFILE]) { + options[0] =3D DHCP_BOOTFILE; + options[1] =3D strlen((char *) opt_struct -> bootfile) + 1; + memcpy(options + 2, opt_struct -> bootfile, options[1]); + options +=3D options[1] + 2; + } + + if (opt_struct -> flag[DHCP_CLIENT_ARCH]) { + options[0] =3D DHCP_CLIENT_ARCH; + options[1] =3D 2; + options[2] =3D (DHCPARCH >> 8); + options[3] =3D DHCPARCH & 0xff; + options +=3D 4; + } + + // end options + options[0] =3D 0xFF; + options++; + + return 1; +} + +/** + * DHCP: Extracts encoded options from DHCP-message into the structure. + * For more information about option coding see dhcp_options_t. + * + * @param opt_field Points to the "options" field of DHCP-message + * (source). + * @param opt_len Length of "options" field. + * @param opt_struct this structure stores info about the options which + * was extracted from DHCP-message (destination). + * @return TRUE - options extracted; + * FALSE - error condition occurs. + * @see dhcp_options_t + */ +static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, + dhcp_options_t * opt_struct) +{ + uint32_t offset =3D 0; + + memset(opt_struct, 0, sizeof(dhcp_options_t)); + + // magic + if (memcmp(opt_field, dhcp_magic, 4)) { + return 0; + } + + offset +=3D 4; + while (offset < opt_len) { + opt_struct -> flag[opt_field[offset]] =3D 1; + switch(opt_field[offset]) { + case DHCP_OVERLOAD : + opt_struct -> overload =3D opt_field[offset + 2]; + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_REQUESTED_IP : + opt_struct -> requested_IP =3D htonl(* (uint32_t *) (opt_field + offset= + 2)); + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_MASK : + opt_struct -> flag[DHCP_MASK] =3D 1; + opt_struct -> subnet_mask =3D htonl(* (uint32_t *) (opt_field + offset = + 2)); + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_DNS : + opt_struct -> flag[DHCP_DNS] =3D 1; + opt_struct -> dns_IP =3D htonl(* (uint32_t *) (opt_field + offset + 2)); + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_ROUTER : + opt_struct -> flag[DHCP_ROUTER] =3D 1; + opt_struct -> router_IP =3D htonl(* (uint32_t *) (opt_field + offset + = 2)); + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_MSG_TYPE : + if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9)) + opt_struct -> msg_type =3D opt_field[offset + 2]; + else + return 0; + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_SERVER_ID : + opt_struct -> server_ID =3D htonl(* (uint32_t *) (opt_field + offset + = 2)); + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_TFTP_SERVER : + memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[off= set + 1]); + (opt_struct -> tftp_server)[opt_field[offset + 1]] =3D 0; + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_BOOTFILE : + memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offse= t + 1]); + (opt_struct -> bootfile)[opt_field[offset + 1]] =3D 0; + offset +=3D 2 + opt_field[offset + 1]; + break; + + case DHCP_CLIENT_ARCH : + opt_struct -> client_arch =3D ((opt_field[offset + 2] << 8) & 0xFF00) |= (opt_field[offset + 3] & 0xFF); + offset +=3D 4; + break; + + case DHCP_PADOPT : + offset++; + break; + + case DHCP_ENDOPT : // End of options + return 1; + + default : + offset +=3D 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing + } + } + if (offset =3D=3D opt_len) + return 1; // options finished without 0xFF + + return 0; +} + +/** + * DHCP: Appends information from source "options" into dest "options". + * This function is used to support "file/sname" overloading. + * + * @param dst_options destanation "options" field + * @param dst_len size of dst_options (modified by this function) + * @param src_options source "options" field + * @param src_len size of src_options + * @return TRUE - options merged; + * FALSE - error condition occurs. + */ +static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, + uint8_t src_options[], uint32_t src_len) +{ + uint32_t dst_offset, src_offset =3D 0; + + // remove ENDOPT if presented + if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, &dst_offset)) + * dst_len =3D dst_offset; + + while (src_offset < src_len) { + switch(src_options[src_offset]) { + case DHCP_PADOPT: + src_offset++; + break; + case DHCP_ENDOPT: + return 1; + default: + if (dhcp_find_option(dst_options, * dst_len, + src_options[src_offset], + &dst_offset)) { + dhcp_combine_option(dst_options, dst_len, + dst_offset, + (uint8_t *) src_options + + src_offset); + } + else { + dhcp_append_option(dst_options, dst_len, src_options + src_offset); + } + src_offset +=3D 2 + src_options[src_offset + 1]; + } + } + + if (src_offset =3D=3D src_len) + return 1; + return 0; +} + +/** + * DHCP: Finds given occurrence of the option with the given code (op_code) + * in "options" field of DHCP-message. + * + * @param options "options" field of DHCP-message + * @param len length of the "options" field + * @param op_code code of the option to find + * @param op_offset SUCCESS - offset to an option occurrence; + * FAULT - offset is set to zero. + * @return TRUE - option was find; + * FALSE - option wasn't find. + */ +static int8_t dhcp_find_option(uint8_t options[], uint32_t len, + uint8_t op_code, uint32_t * op_offset) +{ + uint32_t srch_offset =3D 0; + * op_offset =3D 0; + + while (srch_offset < len) { + if (options[srch_offset] =3D=3D op_code) { + * op_offset =3D srch_offset; + return 1; + } + if (options[srch_offset] =3D=3D DHCP_ENDOPT) + return 0; + + if (options[srch_offset] =3D=3D DHCP_PADOPT) + srch_offset++; + else + srch_offset +=3D 2 + options[srch_offset + 1]; + } + return 0; +} + +/** + * DHCP: Appends new option from one list (src) into the tail + * of another option list (dst) + * + * @param dst_options "options" field of DHCP-message + * @param dst_len length of the "options" field (modified) + * @param new_option points to an option in another list (src) + */ +static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, + uint8_t * new_option) +{ + memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1))); + * dst_len +=3D 2 + *(new_option + 1); +} + +/** + * DHCP: This function is used when options with the same code are + * presented in both merged lists. In this case information + * about the option from one list (src) is combined (complemented) + * with information about the option in another list (dst). + * + * @param dst_options "options" field of DHCP-message + * @param dst_len length of the "options" field (modified) + * @param dst_offset offset of the option from beginning of the list + * @param new_option points to an option in another list (src) + */ +static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, + uint32_t dst_offset, uint8_t * new_option) +{ + uint8_t tmp_buffer[1024]; // use to provide safe memcpy + uint32_t tail_len; + + // move all subsequent options (allocate size for additional info) + tail_len =3D (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1]; + + memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len); + memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)), + tmp_buffer, tail_len); + + // add new_content to option + memcpy(dst_options + (* dst_len) - tail_len, new_option + 2, + * (new_option + 1)); + dst_options[dst_offset + 1] +=3D * (new_option + 1); + + // correct dst_len + * dst_len +=3D * (new_option + 1); +} + +/** + * DHCP: Sends DHCP-Discover message. Looks for DHCP servers. + */ +static void dhcp_send_discover(int fd) +{ + uint32_t packetsize =3D sizeof(struct iphdr) + + sizeof(struct udphdr) + sizeof(struct btphdr); + struct btphdr *btph; + dhcp_options_t opt; + + memset(ether_packet, 0, packetsize); + + btph =3D (struct btphdr *) (ðer_packet[ + sizeof(struct iphdr) + sizeof(struct udphdr)]); + + btph -> op =3D 1; + btph -> htype =3D 1; + btph -> hlen =3D 6; + btph -> xid =3D dhcp_xid; + memcpy(btph -> chaddr, get_mac_address(), 6); + + memset(&opt, 0, sizeof(dhcp_options_t)); + + opt.msg_type =3D DHCPDISCOVER; + + opt.request_list[DHCP_MASK] =3D 1; + opt.request_list[DHCP_DNS] =3D 1; + opt.request_list[DHCP_ROUTER] =3D 1; + opt.request_list[DHCP_TFTP_SERVER] =3D 1; + opt.request_list[DHCP_BOOTFILE] =3D 1; + opt.request_list[DHCP_CLIENT_ARCH] =3D USE_DHCPARCH; + + dhcp_encode_options(btph -> vend, &opt); + + fill_udphdr(ðer_packet[sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ether_packet, sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), + IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF); + + send_ipv4(fd, ether_packet, packetsize); +} + +/** + * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP. + */ +static void dhcp_send_request(int fd) +{ + uint32_t packetsize =3D sizeof(struct iphdr) + + sizeof(struct udphdr) + sizeof(struct btphdr); + struct btphdr *btph; + dhcp_options_t opt; + + memset(ether_packet, 0, packetsize); + + btph =3D (struct btphdr *) (ðer_packet[ + sizeof(struct iphdr) + sizeof(struct udphdr)]); + + btph -> op =3D 1; + btph -> htype =3D 1; + btph -> hlen =3D 6; + btph -> xid =3D dhcp_xid; + memcpy(btph -> chaddr, get_mac_address(), 6); + + memset(&opt, 0, sizeof(dhcp_options_t)); + + opt.msg_type =3D DHCPREQUEST; + memcpy(&(opt.requested_IP), &dhcp_own_ip, 4); + opt.flag[DHCP_REQUESTED_IP] =3D 1; + memcpy(&(opt.server_ID), &dhcp_server_ip, 4); + opt.flag[DHCP_SERVER_ID] =3D 1; + + opt.request_list[DHCP_MASK] =3D 1; + opt.request_list[DHCP_DNS] =3D 1; + opt.request_list[DHCP_ROUTER] =3D 1; + opt.request_list[DHCP_TFTP_SERVER] =3D 1; + opt.request_list[DHCP_BOOTFILE] =3D 1; + opt.request_list[DHCP_CLIENT_ARCH] =3D USE_DHCPARCH; + opt.flag[DHCP_CLIENT_ARCH] =3D USE_DHCPARCH; + + dhcp_encode_options(btph -> vend, &opt); + + fill_udphdr(ðer_packet[sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ether_packet, sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), + IPTYPE_UDP, 0, 0xFFFFFFFF); + + send_ipv4(fd, ether_packet, packetsize); +} + + +/** + * DHCP: Sends DHCP-Release message. Releases occupied IP. + */ +void dhcp_send_release(int fd) +{ + uint32_t packetsize =3D sizeof(struct iphdr) + + sizeof(struct udphdr) + sizeof(struct btphdr); + struct btphdr *btph; + dhcp_options_t opt; + + btph =3D (struct btphdr *) (ðer_packet[ + sizeof(struct iphdr) + sizeof(struct udphdr)]); + + memset(ether_packet, 0, packetsize); + + btph -> op =3D 1; + btph -> htype =3D 1; + btph -> hlen =3D 6; + btph -> xid =3D dhcp_xid; + strcpy((char *) btph -> file, ""); + memcpy(btph -> chaddr, get_mac_address(), 6); + btph -> ciaddr =3D htonl(dhcp_own_ip); + + memset(&opt, 0, sizeof(dhcp_options_t)); + + opt.msg_type =3D DHCPRELEASE; + opt.server_ID =3D dhcp_server_ip; + opt.flag[DHCP_SERVER_ID] =3D 1; + + dhcp_encode_options(btph -> vend, &opt); + + fill_udphdr(ðer_packet[sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ether_packet, sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP, + dhcp_own_ip, dhcp_server_ip); + + send_ipv4(fd, ether_packet, packetsize); +} + +/** + * DHCP: Handles DHCP-messages according to Receive-handle diagram. + * Changes the state of DHCP-client. + * + * @param fd socket descriptor + * @param packet BootP/DHCP-packet to be handled + * @param packetsize length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see btphdr + */ + +int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) +{ + struct btphdr * btph; + struct iphdr * iph; + dhcp_options_t opt; + + memset(&opt, 0, sizeof(dhcp_options_t)); + btph =3D (struct btphdr *) packet; + iph =3D (struct iphdr *) packet - sizeof(struct udphdr) - + sizeof(struct iphdr); + + if (btph->op !=3D 2) + return -1; /* It is not a Bootp/DHCP reply */ + if (btph->xid !=3D dhcp_xid) + return -1; /* The transaction ID does not match */ + + if (memcmp(btph -> vend, dhcp_magic, 4)) { + // It is BootP - RFC 951 + dhcp_own_ip =3D htonl(btph -> yiaddr); + dhcp_siaddr_ip =3D htonl(btph -> siaddr); + dhcp_server_ip =3D htonl(iph -> ip_src); + + if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { + strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, + sizeof(btph -> sname)); + dhcp_tftp_name[sizeof(btph -> sname)] =3D 0; + } + + if (strlen((char *) btph -> file)) { + strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> f= ile)); + dhcp_filename[sizeof(btph -> file)] =3D 0; + } + + dhcp_state =3D DHCP_STATE_SUCCESS; + return 0; + } + + + // decode options + if (!dhcp_decode_options(btph -> vend, packetsize - + sizeof(struct btphdr) + sizeof(btph -> vend), + &opt)) { + return -1; // can't decode options + } + + if (opt.overload) { + int16_t decode_res =3D 0; + uint8_t options[1024]; // buffer for merged options + uint32_t opt_len; + + // move 1-st part of options from vend field into buffer + opt_len =3D packetsize - sizeof(struct btphdr) + + sizeof(btph -> vend) - 4; + memcpy(options, btph -> vend, opt_len + 4); + + // add other parts + switch (opt.overload) { + case DHCP_OVERLOAD_FILE: + decode_res =3D dhcp_merge_options(options + 4, &opt_len, + btph -> file, + sizeof(btph -> file)); + break; + case DHCP_OVERLOAD_SNAME: + decode_res =3D dhcp_merge_options(options + 4, &opt_len, + btph -> sname, + sizeof(btph -> sname)); + break; + case DHCP_OVERLOAD_BOTH: + decode_res =3D dhcp_merge_options(options + 4, &opt_len, + btph -> file, + sizeof(btph -> file)); + if (!decode_res) + break; + decode_res =3D dhcp_merge_options(options + 4, &opt_len, + btph -> sname, + sizeof(btph -> sname)); + break; + } + + if (!decode_res) + return -1; // bad options in sname/file fields + + // decode merged options + if (!dhcp_decode_options(options, opt_len + 4, &opt)) { + return -1; // can't decode options + } + } + + if (!opt.msg_type) { + // It is BootP with Extensions - RFC 1497 + // retrieve conf. settings from BootP - reply + dhcp_own_ip =3D htonl(btph -> yiaddr); + dhcp_siaddr_ip =3D htonl(btph -> siaddr); + if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { + strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph ->= sname)); + dhcp_tftp_name[sizeof(btph -> sname)] =3D 0; + } + + if (strlen((char *) btph -> file)) { + strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> f= ile)); + dhcp_filename[sizeof(btph -> file)] =3D 0; + } + + // retrieve DHCP-server IP from IP-header + dhcp_server_ip =3D iph -> htonl(ip_src); + + dhcp_state =3D DHCP_STATE_SUCCESS; + } + else { + // It is DHCP - RFC 2131 & RFC 2132 + // opt contains parameters from server + switch (dhcp_state) { + case DHCP_STATE_SELECT : + if (opt.msg_type =3D=3D DHCPOFFER) { + dhcp_own_ip =3D htonl(btph -> yiaddr); + dhcp_server_ip =3D opt.server_ID; + dhcp_send_request(fd); + dhcp_state =3D DHCP_STATE_REQUEST; + } + return 0; + case DHCP_STATE_REQUEST : + switch (opt.msg_type) { + case DHCPNACK : + dhcp_own_ip =3D 0; + dhcp_server_ip =3D 0; + dhcp_state =3D DHCP_STATE_FAULT; + break; + case DHCPACK : + dhcp_own_ip =3D htonl(btph -> yiaddr); + dhcp_server_ip =3D opt.server_ID; + dhcp_siaddr_ip =3D htonl(btph -> siaddr); + if (opt.flag[DHCP_TFTP_SERVER]) { + strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server); + } + else { + strcpy((char *) dhcp_tftp_name, ""); + if ((opt.overload !=3D DHCP_OVERLOAD_SNAME && + opt.overload !=3D DHCP_OVERLOAD_BOTH) && + !dhcp_siaddr_ip) { + strncpy((char *) dhcp_tftp_name, + (char *) btph->sname, + sizeof(btph -> sname)); + dhcp_tftp_name[sizeof(btph->sname)] =3D 0; + } + } + + if (opt.flag[DHCP_BOOTFILE]) { + strcpy((char *) dhcp_filename, (char *) opt.bootfile); + } + else { + strcpy((char *) dhcp_filename, ""); + if (opt.overload !=3D DHCP_OVERLOAD_FILE && + opt.overload !=3D DHCP_OVERLOAD_BOTH && + strlen((char *) btph -> file)) { + strncpy((char *) dhcp_filename, + (char *) btph->file, + sizeof(btph->file)); + dhcp_filename[sizeof(btph -> file)] =3D 0; + } + } + + dhcp_state =3D DHCP_STATE_SUCCESS; + break; + default: + break; // Unused DHCP-message - do nothing + } + break; + default : + return -1; // Illegal DHCP-client state + } + } + + if (dhcp_state =3D=3D DHCP_STATE_SUCCESS) { + + // initialize network entity with real own_ip + // to be able to answer for foreign requests + set_ipv4_address(dhcp_own_ip); + + if(response_buffer) { + if(packetsize <=3D 1720) + memcpy(response_buffer, packet, packetsize); + else + memcpy(response_buffer, packet, 1720); + } + + /* Subnet mask */ + if (opt.flag[DHCP_MASK]) { + /* Router */ + if (opt.flag[DHCP_ROUTER]) { + set_ipv4_router(opt.router_IP); + set_ipv4_netmask(opt.subnet_mask); + } + } + + /* DNS-server */ + if (opt.flag[DHCP_DNS]) { + dns_init(opt.dns_IP, 0, 4); + } + } + + return 0; +} diff --git a/pc-bios/s390-ccw/libnet/dhcp.h b/pc-bios/s390-ccw/libnet/dhcp.h new file mode 100644 index 0000000..4432c9b --- /dev/null +++ b/pc-bios/s390-ccw/libnet/dhcp.h @@ -0,0 +1,49 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _DHCP_H_ +#define _DHCP_H_ + +#include +#include "tftp.h" + +/** \struct btphdr + * A header for BootP/DHCP-messages. + * For more information see RFC 951 / RFC 2131. + */ +struct btphdr { + uint8_t op; /**< Identifies is it request (1) or reply (2) */ + uint8_t htype; /**< HW address type (ethernet usually) */ + uint8_t hlen; /**< HW address length */ + uint8_t hops; /**< This info used by relay agents (not used) */ + uint32_t xid; /**< This ID is used to match queries and replies */ + uint16_t secs; /**< Unused */ + uint16_t unused; /**< Unused */ + uint32_t ciaddr; /**< Client IP address (if client knows it) */ + uint32_t yiaddr; /**< "Your" (client) IP address */ + uint32_t siaddr; /**< Next server IP address (TFTP server IP) */ + uint32_t giaddr; /**< Gateway IP address (used by relay agents) */ + uint8_t chaddr[16]; /**< Client HW address */ + uint8_t sname[64]; /**< Server host name (TFTP server name) */ + uint8_t file[128]; /**< Boot file name */ + uint8_t vend[64]; /**< Optional parameters field (DHCP-options) */ +}; + +void dhcpv4_generate_transaction_id(void); +int bootp(char *ret_buffer, filename_ip_t *, unsigned int); +int dhcpv4(char *ret_buffer, filename_ip_t *); +void dhcp_send_release(int fd); + +/* Handles DHCP-packets, which are detected by receive_ether. */ +extern int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize); + +#endif diff --git a/pc-bios/s390-ccw/libnet/dhcpv6.c b/pc-bios/s390-ccw/libnet/dhc= pv6.c new file mode 100644 index 0000000..491d540 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/dhcpv6.c @@ -0,0 +1,212 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include +#include +#include +#include +#include +#include "ethernet.h" +#include "ipv6.h" +#include "udp.h" +#include "dhcpv6.h" +#include "tftp.h" +#include "dns.h" + +static uint8_t tid[3]; +static uint32_t dhcpv6_state =3D -1; +static filename_ip_t *my_fn_ip; + +static struct ip6addr_list_entry all_dhcpv6_ll; /* All DHCPv6 servers addr= ess */ + +void +dhcpv6_generate_transaction_id(void) +{ + /* As per RFC 3315 transaction IDs should be generated randomly */ + tid[0] =3D rand(); + tid[1] =3D rand(); + tid[2] =3D rand(); +} + +static void +send_info_request(int fd) +{ + uint8_t ether_packet[ETH_MTU_SIZE]; + uint32_t payload_length; + struct dhcp_message_header *dhcph; + + memset(ether_packet, 0, ETH_MTU_SIZE); + + /* Get an IPv6 packet */ + payload_length =3D sizeof(struct udphdr) + sizeof(struct dhcp_message_hea= der); + fill_ip6hdr (ether_packet + sizeof(struct ethhdr), + payload_length, IPTYPE_UDP, + get_ipv6_address(), &(all_dhcpv6_ll.addr)); + fill_udphdr ( ether_packet + sizeof(struct ethhdr) + sizeof(struct ip6hdr= ), + payload_length, DHCP_CLIENT_PORT, DHCP_SERVER_PORT); + dhcph =3D (struct dhcp_message_header *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr) + + sizeof(struct udphdr)); + + /* Fill in DHCPv6 data */ + dhcph->type =3D DHCP_INFORMATION_REQUEST; + memcpy( &(dhcph->transaction_id), &tid, 3); + dhcph->option.client_id.code =3D DHCPV6_OPTION_CLIENTID; + dhcph->option.client_id.length =3D 10; + dhcph->option.client_id.duid_type =3D DUID_LL; + dhcph->option.client_id.hardware_type =3D 1; + memcpy( &(dhcph->option.client_id.mac), + get_mac_address(), 6); + dhcph->option.el_time.code =3D DHCPV6_OPTION_ELAPSED_TIME; + dhcph->option.el_time.length =3D 2; + dhcph->option.el_time.time =3D 0x190; /* 4000 ms */ + dhcph->option.option_request_option.code =3D DHCPV6_OPTION_ORO; + dhcph->option.option_request_option.length =3D DHCPV6_OPTREQUEST_NUMOPTS = * 2; + dhcph->option.option_request_option.option_code[0] =3D DHCPV6_OPTION_DNS_= SERVERS; + dhcph->option.option_request_option.option_code[1] =3D DHCPV6_OPTION_DOMA= IN_LIST; + dhcph->option.option_request_option.option_code[2] =3D DHCPV6_OPTION_BOOT= _URL; + + send_ipv6(fd, ether_packet + sizeof(struct ethhdr), + sizeof(struct ip6hdr) + sizeof(struct udphdr) + + sizeof(struct dhcp_message_header)); +} + +static int32_t +dhcpv6_attempt(int fd) +{ + int sec; + + // Send information request + send_info_request(fd); + + dhcpv6_state =3D DHCPV6_STATE_SELECT; + + // setting up a timer with a timeout of two seconds + for (sec =3D 0; sec < 2; sec++) { + set_timer(TICKS_SEC); + do { + receive_ether(fd); + + // Wait until client will switch to Final state or Timeout occurs + switch (dhcpv6_state) { + case DHCP_STATUSCODE_SUCCESS: + return 1; + case DHCP_STATUSCODE_UNSPECFAIL: //FIXME + return 0; + } + } while (get_timer() > 0); + } + + // timeout + return 0; +} + +int32_t +dhcpv6 ( char *ret_buffer, void *fn_ip) +{ + int fd; + + all_dhcpv6_ll.addr.part.prefix =3D 0xff02000000000000ULL; + all_dhcpv6_ll.addr.part.interface_id =3D 0x10002ULL; + + my_fn_ip =3D (filename_ip_t *) fn_ip; + fd =3D my_fn_ip->fd; + + if( !dhcpv6_attempt(fd)) { + return -1; + } + + return 0; +} + +static void dhcp6_process_options (uint8_t *option, int32_t option_length) +{ + struct dhcp_boot_url *option_boot_url; + struct client_identifier *option_clientid; + struct server_identifier *option_serverid; + struct dhcp_dns *option_dns; + struct dhcp_dns_list *option_dns_list; + struct dhcp6_gen_option *option_gen; + char buffer[256]; + + while (option_length > 0) { + switch ((uint16_t) *(option+1)) { + case DHCPV6_OPTION_CLIENTID: + option_clientid =3D (struct client_identifier *) option; + option =3D option + option_clientid->length + 4; + option_length =3D option_length - option_clientid->length - 4; + break; + case DHCPV6_OPTION_SERVERID: + option_serverid =3D (struct server_identifier *) option; + option =3D option + option_serverid->length + 4; + option_length =3D option_length - option_serverid->length - 4; + break; + case DHCPV6_OPTION_DNS_SERVERS: + option_dns =3D (struct dhcp_dns *) option; + option =3D option + option_dns->length + 4; + option_length =3D option_length - option_dns->length - 4; + memcpy( &(my_fn_ip->dns_ip6), + option_dns->p_ip6, + IPV6_ADDR_LENGTH); + dns_init(0, option_dns->p_ip6, 6); + break; + case DHCPV6_OPTION_DOMAIN_LIST: + option_dns_list =3D (struct dhcp_dns_list *) option; + option =3D option + option_dns_list->length + 4; + option_length =3D option_length - option_dns_list->length - 4; + break; + case DHCPV6_OPTION_BOOT_URL: + option_boot_url =3D (struct dhcp_boot_url *) option; + option =3D option + option_boot_url->length + 4; + option_length =3D option_length - option_boot_url->length - 4; + strncpy((char *)buffer, + (const char *)option_boot_url->url, + (size_t)option_boot_url->length); + buffer[option_boot_url->length] =3D 0; + if (parse_tftp_args(buffer, + (char *)my_fn_ip->server_ip6.addr, + (char *)my_fn_ip->filename, + (int)my_fn_ip->fd, + option_boot_url->length) =3D=3D -1) + return; + break; + default: + option_gen =3D (struct dhcp6_gen_option *) option; + option =3D option + option_gen->length + 4; + option_length =3D option_length - option_gen->length - 4; + } + } +} + +uint32_t +handle_dhcpv6(uint8_t * packet, int32_t packetsize) +{ + + uint8_t *first_option; + int32_t option_length; + struct dhcp_message_reply *reply; + reply =3D (struct dhcp_message_reply *) packet; + + if (memcmp(reply->transaction_id, tid, 3)) + return -1; /* Wrong transaction ID */ + + if (reply->type =3D=3D 7) + dhcpv6_state =3D DHCP_STATUSCODE_SUCCESS; + + first_option =3D packet + 4; + option_length =3D packet + packetsize - first_option; + dhcp6_process_options(first_option, option_length); + + return 0; +} diff --git a/pc-bios/s390-ccw/libnet/dhcpv6.h b/pc-bios/s390-ccw/libnet/dhc= pv6.h new file mode 100644 index 0000000..02747a0 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/dhcpv6.h @@ -0,0 +1,154 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _DHCPV6_H_ +#define _DHCPV6_H_ + +#include +#include "ethernet.h" + +#define DHCPV6_STATELESS 0 +#define DHCPV6_STATEFUL 1 + +/* DHCP port numbers */ +#define DHCP_CLIENT_PORT 546 +#define DHCP_SERVER_PORT 547 + +/* DHCPv6 message types */ +#define DHCP_SOLICIT 1 +#define DHCP_ADVERTISE 2 +#define DHCP_REQUEST 3 +#define DHCP_CONFIRM 4 +#define DHCP_RENEW 5 +#define DHCP_REBIND 6 +#define DHCP_REPLY 7 +#define DHCP_RELEASE 8 +#define DHCP_DECLINE 9 +#define DHCP_RECONFIGURE 10 +#define DHCP_INFORMATION_REQUEST 11 +#define RELAY_FORW 12 +#define RELAY_REPL 13 + +/* DHCPv6 option types */ +#define DHCPV6_OPTION_CLIENTID 0x0001 +#define DHCPV6_OPTION_SERVERID 0x0002 +#define DHCPV6_OPTION_IA_NA 3 +#define DHCPV6_OPTION_IA_TA 4 +#define DHCPV6_OPTION_IAADDR 5 +#define DHCPV6_OPTION_ORO 6 +#define DHCPV6_OPTION_PREFEREN 7 +#define DHCPV6_OPTION_ELAPSED_TIME 8 +#define DHCPV6_OPTION_RELAY_MS 9 +#define DHCPV6_OPTION_AUTH 11 +#define DHCPV6_OPTION_UNICAST 12 +#define DHCPV6_OPTION_STATUS_C 13 +#define DHCPV6_OPTION_RAPID_CO 14 +#define DHCPV6_OPTION_USER_CLA 15 +#define DHCPV6_OPTION_VENDOR_C 16 +#define DHCPV6_OPTION_VENDOR_O 17 +#define DHCPV6_OPTION_INTERFAC 18 +#define DHCPV6_OPTION_RECONF_M 19 +#define DHCPV6_OPTION_RECONF_A 20 +#define DHCPV6_OPTION_DNS_SERVERS 23 +#define DHCPV6_OPTION_DOMAIN_LIST 24 +#define DHCPV6_OPTION_BOOT_URL 59 + +/* DHCPv6 status codes */ +#define DHCP_STATUSCODE_SUCCESS 0 +#define DHCP_STATUSCODE_UNSPECFAIL 1 +#define DHCP_STATUSCODE_NOADDRAVAIL 2 +#define DHCP_STATUSCODE_NOBINDING 3 +#define DHCP_STATUSCODE_NOTONLINK 4 +#define DHCP_STATUSCODE_USEMULTICAST 5 +#define DHCPV6_STATE_SELECT 6 + +/* DUID types */ +#define DUID_LLT 1 /* DUID based on Link-layer Address Plus Time */ +#define DUID_EN 2 /* DUID based on Assigned by Vendor Based on Enterprise= Number */ +#define DUID_LL 3 /* DUID based on Link-layer Address */ + +/* Prototypes */ +void dhcpv6_generate_transaction_id(void); +int32_t dhcpv6 ( char *ret_buffer, void *fn_ip); +uint32_t handle_dhcpv6(uint8_t * , int32_t); + +struct dhcp6_gen_option { + uint16_t code; + uint16_t length; +}; + +struct client_identifier { + uint16_t code; + uint16_t length; + uint16_t duid_type; + uint16_t hardware_type; + uint8_t mac[6]; +}; + +struct server_identifier { + uint16_t code; + uint16_t length; + uint16_t duid_type; + uint16_t hardware_type; + uint32_t time; + uint8_t mac[6]; +}; + +#define DHCPV6_OPTREQUEST_NUMOPTS 3 + +struct dhcp_info_request { + struct client_identifier client_id; + struct elapsed_time { + uint16_t code; + uint16_t length; + uint16_t time; + } el_time; + struct option_request { + uint16_t code; + uint16_t length; + uint16_t option_code[DHCPV6_OPTREQUEST_NUMOPTS]; + } option_request_option; +}; + +struct dhcp_message_header { + uint8_t type; /* Message type */ + uint8_t transaction_id[3]; /* Transaction id */ + struct dhcp_info_request option; +}; + +struct dhcp_dns { + uint16_t code; + uint16_t length; + uint8_t p_ip6[16]; + uint8_t s_ip6[16]; +}__attribute((packed)); + +struct dhcp_dns_list { + uint16_t code; + uint16_t length; + uint8_t domain[256]; +}__attribute((packed)); + +struct dhcp_boot_url { + uint16_t type; + uint16_t length; + uint8_t url[256]; +}; + +struct dhcp_message_reply { + uint8_t type; /* Message type */ + uint8_t transaction_id[3]; /* Transaction id */ + struct client_identifier client_id; + struct server_identifier server_id; +}; + +#endif diff --git a/pc-bios/s390-ccw/libnet/dns.c b/pc-bios/s390-ccw/libnet/dns.c new file mode 100644 index 0000000..a7313a9 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/dns.c @@ -0,0 +1,526 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +/********************** DEFINITIONS & DECLARATIONS ***********************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DNS_FLAG_MSGTYPE 0xF800 /**< Message type mask (opcode) */ +#define DNS_FLAG_SQUERY 0x0000 /**< Standard query type */ +#define DNS_FLAG_SRESPONSE 0x8000 /**< Standard response type */ +#define DNS_FLAG_RD 0x0100 /**< Recursion desired flag */ +#define DNS_FLAG_RCODE 0x000F /**< Response code mask + (stores err.cond.) code */ +#define DNS_RCODE_NERROR 0 /**< "No errors" code */ + +#define DNS_QTYPE_A 1 /**< A 32-bit IP record type */ +#define DNS_QTYPE_AAAA 0x1c /**< 128-bit IPv6 record type */ +#define DNS_QTYPE_CNAME 5 /**< Canonical name record type */ + +#define DNS_QCLASS_IN 1 /**< Query class for internet msgs */ + +/** \struct dnshdr + * A header for DNS-messages (see RFC 1035, paragraph 4.1.1). + *

+ * DNS-message consist of DNS-header and 4 optional sections, + * arranged in the following order:

    + *
  • DNS-header + *
  • question section + *
  • answer section + *
  • authority section + *
  • additional section + *
+ */ +struct dnshdr { + uint16_t id; /**< an identifier used to match up replies */ + uint16_t flags; /**< contains op_code, err_code, etc. */ + uint16_t qdcount; /**< specifies the number of entries in the=20 + question section */ + uint16_t ancount; /**< specifies the number of entries in the=20 + answer section */ + uint16_t nscount; /**< specifies the number of entries in the + authority section */ + uint16_t arcount; /**< specifies the number of entries in the=20 + additional section */ +}; + + +/***************************** PROTOTYPES ********************************/ + +static void +dns_send_query(int fd, int8_t * domain_name, uint8_t ip_version); + +static void +fill_dnshdr(uint8_t * packet, int8_t * domain_name, uint8_t ip_version); + +static uint8_t * +dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name); + +static int8_t +urltohost(char * url, char * host_name); + +static int8_t +hosttodomain(char * host_name, char * domain_name); + +/**************************** LOCAL VARIABLES ****************************/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static int32_t dns_server_ip =3D 0; +static uint8_t dns_server_ipv6[16] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0= , 0, 0, 0, 0}; +static int32_t dns_result_ip =3D 0; +static uint8_t dns_result_ipv6[16] =3D {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0= , 0, 0, 0, 0}; +static int8_t dns_error =3D 0; /**< Stores error code or= 0 */ +static int8_t dns_domain_name[0x100]; /**< Raw domain name */ +static int8_t dns_domain_cname[0x100]; /**< Canonical domain name */ + +/**************************** IMPLEMENTATION *****************************/ + +/** + * DNS: Initialize the environment for DNS client. + * To perfrom DNS-queries use the function dns_get_ip. + * + * @param device_socket a socket number used to send and receive packets + * @param server_ip DNS-server IPv4 address (e.g. 127.0.0.1) + * @return TRUE in case of successful initialization; + * FALSE in case of fault (e.g. can't obtain MAC). + * @see dns_get_ip + */ +int8_t +dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip= _version) +{ + if(ip_version =3D=3D 6) + memcpy(dns_server_ipv6, _dns_server_ipv6, 16); + else + dns_server_ip =3D _dns_server_ip; + return 0; +} + +/** + * DNS: For given URL retrieves IPv4/IPv6 from DNS-server. + *

+ * URL can be given in one of the following form:

    + *
  • scheme with full path with (without) user and password + *
    (e.g. "http://user:pass@www.host.org/url-path"); + *
  • host name with url-path + *
    (e.g. "www.host.org/url-path"); + *
  • nothing but host name + *
    (e.g. "www.host.org"); + *
+ * + * @param fd socket descriptor + * @param url the URL to be resolved + * @param domain_ip In case of SUCCESS stores extracted IP. + * In case of FAULT stores zeros (0.0.0.0). + * @return TRUE - IP successfuly retrieved; + * FALSE - error condition occurs. + */ +int8_t +dns_get_ip(int fd, char* url, uint8_t * domain_ip, uint8_t ip_version) +{ + /* this counter is used so that we abort after 30 DNS request */ + int32_t i; + /* this buffer stores host name retrieved from url */ + static int8_t host_name[0x100]; + + (* domain_ip) =3D 0; + + // Retrieve host name from URL + if (!urltohost(url, (char *) host_name)) { + printf("\nERROR:\t\t\tBad URL!\n"); + return 0; + } + + // Reformat host name into a series of labels + if (!hosttodomain((char *) host_name, (char *) dns_domain_name)) { + printf("\nERROR:\t\t\tBad host name!\n"); + return 0; + } + + // Check if DNS server is presented and accessible + if (dns_server_ip =3D=3D 0) { + printf("\nERROR:\t\t\tCan't resolve domain name " + "(DNS server is not presented)!\n"); + return 0; + } + + // Use DNS-server to obtain IP + if (ip_version =3D=3D 6) + memset(dns_result_ipv6, 0, 16); + else + dns_result_ip =3D 0; + dns_error =3D 0; + strcpy((char *) dns_domain_cname, ""); + + for(i =3D 0; i < 30; ++i) { + // Use canonical name in case we obtained it + if (strlen((char *) dns_domain_cname)) + dns_send_query(fd, dns_domain_cname, ip_version); + else + dns_send_query(fd, dns_domain_name, ip_version); + + // setting up a timer with a timeout of one seconds + set_timer(TICKS_SEC); + do { + receive_ether(fd); + if (dns_error) + return 0; // FALSE - error + if ((dns_result_ip !=3D 0) && (ip_version =3D=3D 4)) { + memcpy(domain_ip, &dns_result_ip, 4); + return 1; // TRUE - success (domain IP retrieved) + } + else if ((dns_result_ipv6[0] !=3D 0) && (ip_version =3D=3D 6)) { + memcpy(domain_ip, dns_result_ipv6, 16); + return 1; // TRUE - success (domain IP retrieved) + } + } while (get_timer() > 0); + } + + printf("\nGiving up after %d DNS requests\n", i); + return 0; // FALSE - domain name wasn't retrieved +} + +/** + * DNS: Handles DNS-messages according to Receive-handle diagram. + * Sets dns_result_ip for given dns_domain_name (see dns_get_ip) + * or signals error condition occurs during DNS-resolving process + * by setting dns_error flag. + * + * @param packet DNS-packet to be handled + * @param packetsize length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see dns_get_ip + * @see receive_ether + * @see dnshdr + */ +int32_t +handle_dns(uint8_t * packet, int32_t packetsize) +{ + struct dnshdr * dnsh =3D (struct dnshdr *) packet; + uint8_t * resp_section =3D packet + sizeof(struct dnshdr); + /* This string stores domain name from DNS-packets */ + static int8_t handle_domain_name[0x100];=20 + int i; + + // verify ID - is it response for our query? + if (dnsh -> id !=3D htons(0x1234)) + return 0; + + // Is it DNS response? + if ((dnsh -> flags & htons(DNS_FLAG_MSGTYPE)) !=3D htons(DNS_FLAG_SRESPON= SE)) + return 0; + + // Is error condition occurs? (check error field in incoming packet) + if ((dnsh -> flags & htons(DNS_FLAG_RCODE)) !=3D DNS_RCODE_NERROR) { + dns_error =3D 1; + return 0; + } + + /* Pass all (qdcount) records in question section */ + + for (i =3D 0; i < htons(dnsh -> qdcount); i++) { + // pass QNAME + resp_section =3D dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_sect= ion, + handle_domain_name); + if (resp_section =3D=3D NULL) { + return -1; // incorrect domain name (bad packet) + } + // pass QTYPE & QCLASS + resp_section +=3D 4; + } + + /* Handle all (ancount) records in answer section */ + + for (i =3D 0; i < htons(dnsh -> ancount); i++) { + // retrieve domain name from the packet + resp_section =3D dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_sect= ion, + handle_domain_name); + + if (resp_section =3D=3D NULL) { + return -1; // incorrect domain name (bad packet) + } + + // Check the class of the query (should be IN for Internet) + if (* (uint16_t *) (resp_section + 2) =3D=3D htons(DNS_QCLASS_IN)) { + // check if retrieved name fit raw or canonical domain name + if (!strcmp((char *) handle_domain_name, (char *) dns_domain_name) || + !strcmp((char *) handle_domain_name, (char *) dns_domain_cname)) { + switch (htons(* (uint16_t *) resp_section)) { + + case DNS_QTYPE_A : + // rdata contains IP + dns_result_ip =3D htonl(* (uint32_t *) (resp_section + 10)); + return 0; // IP successfully obtained + + case DNS_QTYPE_CNAME : + // rdata contains canonical name, store it for further requests + if (dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section + 10, + dns_domain_cname) =3D=3D NULL) { + // incorrect domain name (bad packet) + return -1; + } + break; + case DNS_QTYPE_AAAA : + memcpy(dns_result_ipv6, (resp_section + 10), 16); + return 0; // IP successfully obtained + } + } + // continue with next record in answer section + resp_section +=3D htons(* (uint16_t *) (resp_section + 8)) + 10; + } + } + return 0; // Packet successfully handled but IP wasn't obtained +} + +/** + * DNS: Sends a standard DNS-query (read request package) to a DNS-server. + * DNS-server respones with host IP or signals some error condition. + * Responses from the server are handled by handle_dns function. + * + * @param fd socket descriptor + * @param domain_name the domain name given as series of labels preceded + * with length(label) and terminated with 0 =20 + *
(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0") + * @see handle_dns + */ +static void +dns_send_query(int fd, int8_t * domain_name, uint8_t ip_version) +{ + int qry_len =3D strlen((char *) domain_name) + 5; + int iphdr_len =3D (ip_version =3D=3D 4) ? sizeof(struct iphdr) : sizeof(s= truct ip6hdr); + ip6_addr_t server_ipv6; + + uint32_t packetsize =3D iphdr_len + + sizeof(struct udphdr) + sizeof(struct dnshdr) + + qry_len; + + memset(ether_packet, 0, packetsize); + fill_dnshdr(ðer_packet[ + iphdr_len + sizeof(struct udphdr)], + domain_name, + ip_version); + fill_udphdr(ðer_packet[iphdr_len], + sizeof(struct dnshdr) + + sizeof(struct udphdr) + qry_len, + UDPPORT_DNSC, UDPPORT_DNSS); + if (ip_version =3D=3D 4) { + fill_iphdr(ether_packet, + sizeof(struct dnshdr) + sizeof(struct udphdr) + + iphdr_len + qry_len, + IPTYPE_UDP, 0, dns_server_ip); + } else { + memcpy(server_ipv6.addr, dns_server_ipv6, 16); + fill_ip6hdr(ether_packet, + sizeof(struct dnshdr) + sizeof(struct udphdr) + qry_len, + IPTYPE_UDP, get_ipv6_address(), + &server_ipv6); + } + + send_ip(fd, ether_packet, packetsize); +} + +/** + * DNS: Creates standard DNS-query package. Places DNS-header + * and question section in a packet and fills it with + * corresponding information. + *

+ * Use this function with similar functions for other network layers + * (fill_udphdr, fill_iphdr, fill_ethhdr). + * + * @param packet Points to the place where ARP-header must be placed. + * @param domain_name the domain name given as series of labels preceded + * with length(label) and terminated with 0 =20 + *
(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0") + * @see fill_udphdr + * @see fill_iphdr + * @see fill_ethhdr + */ +static void +fill_dnshdr(uint8_t * packet, int8_t * domain_name, uint8_t ip_version) +{ + struct dnshdr * dnsh =3D (struct dnshdr *) packet; + uint8_t * qry_section =3D packet + sizeof(struct dnshdr); + + dnsh -> id =3D htons(0x1234); + dnsh -> flags =3D htons(DNS_FLAG_SQUERY) | htons(DNS_FLAG_RD); + dnsh -> qdcount =3D htons(1); + + strcpy((char *) qry_section, (char *) domain_name); + qry_section +=3D strlen((char *) domain_name) + 1; + + // fill QTYPE (ask for IP) + if (ip_version =3D=3D 4) + * (uint16_t *) qry_section =3D htons(DNS_QTYPE_A); + else + * (uint16_t *) qry_section =3D htons(DNS_QTYPE_AAAA); + qry_section +=3D 2; + // fill QCLASS (IN is a standard class for Internet) + * (uint16_t *) qry_section =3D htons(DNS_QCLASS_IN); +} + +/** + * DNS: Extracts domain name from the question or answer section of + * the DNS-message. This function is need to support message =20 + * compression requirement (see RFC 1035, paragraph 4.1.4). + * + * @param dnsh Points at the DNS-header. + * @param head Points at the beginning of the domain_name + * which has to be extracted. + * @param domain_name In case of SUCCESS this string stores extracted nam= e. + * In case of FAULT this string is empty. + * @return NULL in case of FAULT (domain name > 255 octets);=20 + * otherwise pointer to the data following the name. + * @see dnshdr + */ +static uint8_t * +dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name) +{ + int8_t * tail =3D domain_name; + int8_t * ptr =3D head; + int8_t * next_section =3D NULL; + + while (1) { + if ((ptr[0] & 0xC0) =3D=3D 0xC0) { + // message compressed (reference is used) + next_section =3D ptr + 2; + ptr =3D (int8_t *) dnsh + (htons(* (uint16_t *) ptr) & 0x3FFF); + continue; + } + if (ptr[0] =3D=3D 0) { + // message termination + tail[0] =3D 0; + ptr +=3D 1; + break; + } + // maximum length for domain name is 255 octets w/o termination sym + if (tail - domain_name + ptr[0] + 1 > 255) { + strcpy((char *) domain_name, ""); + return NULL; + } + memcpy(tail, ptr, ptr[0] + 1); + tail +=3D ptr[0] + 1; + ptr +=3D ptr[0] + 1; + } + + if (next_section =3D=3D NULL) + next_section =3D ptr; + + return (uint8_t *) next_section; +} + +/** + * DNS: Parses URL and returns host name. + * Input string can be given as:

    + *
  • scheme with full path with (without) user and password + *
    (e.g. "http://user:pass@www.host.org/url-path"); + *
  • host name with url-path + *
    (e.g. "www.host.org/url-path"); + *
  • nothing but host name + *
    (e.g. "www.host.org"); + *
+ * + * @param url string that stores incoming URL + * @param host_name In case of SUCCESS this string stores the host name, + * In case of FAULT this string is empty. + * @return TRUE - host name retrieved, + * FALSE - host name > 255 octets or empty. + */ +static int8_t +urltohost(char * url, char * host_name) +{ + uint16_t length1; + uint16_t length2; + + strcpy(host_name, ""); + + if (strstr(url, "://") !=3D NULL) + url =3D strstr(url, "//") + 2; // URL + + if (strstr(url, "@") !=3D NULL) // truncate user & password + url =3D strstr(url, "@") + 1; + + if (strstr(url, "/") !=3D NULL) // truncate url path + length1 =3D strstr(url, "/") - url; + else + length1 =3D strlen(url); + + if (strstr(url, ":") !=3D NULL) // truncate port path + length2 =3D strstr(url, ":") - url; + else + length2 =3D strlen(url); + + if(length1 > length2) + length1 =3D length2; + + if (length1 =3D=3D 0) + return 0; // string is empty + if(length1 >=3D 256) + return 0; // host name is too big + + strncpy(host_name, url, length1); + host_name[length1] =3D 0; + + return 1; // Host name is retrieved +} + +/** + * DNS: Transforms host name string into a series of labels + * each of them preceded with length(label). 0 is a terminator. + * "www.domain.dom" -> "\3,w,w,w,\6,d,o,m,a,i,n,\3,c,o,m,\0" + *

+ * This format is used in DNS-messages. + * + * @param host_name incoming string with the host name + * @param domain_name resulting string with series of labels + * or empty string in case of FAULT + * @return TRUE - host name transformed, + * FALSE - host name > 255 octets or label > 63 octets. + */ +static int8_t +hosttodomain(char * host_name, char * domain_name) +{ + char * domain_iter =3D domain_name; + char * host_iter =3D host_name; + + strcpy(domain_name, ""); + + if(strlen(host_name) > 255) + return 0; // invalid host name (refer to RFC 1035) + + for(; 1; ++host_iter) { + if(*host_iter !=3D '.' && *host_iter !=3D 0) + continue; + *domain_iter =3D host_iter - host_name; + if (*domain_iter > 63) { + strcpy(domain_name, ""); + return 0; // invalid host name (refer to RFC 1035) + } + ++domain_iter; + strncpy(domain_iter, host_name, host_iter - host_name); + domain_iter +=3D (host_iter - host_name); + if(*host_iter =3D=3D 0) { + *domain_iter =3D 0; + break; + } + host_name =3D host_iter + 1; + } + return 1; // ok +} diff --git a/pc-bios/s390-ccw/libnet/dns.h b/pc-bios/s390-ccw/libnet/dns.h new file mode 100644 index 0000000..b8756af --- /dev/null +++ b/pc-bios/s390-ccw/libnet/dns.h @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#ifndef _DNS_H_ +#define _DNS_H_ + +#include + +/* Initialize the environment for DNS client. */ +extern int8_t dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[1= 6], uint8_t ip_version); + +/* For given URL retrieves IPv4 from DNS-server. */ +extern int8_t dns_get_ip(int fd, char * url, uint8_t * domain_ip, uint8_t = ip_version); + +/* Handles DNS-packets, which are detected by receive_ether. */ +extern int32_t handle_dns(uint8_t * packet, int32_t packetsize); + +#endif diff --git a/pc-bios/s390-ccw/libnet/ethernet.c b/pc-bios/s390-ccw/libnet/e= thernet.c new file mode 100644 index 0000000..1e03a0b --- /dev/null +++ b/pc-bios/s390-ccw/libnet/ethernet.c @@ -0,0 +1,189 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +/******************************* ALGORITHMS ******************************/ + +/** \file netbase.c

+ * *********************** Receive-handle diagram *************************
+ *
+ * Note: Every layer calls out required upper layer
+ *
+ * lower
+ *  | MAC/LLC     Receive packet (receive_ether)
+ *  |                           |
+ *  | NETWORK       +-----------+---------+
+ *  |               |                     |
+ *  |           IPv4 (handle_ipv4)    IPv6 (handle_ipv4)
+ *  |           ARP  (handle_arp)     ICMP & NDP
+ *  |           ICMP                      |
+ *  |                 |                   |
+ *  |                 +---------+---------+
+ *  |                           |
+ *  | TRANSPORT       +---------+---------+
+ *  |                 |                   |
+ *  |              TCP (handle_tcp)    UDP (handle_udp)
+ *  |                                     |
+ *  | APPLICATION        +----------------+-----------+
+ *  V                    |                            |
+ * upper               DNS (handle_dns)      BootP / DHCP (handle_bootp_cl=
ient)
+ *
+ * ************************************************************************
+ * 
*/ + + +/************************ DEFINITIONS & DECLARATIONS *********************/ + +#include +#include +#include +#include +#include + + +/****************************** LOCAL VARIABLES **************************/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static uint8_t own_mac[6] =3D {0, 0, 0, 0, 0, 0}; +static uint8_t multicast_mac[] =3D {0x01, 0x00, 0x5E}; +static const uint8_t broadcast_mac[] =3D {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x= FF}; + +/****************************** IMPLEMENTATION ***************************/ + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @param own_mac own hardware-address (MAC) + */ +void set_mac_address(const uint8_t * _own_mac) +{ + if (_own_mac) + memcpy(own_mac, _own_mac, 6); + else + memset(own_mac, 0, 6); +} + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @return own hardware-address (MAC) + */ +const uint8_t *get_mac_address(void) +{ + return own_mac; +} + +/** + * Ethernet: Check if given multicast address is a multicast MAC address + * starting with 0x3333 + * + * @return true or false + */ +static uint8_t is_multicast_mac(uint8_t * mac) +{ + + uint16_t mc =3D 0x3333; + if (memcmp(mac, &mc, 2) =3D=3D 0) + return 1; + + return 0; +} + +/** + * Ethernet: Receives an ethernet-packet and handles it according to + * Receive-handle diagram. + * + * @param fd socket fd + * @return ZERO - packet was handled or no packets received; + * NON ZERO - error condition occurs. + */ +int32_t receive_ether(int fd) +{ + int32_t bytes_received; + struct ethhdr * ethh; + + memset(ether_packet, 0, ETH_MTU_SIZE); + bytes_received =3D recv(fd, ether_packet, ETH_MTU_SIZE, 0); + + if (!bytes_received) // No messages + return 0; + + if (bytes_received < 0) + return -1; /* recv() failed */ + + if ((size_t) bytes_received < sizeof(struct ethhdr)) + return -1; // packet is too small + + ethh =3D (struct ethhdr *) ether_packet; + + if(memcmp(ethh->dest_mac, broadcast_mac, 6) !=3D 0 + && memcmp(ethh->dest_mac, multicast_mac, 3) !=3D 0 + && memcmp(ethh->dest_mac, own_mac, 6 ) !=3D 0 + && !is_multicast_mac(ethh->dest_mac)) + return -1; // packet is too small + + switch (htons(ethh -> type)) { + case ETHERTYPE_IP: + return handle_ipv4(fd, (uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); + + case ETHERTYPE_IPv6: + return handle_ipv6(fd, ether_packet + sizeof(struct ethhdr), + bytes_received - sizeof(struct ethhdr)); + + case ETHERTYPE_ARP: + return handle_arp(fd, (uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); + default: + break; + } + return -1; // unknown protocol +} + +/** + * Ethernet: Sends an ethernet frame via the initialized file descriptor. + * + * @return number of transmitted bytes + */ +int +send_ether(int fd, void* buffer, int len) +{ + return send(fd, buffer, len, 0); +} + +/** + * Ethernet: Creates Ethernet-packet. Places Ethernet-header in a packet a= nd + * fills it with corresponding information. + *

+ * Use this function with similar functions for other network la= yers + * (fill_arphdr, fill_iphdr, fill_udphdr, fill_dnshdr, fill_btph= dr). + * + * @param packet Points to the place where eth-header must be placed. + * @param eth_type Type of the next level protocol (e.g. IP or ARP). + * @param src_mac Sender MAC address + * @param dest_mac Receiver MAC address + * @see ethhdr + * @see fill_arphdr + * @see fill_iphdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac) +{ + struct ethhdr * ethh =3D (struct ethhdr *) packet; + + ethh -> type =3D htons(eth_type); + memcpy(ethh -> src_mac, src_mac, 6); + memcpy(ethh -> dest_mac, dest_mac, 6); +} diff --git a/pc-bios/s390-ccw/libnet/ethernet.h b/pc-bios/s390-ccw/libnet/e= thernet.h new file mode 100644 index 0000000..e541c8f --- /dev/null +++ b/pc-bios/s390-ccw/libnet/ethernet.h @@ -0,0 +1,47 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _ETHERNET_H +#define _ETHERNET_H + +#include + +#define ETH_MTU_SIZE 1518 /**< Maximum Transfer Unit */ +#define ETH_ALEN 6 /**< HW address length */ +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_IPv6 0x86DD +#define ETHERTYPE_ARP 0x0806 + +/** \struct ethhdr + * A header for Ethernet-packets. + */ +struct ethhdr { + uint8_t dest_mac[ETH_ALEN]; /**< Destination HW address */ + uint8_t src_mac[ETH_ALEN]; /**< Source HW address */ + uint16_t type; /**< Next level protocol type */ +}; + +/* Initializes ethernet layer */ +extern void set_mac_address(const uint8_t * own_mac); +extern const uint8_t * get_mac_address(void); + +/* Receives and handles packets, according to Receive-handle diagram */ +extern int32_t receive_ether(int fd); + +/* Sends an ethernet frame. */ +extern int send_ether(int fd, void* buffer, int len); + +/* fills ethernet header */ +extern void fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac); + +#endif diff --git a/pc-bios/s390-ccw/libnet/icmpv6.c b/pc-bios/s390-ccw/libnet/icm= pv6.c new file mode 100644 index 0000000..d44ce84 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/icmpv6.c @@ -0,0 +1,409 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include +#include +#include +#include +#include "ethernet.h" +#include "ipv6.h" +#include "icmpv6.h" +#include "ndp.h" +#include "dhcpv6.h" + +static int ra_received =3D 0; + +/** + * NET: + * @param fd socket fd + */ +void +send_router_solicitation (int fd) +{ + ip6_addr_t dest_addr; + uint8_t *ether_packet; + struct packeth headers; + + ether_packet =3D malloc(ETH_MTU_SIZE); + if (!ether_packet) { + fprintf(stderr, "send_router_solicitation: Out of memory\n"); + return; + } + + headers.ip6h =3D (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr= )); + headers.icmp6h =3D (struct icmp6hdr *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + /* Destination is "All routers multicast address" (link-local) */ + dest_addr.part.prefix =3D 0xff02000000000000ULL; + dest_addr.part.interface_id =3D 2; + + /* Fill IPv6 header */ + fill_ip6hdr (ether_packet + sizeof(struct ethhdr), + ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation), + 0x3a, //ICMPV6 + get_ipv6_address(), &dest_addr); + + /* Fill ICMPv6 message */ + headers.icmp6h->type =3D ICMPV6_ROUTER_SOLICITATION; + headers.icmp6h->code =3D 0; + headers.icmp6h->icmp6body.router_solicit.lladdr.type =3D 1; + headers.icmp6h->icmp6body.router_solicit.lladdr.length =3D 1; + memcpy( &(headers.icmp6h->icmp6body.router_solicit.lladdr.mac), + get_mac_address(), 6); + + send_ip (fd, headers.ip6h, sizeof(struct ip6hdr) + + ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation)); + + free(ether_packet); +} + +/** + * NET: Process prefix option in Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +handle_prefixoption (uint8_t *option) +{ + ip6_addr_t prefix; + struct ip6addr_list_entry *new_address; + struct option_prefix *prefix_option; + struct prefix_info *prfx_info; + + prefix_option =3D (struct option_prefix *) option; + memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH); + + /* Link-local adresses in RAs are nonsense */ + if (ip6_is_linklocal(&prefix)) + return; + + if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime) + return; + + /* Add address created from prefix to IPv6 address list */ + new_address =3D ip6_prefix2addr (prefix); + if (!new_address) + return; + + /* Process only prefixes we don't already have an adress from */ + if (!unknown_prefix (&new_address->addr)) { + return; + } + + /* Fill struct prefix_info from data in RA and store it in new_address */ + prfx_info =3D ip6_create_prefix_info(); + if (!prfx_info) + return; + memcpy (&(new_address->prfx_info), prfx_info, sizeof(struct prefix_info)); + + /* Add prefix received in RA to list of known prefixes */ + ip6addr_add (new_address); +} + +/** + * NET: Process source link layer addresses in Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +handle_source_lladdr ( struct option_ll_address *option, struct router *rt= r) +{ + memcpy (&(rtr->mac), &(option->mac), 6); +} + +/** + * NET: Process ICMPv6 options in Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +process_ra_options (uint8_t *option, int32_t option_length, struct router = *r) +{ + while (option_length > 0) { + switch (*option) { + case ND_OPTION_SOURCE_LL_ADDR: + handle_source_lladdr ((struct option_ll_address *) option, r); + break; + case ND_OPTION_PREFIX_INFO: + handle_prefixoption(option); + break; + default: + break; + } + //option+1 is the length field. length is in units of 8 bytes + option_length =3D option_length - (*(option+1) * 8); + option =3D option + (*(option+1) * 8); + } + + return; +} + +/** + * NET: Process Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +handle_ra (struct icmp6hdr *icmp6h, uint8_t *ip6_packet) +{ + uint8_t *first_option; + int32_t option_length; + struct ip6hdr *ip6h; + struct router_advertisement *ra; + struct router *rtr; + ip6_addr_t *rtr_ip; + uint8_t rtr_mac[] =3D {0, 0, 0, 0, 0, 0}; + + ip6h =3D (struct ip6hdr *) ip6_packet; + ra =3D (struct router_advertisement *) &icmp6h->icmp6body.ra; + rtr_ip =3D (ip6_addr_t *) &ip6h->src; + + rtr =3D find_router (&(ip6h->src)); + if (!rtr) { + rtr =3D router_create (rtr_mac, rtr_ip); + router_add (rtr); + } + + /* store info from router advertisement in router struct */ + rtr->lifetime =3D ra->router_lifetime; + rtr->reachable_time =3D ra->reachable_time; + rtr->retrans_timer =3D ra->retrans_timer; + + /* save flags concerning address (auto-) configuration */ + ip6_state.managed_mode =3D ra->flags.managed; + ip6_state.other_config =3D ra->flags.other; + + /* Process ICMPv6 options in Router Advertisement */ + first_option =3D (uint8_t *) icmp6h + ICMPv6_HEADER_SIZE + 12; + option_length =3D (uint8_t *) icmp6h + ip6h->pl - first_option; + process_ra_options( (uint8_t *) first_option, option_length, rtr); + + ra_received =3D 1; +} + +int is_ra_received(void) +{ + return ra_received; +} + +/** + * NET: + * + * @param fd socket fd + * @param ip6_addr_t *dest_ip6 + */ +void +send_neighbour_solicitation (int fd, ip6_addr_t *dest_ip6) +{ + ip6_addr_t snma; + uint8_t *ether_packet; + struct packeth headers; + + ether_packet =3D malloc(ETH_MTU_SIZE); + if (!ether_packet) { + fprintf(stderr, "send_neighbour_solicitation: Out of memory\n"); + return; + } + + memset(ether_packet, 0, ETH_MTU_SIZE); + headers.ethh =3D (struct ethhdr *) ether_packet; + headers.ip6h =3D (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr= )); + headers.icmp6h =3D (struct icmp6hdr *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + /* Fill IPv6 header */ + snma.part.prefix =3D IPV6_SOLIC_NODE_PREFIX; + snma.part.interface_id =3D IPV6_SOLIC_NODE_IFACE_ID; + snma.addr[13] =3D dest_ip6->addr[13]; + snma.addr[14] =3D dest_ip6->addr[14]; + snma.addr[15] =3D dest_ip6->addr[15]; + fill_ip6hdr((uint8_t *) headers.ip6h, + ICMPv6_HEADER_SIZE + sizeof(struct neighbour_solicitation), + 0x3a, //ICMPv6 + get_ipv6_address(), &snma); + + /* Fill ICMPv6 message */ + headers.icmp6h->type =3D ICMPV6_NEIGHBOUR_SOLICITATION; + headers.icmp6h->code =3D 0; + memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.target), + dest_ip6, IPV6_ADDR_LENGTH ); + headers.icmp6h->icmp6body.nghb_solicit.lladdr.type =3D 1; + headers.icmp6h->icmp6body.nghb_solicit.lladdr.length =3D 1; + memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.lladdr.mac), + get_mac_address(), 6); + + send_ip (fd, ether_packet + sizeof(struct ethhdr), + sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE + + sizeof(struct neighbour_solicitation)); + + free(ether_packet); +} + +/** + * NET: + * + * @param fd socket fd + * @param ip6_packet pointer to an IPv6 packet + * @param icmp6hdr pointer to the icmp6 header in ip6_packet + * @param na_flags Neighbour advertisment flags + */ +static void +send_neighbour_advertisement (int fd, struct neighbor *target) +{ + struct na_flags na_adv_flags; + uint8_t *ether_packet; + struct packeth headers; + + ether_packet =3D malloc(ETH_MTU_SIZE); + if (!ether_packet) { + fprintf(stderr, "send_neighbour_advertisement: Out of memory\n"); + return; + } + + headers.ip6h =3D (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr= )); + headers.icmp6h =3D (struct icmp6hdr *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + /* Fill IPv6 header */ + fill_ip6hdr(ether_packet + sizeof(struct ethhdr), + ICMPv6_HEADER_SIZE + sizeof(struct neighbour_advertisement), + 0x3a, //ICMPv6 + get_ipv6_address(), (ip6_addr_t *) &(target->ip.addr)); + + /* Fill ICMPv6 message */ + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target), + &(target->ip.addr), IPV6_ADDR_LENGTH ); + headers.icmp6h->icmp6body.nghb_adv.lladdr.type =3D 1; + headers.icmp6h->icmp6body.nghb_adv.lladdr.length =3D 1; + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac), + get_mac_address(), 6); + + na_adv_flags.is_router =3D 0; + na_adv_flags.na_is_solicited =3D 1; + na_adv_flags.override =3D 1; + + headers.icmp6h->type =3D ICMPV6_NEIGHBOUR_ADVERTISEMENT; + headers.icmp6h->code =3D 0; + headers.icmp6h->icmp6body.nghb_adv.router =3D na_adv_flags.is_router; + + headers.icmp6h->icmp6body.nghb_adv.solicited =3D na_adv_flags.na_is_solic= ited; + headers.icmp6h->icmp6body.nghb_adv.override =3D na_adv_flags.override; + headers.icmp6h->icmp6body.nghb_adv.lladdr.type =3D 2; + headers.icmp6h->icmp6body.nghb_adv.lladdr.length =3D 1; + + memset( &(headers.icmp6h->icmp6body.nghb_adv.target), 0, + IPV6_ADDR_LENGTH ); + + if( na_adv_flags.na_is_solicited ) { + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target), + get_ipv6_address(), IPV6_ADDR_LENGTH); + } + + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac), + get_mac_address(), 6); + + send_ip (fd, ether_packet + sizeof(struct ethhdr), + sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE + + sizeof(struct neighbour_advertisement)); + + free(ether_packet); +} + +/** + * NET: + * + * @param fd socket fd + * @param ip6_packet pointer to an IPv6 packet + */ +static int8_t +handle_na (int fd, uint8_t *packet) +{ + struct neighbor *n =3D NULL; + struct packeth headers; + ip6_addr_t ip; + + headers.ethh =3D (struct ethhdr *) packet; + headers.ip6h =3D (struct ip6hdr *) (packet + sizeof(struct ethhdr)); + headers.icmp6h =3D (struct icmp6hdr *) (packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + memcpy(&(ip.addr), &(headers.ip6h->src), IPV6_ADDR_LENGTH); + + n =3D find_neighbor (&ip); + + if (!n) { + n=3D (struct neighbor *) + neighbor_create( packet, &headers ); + if (!n) + return 0; + if (!neighbor_add(n)) + return 0; + } else { + memcpy (&(n->mac), &(headers.ethh->src_mac[0]), 6); + n->status =3D NB_REACHABLE; + if (n->eth_len > 0) { + struct ethhdr * ethh =3D (struct ethhdr *) &(n->eth_frame); + memcpy(ethh->dest_mac, &(n->mac), 6); + send_ether (fd, &(n->eth_frame), n->eth_len + sizeof(struct ethhdr)); + n->eth_len =3D 0; + } + } + + return 1; +} + +/** + * NET: Handles ICMPv6 messages + * + * @param fd socket fd + * @param ip6_packet pointer to an IPv6 packet + * @param packetsize size of ipv6_packet + */ +int8_t +handle_icmpv6 (int fd, struct ethhdr *etherhdr, + uint8_t *ip6_packet) +{ + + struct icmp6hdr *received_icmp6 =3D NULL; + struct ip6hdr *received_ip6 =3D NULL; + struct neighbor target; + + received_ip6 =3D (struct ip6hdr *) ip6_packet; + received_icmp6 =3D (struct icmp6hdr *) (ip6_packet + + sizeof(struct ip6hdr)); + memcpy( &(target.ip.addr), &(received_ip6->src), + IPV6_ADDR_LENGTH ); + memcpy( &(target.mac), etherhdr->src_mac, 6); + + /* process ICMPv6 types */ + switch(received_icmp6->type) { + case ICMPV6_NEIGHBOUR_SOLICITATION: + send_neighbour_advertisement(fd, &target); + break; + case ICMPV6_NEIGHBOUR_ADVERTISEMENT: + handle_na(fd, (uint8_t *) ip6_packet - sizeof(struct ethhdr)); + break; + case ICMPV6_ROUTER_ADVERTISEMENT: + handle_ra(received_icmp6, (uint8_t *) received_ip6); + break; + default: + return -1; + } + + return 1; +} diff --git a/pc-bios/s390-ccw/libnet/icmpv6.h b/pc-bios/s390-ccw/libnet/icm= pv6.h new file mode 100644 index 0000000..41b0c70 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/icmpv6.h @@ -0,0 +1,135 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _ICMPV6_H_ +#define _ICMPV6_H_ + +#include +#include "ethernet.h" +#include "ipv6.h" + +#define __ICMPV6_DEBUG__ + +#ifdef __ICMPV6_DEBUG__ +#define ICMPV6_DEBUG_PRINT(format, ...) printf(format, ## __VA_ARGS__) +#else +#define ICMPV6_DEBUG_PRINT(format, ...) +#endif + +#define ICMPv6_HEADER_SIZE 4 /* Size of common fields */ +#define IPTYPE_ICMPV6 0x3a + +/* Error message types */ +#define ICMPV6_DEST_UNREACHABLE 1 /* Destination unreachable */ +#define ICMPV6_PACKET_TOO_BIG 2 /* Packet too big */ +#define ICMPV6_TIME_EXCEEDED 3 /* Time exceeded */ +#define ICMPV6_PARAM_PROBLEM 4 /* Parameter problem */ + +/* Informational message types */ +#define ICMPV6_ECHO_REQUEST 128 /* Echo request */ +#define ICMPV6_ECHO_REPLY 129 /* Echo reply */ +#define ICMPV6_MCAST_LISTENER_QUERY 130 /* Multicast listener query */ +#define ICMPV6_MCAST_LISTENER_REPORT 131 /* Multicast listener report */ +#define ICMPv6 MCAST_LISTENER_DONE 132 /* Multicast listener done */ +#define ICMPV6_ROUTER_SOLICITATION 133 /* Router solicitation */ +#define ICMPV6_ROUTER_ADVERTISEMENT 134 /* Router advertisement */ +#define ICMPV6_NEIGHBOUR_SOLICITATION 135 /* Neighbor solicitation */ +#define ICMPV6_NEIGHBOUR_ADVERTISEMENT 136 /* Neighbor advertisement */ +#define ICMPV6_REDIRECT_MSG 137 /* Redirect message */ + +/******** Functions *******************/ +int8_t handle_icmpv6 (int fd, struct ethhdr *etherhdr, uint8_t *ip6_packe= t); +void send_neighbour_solicitation(int fd, ip6_addr_t *target_ip6); +void send_router_solicitation(int fd); +int is_ra_received(void); + +/* Prefix information */ +struct option_prefix { + uint8_t type; + uint8_t length; + uint8_t prefix_length; + uint8_t onlink:1, + autom:1, + not_router:1, + not_site_prefix:1, + reserved:4; + uint32_t valid_lifetime; + uint32_t preferred_lifetime; + uint32_t reserved2; + ip6_addr_t prefix; +} __attribute((packed)); + +/* Neighbour advertisement/solicitation flags */ +struct na_flags { + uint8_t is_router:1, /* sender (we) is a router */ + na_is_solicited:1, /* this NA was solicited (asked for) */ + override:1, /* receiver shall override its cache entries */ + unused:5; +}__attribute((packed)); + +/* Source/Target Link-layer address */ +struct option_ll_address{ + uint8_t type; + uint8_t length; + uint8_t mac[ETH_ALEN]; +} __attribute((packed)); + +struct neighbour_solicitation { + uint32_t router:1, + solicited:1, + override:1, + reserved:29; + ip6_addr_t target; + struct option_ll_address lladdr; +} __attribute((packed)); + +struct neighbour_advertisement { + uint32_t router:1, + solicited:1, + override:1, + reserved:29; + ip6_addr_t target; + struct option_ll_address lladdr; +} __attribute((packed)); + +struct router_solicitation { + uint32_t reserved; + struct option_ll_address lladdr; +} __attribute((packed)); + +struct router_advertisement { + uint8_t curr_hop_limit; + struct raflags { + uint8_t managed:1, + other:1, + reserved:6; + } flags; + uint16_t router_lifetime; + uint32_t reachable_time; + uint32_t retrans_timer; + struct option_prefix prefix; + struct option_ll_address ll_addr; +} __attribute((packed)); + +struct icmp6hdr { + uint8_t type; + uint8_t code; + uint16_t checksum; + union { + struct neighbour_solicitation nghb_solicit; + struct neighbour_advertisement nghb_adv; + struct router_solicitation router_solicit; + struct router_advertisement ra; + } icmp6body; +} __attribute((packed)); + +#endif diff --git a/pc-bios/s390-ccw/libnet/ipv4.c b/pc-bios/s390-ccw/libnet/ipv4.c new file mode 100644 index 0000000..3a1a789 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/ipv4.c @@ -0,0 +1,898 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +/********************** DEFINITIONS & DECLARATIONS ***********************/ + +#include +#include +#include +#include +#include +#include +#include + +/* ARP Message types */ +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +/* ARP talbe size (+1) */ +#define ARP_ENTRIES 10 + +/* ICMP Message types */ +#define ICMP_ECHO_REPLY 0 +#define ICMP_DST_UNREACHABLE 3 +#define ICMP_SRC_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO_REQUEST 8 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETER_PROBLEM 12 +#define ICMP_TIMESTAMP_REQUEST 13 +#define ICMP_TIMESTAMP_REPLY 14 +#define ICMP_INFORMATION_REQUEST 15 +#define ICMP_INFORMATION_REPLY 16 + +/** \struct arp_entry + * A entry that describes a mapping between IPv4- and MAC-address. + */ +typedef struct arp_entry arp_entry_t; +struct arp_entry { + uint32_t ipv4_addr; + uint8_t mac_addr[6]; + uint8_t eth_frame[ETH_MTU_SIZE]; + int eth_len; + int pkt_pending; +}; + +/** \struct icmphdr + * ICMP packet + */ +struct icmphdr { + unsigned char type; + unsigned char code; + unsigned short int checksum; + union { + /* for type 3 "Destination Unreachable" */ + unsigned int unused; + /* for type 0 and 8 */ + struct echo { + unsigned short int id; + unsigned short int seq; + } echo; + } options; + union { + /* payload for destination unreachable */ + struct dun { + unsigned char iphdr[20]; + unsigned char data[64]; + } dun; + /* payload for echo or echo reply */ + /* maximum size supported is 84 */ + unsigned char data[84]; + } payload; +}; + +/****************************** PROTOTYPES *******************************/ + +static unsigned short checksum(unsigned short *packet, int words); + +static void arp_send_request(int fd, uint32_t dest_ip); + +static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac); + +static void fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip); + +static arp_entry_t *lookup_mac_addr(uint32_t ipv4_addr); + +static void fill_udp_checksum(struct iphdr *ipv4_hdr); + +static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, + int32_t packetsize); + +/****************************** LOCAL VARIABLES **************************/ + +/* Routing parameters */ +static uint32_t own_ip =3D 0; +static uint32_t multicast_ip =3D 0; +static uint32_t router_ip =3D 0; +static uint32_t subnet_mask =3D 0; + +/* helper variables */ +static uint32_t ping_dst_ip; +static const uint8_t null_mac_addr[] =3D {0x00, 0x00, 0x00, 0x00, 0x00, 0x= 00}; +static const uint8_t broadcast_mac[] =3D {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x= FF}; +static uint8_t multicast_mac[] =3D {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x= FF}; + +/* There are only (ARP_ENTRIES-1) effective entries because + * the entry that is pointed by arp_producer is never used. + */ +static unsigned int arp_consumer =3D 0; +static unsigned int arp_producer =3D 0; +static arp_entry_t arp_table[ARP_ENTRIES]; + +static uint8_t pending_pkt_frame[ETH_MTU_SIZE]; +static int pending_pkt_len; + +/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ +int (*send_ip) (int fd, void *, int); + +/***************************** IMPLEMENTATION ****************************/ + +/** + * IPv4: Initialize the environment for the IPv4 layer. + */ +static void ipv4_init(void) +{ + int i; + + ping_dst_ip =3D 0; + + // clear ARP table + arp_consumer =3D 0; + arp_producer =3D 0; + for(i=3D0; i 0xEFFFFFFF)) { + multicast_ip =3D 0; + memset(multicast_mac, 0xFF, 6); + return; + } + + multicast_ip =3D _multicast_ip; + multicast_mac[0] =3D 0x01; + multicast_mac[1] =3D 0x00; + multicast_mac[2] =3D 0x5E; + multicast_mac[3] =3D (uint8_t) 0x7F & (multicast_ip >> 16); + multicast_mac[4] =3D (uint8_t) 0xFF & (multicast_ip >> 8); + multicast_mac[5] =3D (uint8_t) 0xFF & (multicast_ip >> 0); +} + +/** + * IPv4: Get the IPv4 multicast address. + * + * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not= set) + */ +uint32_t get_ipv4_multicast(void) +{ + return multicast_ip; +} + +/** + * IPv4: Set the routers IPv4 address. + * + * @param _router_ip router IPv4 address + */ +void set_ipv4_router(uint32_t _router_ip) +{ + router_ip =3D _router_ip; + ipv4_init(); +} + +/** + * IPv4: Get the routers IPv4 address. + * + * @return router IPv4 address + */ +uint32_t get_ipv4_router(void) +{ + return router_ip; +} + +/** + * IPv4: Set the subnet mask. + * + * @param _subnet_mask netmask of the own IPv4 address + */ +void set_ipv4_netmask(uint32_t _subnet_mask) +{ + subnet_mask =3D _subnet_mask; + ipv4_init(); +} + +/** + * IPv4: Get the subnet mask. + * + * @return netmask of the own IPv4 address + */ +uint32_t get_ipv4_netmask(void) +{ + return subnet_mask; +} + +/** + * IPv4: Get the default subnet mask according to the IP class + * + * @param ip_addr IPv4 address + * @return default netmask according to the IP class + */ +uint32_t get_default_ipv4_netmask(char *ip_addr) +{ + unsigned char top; + + top =3D ip_addr[0]; + if (top > 0 && top < 128) + return 0xFF000000; /* Class A: 255.0.0.0 */ + else if (top >=3D 128 && top < 192) + return 0xFFFF0000; /* Class B: 255.255.0.0 */ + else if (top >=3D 192 && top < 224) + return 0xFFFFFF00; /* Class C: 255.255.255.0 */ + else + return 0; +} + +/** + * IPv4: Creates IP-packet. Places IP-header in a packet and fills it + * with corresponding information. + *

+ * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where IP-header must be placed. + * @param packetsize Size of the packet in bytes incl. this hdr and data. + * @param ip_proto Type of the next level protocol (e.g. UDP). + * @param ip_src Sender IP address + * @param ip_dst Receiver IP address + * @see iphdr + * @see fill_ethhdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void fill_iphdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) +{ + struct iphdr * iph =3D (struct iphdr *) packet; + + iph -> ip_hlv =3D 0x45; + iph -> ip_tos =3D 0x10; + iph -> ip_len =3D htons(packetsize); + iph -> ip_id =3D htons(0); + iph -> ip_off =3D 0; + iph -> ip_ttl =3D 0xFF; + iph -> ip_p =3D ip_proto; + iph -> ip_src =3D htonl(ip_src); + iph -> ip_dst =3D htonl(ip_dst); + iph -> ip_sum =3D 0; +} + +/** + * IPv4: Handles IPv4-packets according to Receive-handle diagram. + * + * @param fd socket fd + * @param ip_packet IP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see iphdr + */ +int8_t handle_ipv4(int fd, uint8_t * ip_packet, uint32_t packetsize) +{ + struct iphdr * iph; + int32_t old_sum; + static uint8_t ip_heap[65536 + ETH_MTU_SIZE]; + + if (packetsize < sizeof(struct iphdr)) + return -1; // packet is too small + + iph =3D (struct iphdr * ) ip_packet; + + /* Drop it if destination IPv4 address is no IPv4 Broadcast, no + * registered IPv4 Multicast and not our Unicast address + */ + if((multicast_ip =3D=3D 0 && iph->ip_dst >=3D 0xE0000000 && iph->ip_dst <= =3D 0xEFFFFFFF) + || (multicast_ip !=3D iph->ip_dst && iph->ip_dst !=3D 0xFFFFFFFF && + own_ip !=3D 0 && iph->ip_dst !=3D own_ip)) { + return -1; + } + + old_sum =3D iph -> ip_sum; + iph -> ip_sum =3D 0; + if (old_sum !=3D checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1)) + return -1; // Wrong IP checksum + + // is it the first fragment in a packet? + if (((iph -> ip_off) & 0x1FFF) =3D=3D 0) { + // is it part of more fragments? + if (((iph -> ip_off) & 0x2000) =3D=3D 0x2000) { + memcpy(ip_heap, ip_packet, iph->ip_len); + return 0; + } + } + // it's not the first fragment + else { + // get the first fragment + struct iphdr * iph_first =3D (struct iphdr * ) ip_heap; + + // is this fragment not part of the first one, then exit + if ((iph_first->ip_id !=3D iph->ip_id ) || + (iph_first->ip_p !=3D iph->ip_p ) || + (iph_first->ip_src !=3D iph->ip_src) || + (iph_first->ip_dst !=3D iph->ip_dst)) { + return 0; + } + + // this fragment is part of the first one! + memcpy(ip_heap + sizeof(struct iphdr) + + ((iph -> ip_off) & 0x1FFF) * 8, + ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + + // is it part of more fragments? Then return. + if (((iph -> ip_off) & 0x2000) =3D=3D 0x2000) { + return 0; + } + + // packet is completly reassambled now! + + // recalculate ip_len and set iph and ip_packet to the + iph_first->ip_len =3D iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8; + + // set iph and ip_packet to the resulting packet. + ip_packet =3D ip_heap; + iph =3D (struct iphdr * ) ip_packet; + } + + switch (iph -> ip_p) { + case IPTYPE_ICMP: + return handle_icmp(fd, iph, ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + case IPTYPE_UDP: + return handle_udp(fd, ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + case IPTYPE_TCP: + return handle_tcp(ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + default: + break; + } + return -1; // Unknown protocol +} + +/** + * IPv4: Send IPv4-packets. + * + * Before the packet is sent there are some patcches performed: + * - IPv4 source address is replaced by our unicast IPV4 address + * if it is set to 0 or 1 + * - IPv4 destination address is replaced by our multicast IPV4 addr= ess + * if it is set to 1 + * - IPv4 checksum is calculaded. + * - If payload type is UDP, then the UDP checksum is calculated als= o. + * + * We send an ARP request first, if this is the first packet sent to + * the declared IPv4 destination address. In this case we store the + * the packet and send it later if we receive the ARP response. + * If the MAC address is known already, then we send the packet imme= diately. + * If there is already an ARP request pending, then we drop this pac= ket + * and send again an ARP request. + * + * @param fd socket fd + * @param ip_packet IP-packet to be handled + * @param packetsize Length of the packet + * @return -2 - packet dropped (MAC address not resolved - ARP = request pending) + * -1 - packet dropped (bad format) + * 0 - packet stored (ARP request sent - packet will = be sent if + * ARP response is received) + * >0 - packet send (number of transmitted bytes is = returned) + * + * @see receive_ether + * @see iphdr + */ +int send_ipv4(int fd, void* buffer, int len) +{ + arp_entry_t *arp_entry =3D 0; + struct iphdr *ip; + const uint8_t *mac_addr =3D 0; + uint32_t ip_dst =3D 0; + + if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE) + return -1; + + ip =3D (struct iphdr *) buffer; + + /* Replace source IPv4 address with our own unicast IPv4 address + * if it's 0 (=3D own unicast source address not specified). + */ + if(ip->ip_src =3D=3D 0) { + ip->ip_src =3D htonl( own_ip ); + } + /* Replace source IPv4 address with our unicast IPv4 address and + * replace destination IPv4 address with our multicast IPv4 address + * if source address is set to 1. + */ + else if(ip->ip_src =3D=3D 1) { + ip->ip_src =3D htonl( own_ip ); + ip->ip_dst =3D htonl( multicast_ip ); + } + + // Calculate the IPv4 checksum + ip->ip_sum =3D 0; + ip->ip_sum =3D checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1); + + // if payload type is UDP, then we need to calculate the + // UDP checksum that depends on the IP header + if(ip->ip_p =3D=3D IPTYPE_UDP) { + fill_udp_checksum(ip); + } + + ip_dst =3D ip->ip_dst; + // Check if the MAC address is already cached + if(~ip->ip_dst =3D=3D 0 + || ( ((~subnet_mask) & ip->ip_dst) =3D=3D ~subnet_mask && + ( subnet_mask & ip->ip_dst) =3D=3D (subnet_mask & own_ip))) { + arp_entry =3D &arp_table[arp_producer]; + mac_addr =3D broadcast_mac; + } + else if(ip->ip_dst =3D=3D multicast_ip) { + arp_entry =3D &arp_table[arp_producer]; + mac_addr =3D multicast_mac; + } + else { + // Check if IP address is in the same subnet as we are + if((subnet_mask & own_ip) =3D=3D (subnet_mask & ip->ip_dst)) + arp_entry =3D lookup_mac_addr(ip->ip_dst); + // if not then we need to know the router's IP address + else { + ip_dst =3D router_ip; + arp_entry =3D lookup_mac_addr(router_ip); + } + if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) !=3D 0) + mac_addr =3D arp_entry->mac_addr; + } + + // If we could not resolv the MAC address by our own... + if(!mac_addr) { + // send the ARP request + arp_send_request(fd, ip_dst); + + // drop the current packet if there is already a ARP request pending + if(arp_entry) + return -2; + + // take the next entry in the ARP table to prepare a the new ARP entry. + arp_entry =3D &arp_table[arp_producer]; + arp_producer =3D (arp_producer+1)%ARP_ENTRIES; + + // if ARP table is full then we must drop the oldes entry. + if(arp_consumer =3D=3D arp_producer) + arp_consumer =3D (arp_consumer+1)%ARP_ENTRIES; + + // store the packet to be send if the ARP reply is received + arp_entry->pkt_pending =3D 1; + arp_entry->ipv4_addr =3D ip_dst; + memset(arp_entry->mac_addr, 0, 6); + fill_ethhdr (pending_pkt_frame, htons(ETHERTYPE_IP), + get_mac_address(), null_mac_addr); + memcpy(&pending_pkt_frame[sizeof(struct ethhdr)], + buffer, len); + pending_pkt_len =3D len + sizeof(struct ethhdr); + + set_timer(TICKS_SEC); + do { + receive_ether(fd); + if (!arp_entry->eth_len) + break; + } while (get_timer() > 0); + + return 0; + } + + // Send the packet with the known MAC address + fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP), + get_mac_address(), mac_addr); + memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len); + return send_ether(fd, arp_entry->eth_frame, len + sizeof(struct ethhdr)); +} + +/** + * IPv4: Calculate UDP checksum. Places the result into the UDP-header. + *

+ * Use this function after filling the UDP payload. + * + * @param ipv4_hdr Points to the place where IPv4-header starts. + */ +static void fill_udp_checksum(struct iphdr *ipv4_hdr) +{ + unsigned i; + unsigned long checksum =3D 0; + struct iphdr ip_hdr; + char *ptr; + udp_hdr_t *udp_hdr; + + udp_hdr =3D (udp_hdr_t *) (ipv4_hdr + 1); + udp_hdr->uh_sum =3D 0; + + memset(&ip_hdr, 0, sizeof(struct iphdr)); + ip_hdr.ip_src =3D ipv4_hdr->ip_src; + ip_hdr.ip_dst =3D ipv4_hdr->ip_dst; + ip_hdr.ip_len =3D udp_hdr->uh_ulen; + ip_hdr.ip_p =3D ipv4_hdr->ip_p; + + ptr =3D (char*) udp_hdr; + for (i =3D 0; i < udp_hdr->uh_ulen; i+=3D2) + checksum +=3D *((uint16_t*) &ptr[i]); + + ptr =3D (char*) &ip_hdr; + for (i =3D 0; i < sizeof(struct iphdr); i+=3D2) + checksum +=3D *((uint16_t*) &ptr[i]); + + checksum =3D (checksum >> 16) + (checksum & 0xffff); + checksum +=3D (checksum >> 16); + udp_hdr->uh_sum =3D ~checksum; + + /* As per RFC 768, if the computed checksum is zero, + * it is transmitted as all ones (the equivalent in + * one's complement arithmetic). + */ + if (udp_hdr->uh_sum =3D=3D 0) + udp_hdr->uh_sum =3D ~udp_hdr->uh_sum; +} + +/** + * IPv4: Calculates checksum for IP header. + * + * @param packet Points to the IP-header + * @param words Size of the packet in words incl. IP-header and data. + * @return Checksum + * @see iphdr + */ +static unsigned short checksum(unsigned short * packet, int words) +{ + unsigned long checksum; + + for (checksum =3D 0; words > 0; words--) + checksum +=3D *packet++; + checksum =3D (checksum >> 16) + (checksum & 0xffff); + checksum +=3D (checksum >> 16); + + return ~checksum; +} + +static arp_entry_t* lookup_mac_addr(uint32_t ipv4_addr) +{ + unsigned int i; + + for(i=3Darp_consumer; i !=3D arp_producer; i =3D ((i+1)%ARP_ENTRIES) ) { + if(arp_table[i].ipv4_addr =3D=3D ipv4_addr) + return &arp_table[i]; + } + return 0; +} + + +/** + * ARP: Sends an ARP-request package. + * For given IPv4 retrieves MAC via ARP (makes several attempts) + * + * @param fd socket fd + * @param dest_ip IP of the host which MAC should be obtained + */ +static void arp_send_request(int fd, uint32_t dest_ip) +{ + arp_entry_t *arp_entry =3D &arp_table[arp_producer]; + + memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arp= hdr)); + fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST, + get_mac_address(), own_ip, broadcast_mac, dest_ip); + fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, + get_mac_address(), broadcast_mac); + + send_ether(fd, arp_entry->eth_frame, + sizeof(struct ethhdr) + sizeof(struct arphdr)); +} + +/** + * ARP: Sends an ARP-reply package. + * This package is used to serve foreign requests (in case IP in + * foreign request matches our host IP). + * + * @param fd socket fd + * @param src_ip requester IP address (foreign IP) + * @param src_mac requester MAC address (foreign MAC) + */ +static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac) +{ + arp_entry_t *arp_entry =3D &arp_table[arp_producer]; + + memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arp= hdr)); + fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, + get_mac_address(), src_mac); + fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY, + get_mac_address(), own_ip, src_mac, src_ip); + + send_ether(fd, arp_entry->eth_frame, + sizeof(struct ethhdr) + sizeof(struct arphdr)); +} + +/** + * ARP: Creates ARP package. Places ARP-header in a packet and fills it + * with corresponding information. + *

+ * Use this function with similar functions for other network layers + * (fill_ethhdr). + * + * @param packet Points to the place where ARP-header must be placed. + * @param opcode Identifies is it request (ARP_REQUEST) + * or reply (ARP_REPLY) package. + * @param src_mac sender MAC address + * @param src_ip sender IP address + * @param dest_mac receiver MAC address + * @param dest_ip receiver IP address + * @see arphdr + * @see fill_ethhdr + */ +static void fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip) +{ + struct arphdr * arph =3D (struct arphdr *) packet; + + arph -> hw_type =3D htons(1); + arph -> proto_type =3D htons(ETHERTYPE_IP); + arph -> hw_len =3D 6; + arph -> proto_len =3D 4; + arph -> opcode =3D htons(opcode); + + memcpy(arph->src_mac, src_mac, 6); + arph->src_ip =3D htonl(src_ip); + memcpy(arph->dest_mac, dest_mac, 6); + arph->dest_ip =3D htonl(dest_ip); +} + +/** + * ARP: Handles ARP-messages according to Receive-handle diagram. + * Updates arp_table for outstanding ARP requests (see arp_getmac). + * + * @param fd socket fd + * @param packet ARP-packet to be handled + * @param packetsize length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see arp_getmac + * @see receive_ether + * @see arphdr + */ +int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize) +{ + struct arphdr * arph =3D (struct arphdr *) packet; + + if (packetsize < sizeof(struct arphdr)) + return -1; // Packet is too small + + if (arph -> hw_type !=3D htons(1) || arph -> proto_type !=3D htons(ETHERT= YPE_IP)) + return -1; // Unknown hardware or unsupported protocol + + if (arph -> dest_ip !=3D htonl(own_ip)) + return -1; // receiver IP doesn't match our IP + + switch(htons(arph -> opcode)) { + case ARP_REQUEST: + // foreign request + if(own_ip !=3D 0) + arp_send_reply(fd, htonl(arph->src_ip), arph -> src_mac); + return 0; // no error + case ARP_REPLY: { + unsigned int i; + // if it is not for us -> return immediately + if(memcmp(get_mac_address(), arph->dest_mac, 6)) { + return 0; // no error + } + + if(arph->src_ip =3D=3D 0) { + // we are not interested for a MAC address if + // the IPv4 address is 0.0.0.0 or ff.ff.ff.ff + return -1; + } + + // now let's find the corresponding entry in the ARP table + + for(i=3Darp_consumer; i !=3D arp_producer; i =3D ((i+1)%ARP_ENTRIES) ) { + if(arp_table[i].ipv4_addr =3D=3D arph->src_ip) + break; + } + if(i =3D=3D arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr,= 6) !=3D 0) { + // we have not asked to resolve this IPv4 address ! + return -1; + } + + memcpy(arp_table[i].mac_addr, arph->src_mac, 6); + + // do we have something to send + if (arp_table[i].pkt_pending) { + struct ethhdr * ethh =3D (struct ethhdr *) pending_pkt_frame; + memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6); + + send_ether(fd, pending_pkt_frame, pending_pkt_len); + arp_table[i].pkt_pending =3D 0; + arp_table[i].eth_len =3D 0; + } + return 0; // no error + } + default: + break; + } + return -1; // Invalid message type +} + +/** + * ICMP: Send an ICMP Echo request to destination IPv4 address. + * This function does also set a global variable to the + * destination IPv4 address. If there is an ICMP Echo Reply + * received later then the variable is set back to 0. + * In other words, reading a value of 0 form this variable + * means that an answer to the request has been arrived. + * + * @param fd socket descriptor + * @param _ping_dst_ip destination IPv4 address + */ +void ping_ipv4(int fd, uint32_t _ping_dst_ip) +{ + unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)]; + struct icmphdr *icmp; + + ping_dst_ip =3D _ping_dst_ip; + + if(ping_dst_ip =3D=3D 0) + return; + + fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_= ICMP, + 0, ping_dst_ip); + icmp =3D (struct icmphdr *) (packet + sizeof(struct iphdr)); + icmp->type =3D ICMP_ECHO_REQUEST; + icmp->code =3D 0; + icmp->checksum =3D 0; + icmp->options.echo.id =3D 0xd476; + icmp->options.echo.seq =3D 1; + + memset(icmp->payload.data, '*', sizeof(icmp->payload.data)); + + icmp->checksum =3D + checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1); + send_ipv4(fd, packet, sizeof(struct iphdr) + sizeof(struct icmphdr)); +} + +/** + * ICMP: Return host IPv4 address that we are waiting for a + * ICMP Echo reply message. If this value is 0 then we have + * received an reply. + * + * @return ping_dst_ip host IPv4 address + */ +uint32_t pong_ipv4(void) +{ + return ping_dst_ip; +} + +/** + * ICMP: Handles ICMP-packets according to Receive-handle diagram. + * + * @param fd socket fd + * @param icmp_packet ICMP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see handle_ipv4 + */ +static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, + int32_t packetsize) +{ + struct icmphdr *icmp =3D (struct icmphdr *) packet; + + switch(icmp->type) { + case ICMP_ECHO_REPLY: + if (icmp->options.echo.id !=3D 0xd476) + return -1; + if (icmp->options.echo.seq !=3D 1) + return -1; + if(ping_dst_ip !=3D iph->ip_src + || ping_dst_ip =3D=3D 0) + return -1; + ping_dst_ip =3D 0; + break; + case ICMP_DST_UNREACHABLE: { + // We've got Destination Unreachable msg + // Inform corresponding upper network layers + struct iphdr * bad_iph =3D (struct iphdr * ) &icmp->payload; + + switch(bad_iph->ip_p) { + case IPTYPE_TCP: + handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize + - sizeof(struct icmphdr) + - sizeof(struct iphdr), icmp->code); + break; + case IPTYPE_UDP: + handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize + - sizeof(struct icmphdr) + - sizeof(struct iphdr), icmp->code); + break; + } + break; + } + case ICMP_SRC_QUENCH: + break; + case ICMP_REDIRECT: + break; + case ICMP_ECHO_REQUEST: { + // We've got an Echo Request - answer with Echo Replay msg + unsigned char reply_packet[sizeof(struct iphdr) + packetsize]; + struct icmphdr *reply_icmph; + + fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize, + IPTYPE_ICMP, 0, iph->ip_src); + + reply_icmph =3D (struct icmphdr *) &reply_packet[sizeof(struct iphdr)]; + memcpy(reply_icmph, packet, packetsize); + reply_icmph -> type =3D ICMP_ECHO_REPLY; + reply_icmph -> checksum =3D 0; + reply_icmph->checksum =3D checksum((unsigned short *) reply_icmph, + sizeof(struct icmphdr) >> 1); + + send_ipv4(fd, reply_packet, sizeof(struct iphdr) + packetsize); + break; + } + case ICMP_TIME_EXCEEDED: + break; + case ICMP_PARAMETER_PROBLEM: + break; + case ICMP_TIMESTAMP_REQUEST: + break; + case ICMP_TIMESTAMP_REPLY: + break; + case ICMP_INFORMATION_REQUEST: + break; + case ICMP_INFORMATION_REPLY: + break; + } + return 0; +} diff --git a/pc-bios/s390-ccw/libnet/ipv4.h b/pc-bios/s390-ccw/libnet/ipv4.h new file mode 100644 index 0000000..5717c9a --- /dev/null +++ b/pc-bios/s390-ccw/libnet/ipv4.h @@ -0,0 +1,97 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#ifndef _IPV4_H_ +#define _IPV4_H_ + +#include + +#define IPTYPE_ICMP 1 + +/** \struct iphdr + * A header for IP-packets. + * For more information see RFC 791. + */ +struct iphdr { + uint8_t ip_hlv; /**< Header length and version of the header */ + uint8_t ip_tos; /**< Type of Service */ + uint16_t ip_len; /**< Length in octets, inlc. this header and data */ + uint16_t ip_id; /**< ID is used to aid in assembling framents */ + uint16_t ip_off; /**< Info about fragmentation (control, offset) */ + uint8_t ip_ttl; /**< Time to Live */ + uint8_t ip_p; /**< Next level protocol type */ + uint16_t ip_sum; /**< Header checksum */ + uint32_t ip_src; /**< Source IP address */ + uint32_t ip_dst; /**< Destination IP address */ +}; +typedef struct iphdr ipv4_hdr_t; + +/* ICMP Error Codes */ +#define ICMP_NET_UNREACHABLE 0 +#define ICMP_HOST_UNREACHABLE 1 +#define ICMP_PROTOCOL_UNREACHABLE 2 +#define ICMP_PORT_UNREACHABLE 3 +#define ICMP_FRAGMENTATION_NEEDED 4 +#define ICMP_SOURCE_ROUTE_FAILED 5 + +/** \struct arphdr + * A header for ARP-messages, retains info about HW and proto addresses. + * For more information see RFC 826. + */ +struct arphdr { + uint16_t hw_type; /**< HW address space (1 for Ethernet) */ + uint16_t proto_type; /**< Protocol address space */ + uint8_t hw_len; /**< Byte length of each HW address */ + uint8_t proto_len; /**< Byte length of each proto address */ + uint16_t opcode; /**< Identifies is it request (1) or reply (2) */ + uint8_t src_mac[6]; /**< HW address of sender of this packet */ + uint32_t src_ip; /**< Proto address of sender of this packet */ + uint8_t dest_mac[6]; /**< HW address of target of this packet */ + uint32_t dest_ip; /**< Proto address of target of this packet */ +} __attribute((packed)); + +/************** Initialization of the IPv4 network layer. **************/ +extern void set_ipv4_address(uint32_t own_ip); +extern uint32_t get_ipv4_address(void); +extern void set_ipv4_multicast(uint32_t multicast_ip); +extern uint32_t get_ipv4_multicast(void); +extern void set_ipv4_router(uint32_t router_ip); +extern uint32_t get_ipv4_router(void); +extern void set_ipv4_netmask(uint32_t subnet_mask); +extern uint32_t get_ipv4_netmask(void); +extern uint32_t get_default_ipv4_netmask(char *ip_addr); + +extern int (*send_ip) (int fd, void *, int); + +/* fills ip header */ +extern void fill_iphdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst); + +/* Send a IPv4 packet. Adding the Ethernet-Header and resolving the + * MAC address is done transparent in the background if necessary. + */ +extern int send_ipv4(int fd, void* buffer, int len); + +/* Sends an ICMP Echo request to destination IPv4 address */ +extern void ping_ipv4(int fd, uint32_t _ping_dst_ip); + +/* Returns host IPv4 address that we are waiting for a response */ +extern uint32_t pong_ipv4(void); + +/* Handles IPv4-packets that are detected by receive_ether. */ +extern int8_t handle_ipv4(int fd, uint8_t * packet, uint32_t packetsize); + +/* Handles ARP-packets that are detected by receive_ether. */ +extern int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize); + +#endif diff --git a/pc-bios/s390-ccw/libnet/ipv6.c b/pc-bios/s390-ccw/libnet/ipv6.c new file mode 100644 index 0000000..62a444e --- /dev/null +++ b/pc-bios/s390-ccw/libnet/ipv6.c @@ -0,0 +1,774 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include +#include +#include +#include +#include +#include +#include "ethernet.h" +#include "ipv6.h" +#include "icmpv6.h" +#include "ndp.h" +#include "udp.h" + +#undef IPV6_DEBUG +//#define IPV6_DEBUG +#ifdef IPV6_DEBUG +#define dprintf(_x ...) do { printf(_x); } while (0) +#else +#define dprintf(_x ...) +#endif + +/****************************** PROTOTYPES *******************************/ +static void ipv6_init(int fd); +static int ip6_is_multicast (ip6_addr_t * ip); + +/****************************** LOCAL VARIABLES **************************/ + +/* List of Ipv6 Addresses */ +static struct ip6addr_list_entry *first_ip6; +static struct ip6addr_list_entry *last_ip6; + +/* Own IPv6 address */ +static struct ip6addr_list_entry *own_ip6; + +/* All nodes link-local address */ +struct ip6addr_list_entry all_nodes_ll; + +/* Null IPv6 address */ +static ip6_addr_t null_ip6; + +/* helper variables */ +static uint8_t null_mac[] =3D {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +struct ip6_config ip6_state; + +/****************************** IMPLEMENTATION ***************************/ + +/** + * IPv6: Set the own IPv6 address. + * + * @param fd Socket descriptor + * @param _own_ip client IPv6 address (e.g. ::1) + */ +void set_ipv6_address(int fd, ip6_addr_t *_own_ip6) +{ + struct ip6addr_list_entry *ile; + + ile =3D malloc(sizeof(struct ip6addr_list_entry)); + if (!ile) + return; + memset(ile, 0, sizeof(struct ip6addr_list_entry)); + own_ip6 =3D ile; + + /* If no address was passed as a parameter generate a link-local + * address from our MAC address.*/ + if (_own_ip6 =3D=3D NULL) + ip6_create_ll_address(get_mac_address(), &own_ip6->addr); + else + memcpy (&(own_ip6->addr.addr), _own_ip6, 16); + + /* Add to our list of IPv6 addresses */ + ip6addr_add (own_ip6); + + ipv6_init(fd); + + /* + * Check whether we've got a non-link-local address during + * ipv6_init() and use that as preferred address if possible + */ + if (_own_ip6 =3D=3D NULL) { + for (ile =3D first_ip6; ile !=3D NULL ; ile =3D ile->next) { + if (!ip6_is_multicast(&ile->addr) && + !ip6_is_linklocal(&ile->addr)) { + own_ip6 =3D ile; + break; + } + } + } +} + +/** + * IPv6: Get pointer to own IPv6 address. + * + * @return pointer to client IPv6 address (e.g. ::1) + */ +ip6_addr_t *get_ipv6_address(void) +{ + return (ip6_addr_t *) &(own_ip6->addr); +} + +/** + * IPv6: Search for IPv6 address in list + * + * @return 0 - IPv6 address is not in list + * 1 - IPv6 address is in list + */ +static int8_t find_ip6addr(ip6_addr_t *ip) +{ + struct ip6addr_list_entry *n =3D NULL; + + if (ip =3D=3D NULL) + return 0; + + for (n =3D first_ip6; n !=3D NULL ; n=3Dn->next) + if (ip6_cmp (&(n->addr), ip)) + return 1; /* IPv6 address is in our list*/ + + return 0; /* not one of our IPv6 addresses*/ +} + +/** + * NET: Handles IPv6-packets + * + * @param fd - Socket descriptor + * @param ip6_packet - Pointer to IPv6 header + * @param packetsize - Size of Ipv6 packet + * @return ERROR - -1 if packet is too small or unknown protocol + * return value of handle_udp + * + * @see handle_udp + * @see ip6hdr + */ +int8_t handle_ipv6(int fd, uint8_t * ip6_packet, uint32_t packetsize) +{ + + struct ip6hdr *ip6 =3D NULL; + ip6 =3D (struct ip6hdr *) ip6_packet; + + /* Only handle packets which are for us */ + if (! find_ip6addr(&(ip6->dst))) + return -1; + + if (packetsize < sizeof(struct ip6hdr)) + return -1; // packet is too small + + switch (ip6->nh) { + case IPTYPE_UDP: + return handle_udp (fd, ip6_packet + sizeof (struct ip6hdr), + ip6->pl); + case IPTYPE_ICMPV6: + return handle_icmpv6 (fd, (struct ethhdr *) ip6_packet - sizeof(struct = ethhdr), + ip6_packet); + } + + return -1; // unknown protocol +} + + /** + * NET: Creates IPv6-packet. Places IPv6-header in a packet and fills it + * with corresponding information. + *

+ * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where IPv6-header must be place= d. + * @param packetsize Size of payload (i.e. excluding ethhdr and ip6hdr) + * @param ip_proto Type of the next level protocol (e.g. UDP). + * @param ip6_src Sender IPv6 address + * @param ip6_dst Receiver IPv6 address + * @see ip6hdr + * @see fill_iphdr + * @see fill_ethhdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void fill_ip6hdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst) +{ + struct ip6hdr * ip6h =3D (struct ip6hdr *) packet; + + ip6h->ver_tc_fl =3D 6 << 28; // set version to 6 + ip6h->pl =3D packetsize; // IPv6 payload size + ip6h->nh =3D ip_proto; + ip6h->hl =3D 255; + memcpy (&(ip6h->src), ip6_src, IPV6_ADDR_LENGTH); + memcpy (&(ip6h->dst), ip6_dst, IPV6_ADDR_LENGTH); +} + +/** + * NET: For a given MAC calculates EUI64-Identifier. + * See RFC 4291 "IP Version 6 Addressing Architecture" + * + */ +uint64_t mac2eui64(const uint8_t *mac) +{ + uint8_t eui64id[8]; + uint64_t retid; + + memcpy (eui64id, mac, 3); + memcpy (eui64id + 5, mac + 3, 3); + eui64id[3] =3D 0xff; + eui64id[4] =3D 0xfe; + + memcpy(&retid, eui64id, 8); + return retid; +} + +/** + * NET: create link-local IPv6 address + * + * @param own_mac MAC of NIC + * @param ll_addr pointer to link-local address which should be created + */ +void ip6_create_ll_address(const uint8_t *own_mac, ip6_addr_t *ll_addr) +{ + ll_addr->part.prefix =3D IPV6_LL_PREFIX; + ll_addr->part.interface_id =3D mac2eui64((uint8_t *) own_mac); +} + +/* + * NET: check if we already have an address with the same prefix. + * @param struct ip6_addr_list_entry *ip6 + * @return true or false + */ +int8_t unknown_prefix(ip6_addr_t *ip) +{ + struct ip6addr_list_entry *node; + + for( node =3D first_ip6; node !=3D NULL; node=3Dnode->next ) + if( node->addr.part.prefix =3D=3D ip->part.prefix ) + return 0; /* address is one of ours */ + + return 1; /* prefix not yet in our list */ +} + +/* + * NET: Create empty element for prefix list and return a pointer to it; + * @return NULL - malloc failed + * ! NULL - pointer to new prefix_info + */ +struct prefix_info *ip6_create_prefix_info(void) +{ + struct prefix_info *prfx_info; + + prfx_info =3D malloc (sizeof(struct prefix_info)); + if (!prfx_info) + return NULL; + memset(prfx_info, 0, sizeof(struct prefix_info)); + + return prfx_info; +} + +/* + * NET: create a new IPv6 address with a given network prefix + * and add it to our IPv6 address list + * + * @param ip6_addr prefix (as received in RA) + * @return NULL - pointer to new ip6addr_list entry + */ +void *ip6_prefix2addr(ip6_addr_t prefix) +{ + struct ip6addr_list_entry *new_address; + uint64_t interface_id; + + new_address =3D malloc (sizeof(struct ip6addr_list_entry)); + if( !new_address ) + return NULL; + memset(new_address, 0, sizeof(struct ip6addr_list_entry)); + + /* fill new addr struct */ + /* extract prefix from Router Advertisement */ + memcpy (&(new_address->addr.part.prefix), &prefix, 8 ); + + /* interface id is generated from MAC address */ + interface_id =3D mac2eui64 (get_mac_address()); + memcpy (&(new_address->addr.part.interface_id), &interface_id, 8); + + return new_address; +} + +/** + * NET: add new IPv6 adress to list + * + * @param ip6_addr *new_address + * @return 0 - passed pointer =3D NULL; + * 1 - ok + */ +int8_t ip6addr_add(struct ip6addr_list_entry *new_address) +{ + struct ip6addr_list_entry *solicited_node; + + + if (new_address =3D=3D NULL) + return 0; + + /* Don't add the same address twice */ + if (find_ip6addr (&(new_address->addr))) + return 0; + + /* If address is a unicast address, we also have to process packets + * for its solicited-node multicast address. + * See RFC 2373 - IP Version 6 Adressing Architecture */ + if (! ip6_is_multicast(&(new_address->addr))) { + solicited_node =3D malloc(sizeof(struct ip6addr_list_entry)); + if (! solicited_node) + return 0; + memset(solicited_node, 0, sizeof(struct ip6addr_list_entry)); + + solicited_node->addr.part.prefix =3D IPV6_SOLIC_NODE_PREFIX; + solicited_node->addr.part.interface_id =3D IPV6_SOLIC_NODE_IFACE_ID; + solicited_node->addr.addr[13] =3D new_address->addr.addr[13]; + solicited_node->addr.addr[14] =3D new_address->addr.addr[14]; + solicited_node->addr.addr[15] =3D new_address->addr.addr[15]; + ip6addr_add (solicited_node); + } + + if (first_ip6 =3D=3D NULL) + first_ip6 =3D new_address; + else + last_ip6->next =3D new_address; + last_ip6 =3D new_address; + last_ip6->next =3D NULL; + + return 1; /* no error */ +} + +/** + * NET: Initialize IPv6 + * + * @param fd socket fd + */ +static void ipv6_init(int fd) +{ + int i =3D 0; + + send_ip =3D &send_ipv6; + + /* Address configuration parameters */ + ip6_state.managed_mode =3D 0; + + /* Null IPv6 address */ + null_ip6.part.prefix =3D 0; + null_ip6.part.interface_id =3D 0; + + /* Multicast addresses */ + all_nodes_ll.addr.part.prefix =3D 0xff02000000000000; + all_nodes_ll.addr.part.interface_id =3D 1; + ip6addr_add(&all_nodes_ll); + + ndp_init(); + + send_router_solicitation (fd); + for(i=3D0; i < 4 && !is_ra_received(); i++) { + set_timer(TICKS_SEC); + do { + receive_ether(fd); + if (is_ra_received()) + break; + } while (get_timer() > 0); + } +} + +/** + * NET: compare IPv6 adresses + * + * @param ip6_addr ip_1 + * @param ip6_addr ip_2 + */ +int8_t ip6_cmp(ip6_addr_t *ip_1, ip6_addr_t *ip_2) +{ + return ((int8_t) !memcmp( &(ip_1->addr[0]), &(ip_2->addr[0]), + IPV6_ADDR_LENGTH )); +} + +/** + * NET: Calculate checksum over IPv6 header and upper-layer protocol + * (e.g. UDP or ICMPv6) + * + * @param *ip - pointer to IPv6 address + * @return true or false + */ +int ip6_is_multicast(ip6_addr_t * ip) +{ + return ip->addr[0] =3D=3D 0xFF; +} + +/** + * NET: Generate multicast MAC address from IPv6 address + * (e.g. UDP or ICMPv6) + * + * @param *ip - pointer to IPv6 address + * @param *mc_mac pointer to an array with 6 bytes (for the MAC address) + * @return pointer to Multicast MAC address + */ +static uint8_t *ip6_to_multicast_mac(ip6_addr_t * ip, uint8_t *mc_mac) +{ + mc_mac[0] =3D 0x33; + mc_mac[1] =3D 0x33; + memcpy (mc_mac+2, (uint8_t *) &(ip->addr)+12, 4); + + return mc_mac; +} + +/** + * Check whether an IPv6 address is on the same network as we are + */ +static bool is_ip6addr_in_my_net(ip6_addr_t *ip) +{ + struct ip6addr_list_entry *n =3D NULL; + + for (n =3D first_ip6; n !=3D NULL; n =3D n->next) { + if (n->addr.part.prefix =3D=3D ip->part.prefix) + return true; /* IPv6 address is in our neighborhood */ + } + + return false; /* not in our neighborhood */ +} + +/** + * NET: calculate checksum over IPv6 header and upper-layer protocol + * (e.g. UDP or ICMPv6) + * + * @param struct ip6hdr *ip6h - pointer to IPv6 header + * @param unsigned short *packet - pointer to header of upper-layer + * protocol + * @param int words - number of words (as in 2 bytes) + * starting from *packet + * @return checksum + */ +static unsigned short ip6_checksum(struct ip6hdr *ip6h, unsigned short *pa= cket, + int words) +{ + int i=3D0; + unsigned long checksum; + struct ip6hdr pseudo_ip6h; + unsigned short *pip6h; + + memcpy (&pseudo_ip6h, ip6h, sizeof(struct ip6hdr)); + pseudo_ip6h.hl =3D ip6h->nh; + pseudo_ip6h.ver_tc_fl =3D 0; + pseudo_ip6h.nh =3D 0; + pip6h =3D (unsigned short *) &pseudo_ip6h; + + for (checksum =3D 0; words > 0; words--) { + checksum +=3D *packet++; + i++; + } + + for (i =3D 0; i < 20; i++) { + checksum +=3D *pip6h++; + } + + checksum =3D (checksum >> 16) + (checksum & 0xffff); + checksum +=3D (checksum >> 16); + + return ~checksum; +} + +/** + * NET: Handles IPv6-packets + * + * @param fd socket fd + * @param ip6_packet Pointer to IPv6 header in packet + * @param packetsize Size of IPv6 packet + * @return -1 : Some error occured + * 0 : packet stored (NDP request sent - packet will be sent if + * NDP response is received) + * >0 : packet sent (number of transmitted bytes is returned) + * + * @see receive_ether + * @see ip6hdr + */ +int send_ipv6(int fd, void* buffer, int len) +{ + struct ip6hdr *ip6h; + struct udphdr *udph; + struct icmp6hdr *icmp6h; + ip6_addr_t ip_dst; + uint8_t *mac_addr, mc_mac[6]; + static uint8_t ethframe[ETH_MTU_SIZE]; + + mac_addr =3D null_mac; + + ip6h =3D (struct ip6hdr *) buffer; + udph =3D (struct udphdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr)= ); + icmp6h =3D (struct icmp6hdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr)= ); + + memcpy(&ip_dst, &ip6h->dst, 16); + + if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE) + return -1; + + if ( ip6_cmp (&ip6h->src, &null_ip6)) + memcpy (&(ip6h->src), get_ipv6_address(), IPV6_ADDR_LENGTH); + + if (ip6h->nh =3D=3D 17) {//UDP + udph->uh_sum =3D ip6_checksum (ip6h, (unsigned short *) udph , + ip6h->pl >> 1); + /* As per RFC 768, if the computed checksum is zero, + * it is transmitted as all ones (the equivalent in + * one's complement arithmetic). + */ + if (udph->uh_sum =3D=3D 0) + udph->uh_sum =3D ~udph->uh_sum; + } + else if (ip6h->nh =3D=3D 0x3a) //ICMPv6 + icmp6h->checksum =3D ip6_checksum (ip6h, + (unsigned short *) icmp6h, + ip6h->pl >> 1); + + if (ip6_is_multicast (&ip_dst)) { + /* If multicast, then create a proper multicast mac address */ + mac_addr =3D ip6_to_multicast_mac (&ip_dst, mc_mac); + } else if (!is_ip6addr_in_my_net(&ip_dst)) { + /* If server is not in same subnet, user MAC of the router */ + struct router *gw; + gw =3D ipv6_get_default_router(&ip6h->src); + mac_addr =3D gw ? gw->mac : null_mac; + } else { + /* Normal unicast, so use neighbor cache to look up MAC */ + struct neighbor *n =3D find_neighbor (&ip_dst); + if (n) { /* Already cached ? */ + if (memcmp(n->mac, null_mac, ETH_ALEN) !=3D 0) + mac_addr =3D n->mac; /* found it */ + } else { + mac_addr =3D null_mac; + n =3D malloc(sizeof(struct neighbor)); + if (!n) + return -1; + memset(n, 0, sizeof(struct neighbor)); + memcpy(&(n->ip.addr[0]), &ip_dst, 16); + n->status =3D NB_PROBE; + n->times_asked +=3D 1; + neighbor_add(n); + } + + if (! memcmp (mac_addr, &null_mac, 6)) { + if (n->eth_len =3D=3D 0) { + send_neighbour_solicitation (fd, &ip_dst); + + // Store the packet until we know the MAC address + fill_ethhdr (n->eth_frame, + htons(ETHERTYPE_IPv6), + get_mac_address(), + mac_addr); + memcpy (&(n->eth_frame[sizeof(struct ethhdr)]), + buffer, len); + n->eth_len =3D len; + set_timer(TICKS_SEC); + do { + receive_ether(fd); + if (n->status =3D=3D NB_REACHABLE) + return len; + } while (get_timer() > 0); + return 0; + } + } + } + + if (mac_addr =3D=3D null_mac) + return -1; + + fill_ethhdr(ethframe, htons(ETHERTYPE_IPv6), get_mac_address(), + mac_addr); + memcpy(ðframe[sizeof(struct ethhdr)], buffer, len); + + return send_ether(fd, ethframe, len + sizeof(struct ethhdr)); +} + +static int check_colons(const char *str) +{ + char *pch, *prv; + int col =3D 0; + int dcol =3D 0; + + dprintf("str : %s\n",str); + pch =3D strchr(str, ':'); + while(pch !=3D NULL){ + prv =3D pch; + pch =3D strchr(pch+1, ':'); + if((pch-prv) !=3D 1) { + col++; + } else { + col--; /* Its part of double colon */ + dcol++; + } + } + + dprintf("The number of col : %d \n",col); + dprintf("The number of dcol : %d \n",dcol); + + if((dcol > 1) || /* Cannot have 2 "::" */ + ((dcol =3D=3D 1) && (col > 5)) || /* Too many ':'s */ + ((dcol =3D=3D 0) && (col !=3D 7)) ) { /* Too few ':'s */ + dprintf(" exiting for check_colons \n"); + return 0; + } + + return (col+dcol); +} + +static int ipv6str_to_bytes(const char *str, char *ip) +{ + char block[5]; + int res; + char *pos; + uint32_t cnt =3D 0, len; + + dprintf("str : %s \n",str); + + while (*str !=3D 0) { + if (cnt > 15 || !isxdigit(*str)){ + return 0; + } + if ((pos =3D strchr(str, ':')) !=3D NULL) { + len =3D (int16_t) (pos - str); + dprintf("\t len is : %d \n",len); + if (len > 4) + return 0; + strncpy(block, str, len); + block[len] =3D 0; + dprintf("\t str : %s \n",str); + dprintf("\t block : %s \n",block); + str +=3D len; + } else { + strncpy(block, str, 4); + block[4] =3D 0; + dprintf("\t str : %s \n",str); + dprintf("\t block : %s \n",block); + str +=3D strlen(block); + } + res =3D strtol(block, NULL, 16); + dprintf("\t res : %x \n",res); + if ((res > 0xFFFF) || (res < 0)) + return 0; + ip[cnt++] =3D (res & 0xFF00) >> 8; + ip[cnt++] =3D (res & 0x00FF); + if (*str =3D=3D ':'){ + str++; + } + } + + dprintf("cnt : %d\n",cnt); + return cnt; +} + +int str_to_ipv6(const char *str, uint8_t *ip) +{ + int i, k; + uint16_t len; + char *ptr; + char tmp[30], buf[16]; + + memset(ip,0,16); + + if(!check_colons(str)) + return 0; + + if ((ptr =3D strstr(str, "::")) !=3D NULL) { + /* Handle the ::1 IPv6 loopback */ + if(!strcmp(str,"::1")) { + ip[15] =3D 1; + return 16; + } + len =3D (ptr-str); + dprintf(" len : %d \n",len); + if (len >=3D sizeof(tmp)) + return 0; + strncpy(tmp, str, len); + tmp[len] =3D 0; + ptr +=3D 2; + + i =3D ipv6str_to_bytes(ptr, buf); + if(i =3D=3D 0) + return i; + + #if defined(ARGS_DEBUG) + int j; + dprintf("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D bottom part i : %d \n",i); + for(j=3D0; j +#include "ethernet.h" + +#define __IPV6_DEBUG__ + +#ifdef __IPV6_DEBUG__ +#define IPV6_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__);= } while (0) +#else +#define IPV6_DEBUG_PRINT(format, ...) +#endif + +#define IPV6_ADDR_LENGTH 16 /* Size of IPv6 adress in bytes */ +#define IPV6_LL_PREFIX 0xFE80000000000000ULL +#define IPV6_LL_PREFIX_MASK 0xFFC0000000000000ULL +#define IPV6_SOLIC_NODE_PREFIX 0xFF02000000000000ULL +#define IPV6_SOLIC_NODE_IFACE_ID 0x00000001FF000000ULL + +/** + * An IPv6 Address + */ +typedef union { + uint8_t addr[IPV6_ADDR_LENGTH]; + struct { + uint64_t prefix; + uint64_t interface_id; + } part; +} ip6_addr_t; + +typedef struct { + uint8_t type; + uint8_t pad[7]; + union { + ip6_addr_t v6; + char v4[4]; + } addr; +} netaddr_t; + +/** \struct prefix_info + * + * List of Prefixes we have adresses from + * Used for internal purposes, information derived from prefix option + * in Router Advertisements + * See RFC 4861 section 4.6.2 + */ +struct prefix_info { + uint64_t prefix; + uint8_t on_link:1, /* When set prefix can be used for on-link + * determination */ + autoconf:1, /* Prefix can be used for stateless address + * configuration */ + reserved1:6; + uint32_t valid_lifetime; /* Time until prefix expires */ + uint32_t preferred_lifetime; /* Time until prefix becomes deprecated */ + uint32_t start_time; /* Time when received */ + uint32_t reserved2; + struct prefix_info *next; +}; + + +/* List of IPv6 addresses */ +struct ip6addr_list_entry { + ip6_addr_t addr; + struct prefix_info prfx_info; + struct ip6addr_list_entry *next; +}; + +/** \struct ip6hdr + * A header for IPv6 packets. + * For more information see RFC 2460 + */ +struct ip6hdr { + uint32_t ver_tc_fl; /**< Version, Traffic class, Flow label */ + uint16_t pl; /**< Payload length */ + uint8_t nh; /**< Next header */ + uint8_t hl; /**< Hop limit */ + ip6_addr_t src; /**< IPv6 source address */ + ip6_addr_t dst; /**< IPv6 destination address */ +} __attribute((packed)); + +/** \struct packeth + * Struct with pointers to headers within a packet + */ +struct packeth { + struct ethhdr *ethh; + struct ip6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct udphdr *udph; + /* ... */ +}; + +/** \struct parseip6_state + * Stores information about state of IPv6 address parser + */ +struct parseip6_state { + char *lookahead; + char *ptr; + const char *addr; + int state; + int s1ctr; + int s2ctr; + int blocknr; + int zeroblocks; + int i; + int done; + int errorcode; +}; + +/** \struct ip6_config + * Stores flags wheter we use Stateless- or Stateful Autoconfiguration or = DHCPv6 + */ +struct ip6_config { + uint8_t managed_mode:1, + other_config:1, + reserved:6; +}; + +/******************** VARIABLES ******************************************= ****/ +/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ +extern int (*send_ip) (int fd, void *, int); + +extern struct ip6_config ip6_state; + +/******************** FUNCTIONS ******************************************= ***/ +/* Handles IPv6-packets that are detected by receive_ether. */ +int8_t handle_ipv6(int fd, uint8_t * ip6_packet, uint32_t packetsize); + +/* Fill IPv6 header */ +void fill_ip6hdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst); + +/* Set own IPv6 address */ +void set_ipv6_address(int fd, ip6_addr_t *own_ip6); + +/* Get own IPv6 address */ +ip6_addr_t *get_ipv6_address(void); + +/* Create link-local address from a given Mac Address */ +void ip6_create_ll_address (const uint8_t *own_mac, ip6_addr_t *ll_addr); + +/* For a given MAC calculates EUI64-Identifier.*/ +uint64_t mac2eui64 (const uint8_t *mac); + +/* Create empty element for prefix list and return a pointer to it */ +struct prefix_info * ip6_create_prefix_info(void); + +/* Create a new IPv6 address with a given network prefix + * and add it to our IPv6 address list */ +void * ip6_prefix2addr (ip6_addr_t prefix); + +/* Compare IPv6 adresses */ +int8_t ip6_cmp( ip6_addr_t *ip_1, ip6_addr_t *ip_2 ); + +/* Check if it is a link-local address */ +static inline int ip6_is_linklocal(ip6_addr_t *ip) +{ + return (ip->part.prefix & IPV6_LL_PREFIX_MASK) =3D=3D IPV6_LL_PREFIX; +} + +/* Check if prefix is already in our list */ +int8_t unknown_prefix (ip6_addr_t *ip); + +/* Send IPv6 packet */ +int send_ipv6 (int fd, void* buffer, int len); + +/* Add IPv6 address to list */ +int8_t ip6addr_add (struct ip6addr_list_entry *new_address); + +/* Parse an IPv6 address */ +int parseip6(const char *addr, uint8_t *parsedaddr); +int str_to_ipv6(const char *str, uint8_t *ip); +void ipv6_to_str(const uint8_t *ip, char *str); + +#endif diff --git a/pc-bios/s390-ccw/libnet/ndp.c b/pc-bios/s390-ccw/libnet/ndp.c new file mode 100644 index 0000000..f1f51c7 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/ndp.c @@ -0,0 +1,184 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include +#include +#include "ipv6.h" +#include "icmpv6.h" +#include "ndp.h" + +/* Neighbor cache */ +static struct neighbor *first_neighbor; +static struct neighbor *last_neighbor; + +/* Router list */ +static struct router *first_router; +static struct router *last_router; + +/* + * NET: add new router to list + * @param struct router nghb - new router + * @return true or false + */ +int8_t +router_add (struct router *nghb ) +{ + if (nghb =3D=3D NULL) + return -1; + + if (first_router =3D=3D NULL) { + first_router=3D nghb; + last_router =3D first_router; + last_router->next =3D NULL; + } else { + last_router->next =3D nghb; + last_router =3D nghb; + last_router->next =3D NULL; + } + return 1; /* no error */ +} + +/* + * NET: create a new router + * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghS= lct) + * @param struct packeth - pointers to headers in packet + * @return pointer to new router + */ +void * +router_create (uint8_t *mac, ip6_addr_t *ip) +{ + struct router *new_router; + + new_router =3D malloc (sizeof(struct router)); + if( !new_router) { + return 0; + } + memset (new_router, 0, sizeof(struct router)); + + /* fill neighbor struct */ + memcpy (new_router->mac, mac, 6); + memcpy (&(new_router->ip.addr[0]), &(ip->addr[0]), IPV6_ADDR_LENGTH); + + return new_router; +} + +struct router * +find_router( ip6_addr_t *ip ) +{ + struct router *n =3D NULL; + + for (n =3D first_router; n !=3D NULL ; n=3Dn->next) + if (ip6_cmp (&(n->ip), ip)) + return n; /* router is already in list*/ + + return NULL; /* router is unknown */ +} + +/** + * Find a router for a given host address + * @param ip - IPv6 address with the prefered prefix + * @return pointer to router, or NULL if none is available + */ +struct router *ipv6_get_default_router(ip6_addr_t *ip) +{ + struct router *n =3D NULL; + + for (n =3D first_router; n !=3D NULL; n =3D n->next) { + if (n->ip.part.prefix =3D=3D ip->part.prefix) + return n; + } + + return first_router; +} + +/* + * NET: add new neighbor to list + * @param struct neighbor nghb - new neighbor + * @return true or false + */ +int8_t +neighbor_add (struct neighbor *nghb) +{ + if (nghb =3D=3D NULL) + return -1; + + if (first_neighbor =3D=3D NULL) { + first_neighbor =3D nghb; + last_neighbor =3D first_neighbor; + last_neighbor->next =3D NULL; + } else { + last_neighbor->next =3D nghb; + last_neighbor =3D nghb; + last_neighbor->next =3D NULL; + } + + return 1; /* no error */ +} + +/* + * NET: create a new neighbor + * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghS= lct) + * @param struct packeth - pointers to headers in packet + * @return pointer - pointer to new neighbor + * NULL - malloc failed + */ +void * +neighbor_create (uint8_t *packet, struct packeth *headers) +{ + struct neighbor *new_neighbor; + + new_neighbor =3D malloc (sizeof(struct neighbor)); + if( !new_neighbor ) + return NULL; + memset(new_neighbor, 0, sizeof(struct neighbor)); + + /* fill neighbor struct */ + memcpy (&(new_neighbor->mac), + &(headers->ethh->src_mac[0]), 6); + memcpy (&(new_neighbor->ip.addr), &(headers->ip6h->src), IPV6_ADDR_LENGTH= ); + new_neighbor->status =3D NB_INCOMPLETE; + + return new_neighbor; +} + +/** + * NET: Find neighbor with given IPv6 address in Neighbor Cache + * + * @param ip - Pointer to IPv6 address + * @return pointer - pointer to client IPv6 address (e.g. ::1) + * NULL - Neighbor not found + */ +struct neighbor * +find_neighbor (ip6_addr_t *ip) +{ + struct neighbor *n =3D NULL; + + for (n =3D first_neighbor; n !=3D NULL ; n=3Dn->next) { + if (ip6_cmp (&(n->ip), ip)) { + return n; /* neighbor is already in cache */ + } + } + + return NULL; /* neighbor is unknown */ +} + +void ndp_init(void) +{ + /* Router list */ + first_router =3D NULL; + last_router =3D first_router; + + /* Init Neighbour cache */ + first_neighbor =3D NULL; + last_neighbor =3D first_neighbor; +} diff --git a/pc-bios/s390-ccw/libnet/ndp.h b/pc-bios/s390-ccw/libnet/ndp.h new file mode 100644 index 0000000..cd18158 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/ndp.h @@ -0,0 +1,72 @@ +/*************************************************************************= ***** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _NDP_H_ +#define _NDP_H_ + +#include "ipv6.h" + +#define __NDP_DEBUG__ + +#ifdef __NDP_DEBUG__ +#define NDP_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__); = } while (0) +#else +#define NDP_DEBUG_PRINT(format, ...) +#endif + +#define ND_OPTION_SOURCE_LL_ADDR 1 +#define ND_OPTION_TARGET_LL_ADDR 2 +#define ND_OPTION_PREFIX_INFO 3 +#define ND_OPTION_REDIRECT_HDR 4 +#define ND_OPTION_MTU 5 + +/* Default Router List */ +struct router { + uint8_t mac[6]; + ip6_addr_t ip; + uint32_t lifetime; + uint32_t reachable_time; + uint32_t retrans_timer; + struct router *next; +}; + +/* Neighbor cache */ +struct neighbor { + uint8_t mac[6]; + ip6_addr_t ip; + uint8_t is_router; + uint8_t status; + uint8_t times_asked; + /* ... */ + struct neighbor *next; + uint8_t eth_frame[ETH_MTU_SIZE]; + uint32_t eth_len; + +#define NB_INCOMPLETE 1 +#define NB_REACHABLE 2 +#define NB_STALE 3 +#define NB_DELAY 4 +#define NB_PROBE 5 +}; + +/******************** FUNCTIONS ******************************************= ***/ +void ndp_init(void); +int8_t neighbor_add (struct neighbor *); +void * neighbor_create (uint8_t *packet, struct packeth *headers); +struct neighbor * find_neighbor (ip6_addr_t *); + +int8_t router_add(struct router*); +void * router_create(uint8_t *mac, ip6_addr_t *ip); +struct router * find_router(ip6_addr_t *); +struct router *ipv6_get_default_router(ip6_addr_t *ip); + +#endif //_NDP_H_ diff --git a/pc-bios/s390-ccw/libnet/netapps.h b/pc-bios/s390-ccw/libnet/ne= tapps.h new file mode 100644 index 0000000..91c1ebd --- /dev/null +++ b/pc-bios/s390-ccw/libnet/netapps.h @@ -0,0 +1,28 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _NETAPPS_H_ +#define _NETAPPS_H_ + +#define F_IPV4 4 +#define F_IPV6 6 + +struct filename_ip; + +extern int netload(char *buffer, int len, char *ret_buffer, int huge_load, + int block_size, char *args_fs, int alen); +extern int netsave(int argc, char *argv[]); +extern int ping(char *args_fs, int alen); +extern int dhcp(char *ret_buffer, struct filename_ip *fn_ip, + unsigned int retries, int flags); + +#endif diff --git a/pc-bios/s390-ccw/libnet/netload.c b/pc-bios/s390-ccw/libnet/ne= tload.c new file mode 100644 index 0000000..cd3720a --- /dev/null +++ b/pc-bios/s390-ccw/libnet/netload.c @@ -0,0 +1,868 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "args.h" +#include "netapps.h" + +#define IP_INIT_DEFAULT 5 +#define IP_INIT_NONE 0 +#define IP_INIT_BOOTP 1 +#define IP_INIT_DHCP 2 +#define IP_INIT_DHCPV6_STATELESS 3 +#define IP_INIT_IPV6_MANUAL 4 + +#define DEFAULT_BOOT_RETRIES 10 +#define DEFAULT_TFTP_RETRIES 20 +static int ip_version =3D 4; + +typedef struct { + char filename[100]; + int ip_init; + char siaddr[4]; + ip6_addr_t si6addr; + char ciaddr[4]; + ip6_addr_t ci6addr; + char giaddr[4]; + ip6_addr_t gi6addr; + int bootp_retries; + int tftp_retries; +} obp_tftp_args_t; + + +/** + * Parses a argument string for IPv6 booting, extracts all + * parameters and fills a structure accordingly + * + * @param arg_str string with arguments, separated with ',' + * @param argc number of arguments + * @param obp_tftp_args structure which contains the result + * @return updated arg_str + */ +static const char *=20 +parse_ipv6args (const char *arg_str, unsigned int argc, + obp_tftp_args_t *obp_tftp_args) +{ + char *ptr =3D NULL; + char arg_buf[100]; + + // find out siaddr + if (argc =3D=3D 0) + memset(&obp_tftp_args->si6addr.addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if(str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) { + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] =3D=3D 0) { + memset(&obp_tftp_args->si6addr.addr, 0, 16); + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->si6addr.addr, 0, 16); + } + + // find out filename + if (argc =3D=3D 0) + obp_tftp_args->filename[0] =3D 0; + else { + argncpy(arg_str, 0, obp_tftp_args->filename, 100); + for(ptr =3D obp_tftp_args->filename; *ptr !=3D 0; ++ptr) + if(*ptr =3D=3D '\\') { + *ptr =3D '/'; + } + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + + // find out ciaddr + if (argc =3D=3D 0) + memset(&obp_tftp_args->ci6addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr[0])))= { + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] =3D=3D 0) { + memset(&obp_tftp_args->ci6addr.addr, 0, 16); + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->ci6addr.addr, 0, 16); + } + + // find out giaddr + if (argc =3D=3D 0) + memset(&obp_tftp_args->gi6addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) { + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] =3D=3D 0) { + memset(&obp_tftp_args->gi6addr, 0, 16); + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->gi6addr.addr, 0, 16); + } + + return arg_str; +} + + +/** + * Parses a argument string for IPv4 booting, extracts all + * parameters and fills a structure accordingly + * + * @param arg_str string with arguments, separated with ',' + * @param argc number of arguments + * @param obp_tftp_args structure which contains the result + * @return updated arg_str + */ +static const char *=20 +parse_ipv4args (const char *arg_str, unsigned int argc, + obp_tftp_args_t *obp_tftp_args) +{ + char *ptr =3D NULL; + char arg_buf[100]; + + // find out siaddr + if(argc=3D=3D0) { + memset(obp_tftp_args->siaddr, 0, 4); + } else { + argncpy(arg_str, 0, arg_buf, 100); + if(strtoip(arg_buf, obp_tftp_args->siaddr)) { + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] =3D=3D 0) { + memset(obp_tftp_args->siaddr, 0, 4); + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(obp_tftp_args->siaddr, 0, 4); + } + + // find out filename + if(argc=3D=3D0) + obp_tftp_args->filename[0] =3D 0; + else { + argncpy(arg_str, 0, obp_tftp_args->filename, 100); + for(ptr =3D obp_tftp_args->filename; *ptr !=3D 0; ++ptr) + if(*ptr =3D=3D '\\') + *ptr =3D '/'; + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + + // find out ciaddr + if(argc=3D=3D0) + memset(obp_tftp_args->ciaddr, 0, 4); + else { + argncpy(arg_str, 0, arg_buf, 100); + if(strtoip(arg_buf, obp_tftp_args->ciaddr)) { + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] =3D=3D 0) { + memset(obp_tftp_args->ciaddr, 0, 4); + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(obp_tftp_args->ciaddr, 0, 4); + } + + // find out giaddr + if(argc=3D=3D0) + memset(obp_tftp_args->giaddr, 0, 4); + else { + argncpy(arg_str, 0, arg_buf, 100); + if(strtoip(arg_buf, obp_tftp_args->giaddr)) { + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] =3D=3D 0) { + memset(obp_tftp_args->giaddr, 0, 4); + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(obp_tftp_args->giaddr, 0, 4); + } + + return arg_str; +} + +/** + * Parses a argument string which is given by netload, extracts all + * parameters and fills a structure according to this + * + * Netload-Parameters: + * [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries + * + * @param arg_str string with arguments, separated with ',' + * @param obp_tftp_args structure which contains the result + * @return none + */ +static void +parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args) +{ + unsigned int argc; + char arg_buf[100]; + + memset(obp_tftp_args, 0, sizeof(*obp_tftp_args)); + + argc =3D get_args_count(arg_str); + + // find out if we should use BOOTP or DHCP + if(argc=3D=3D0) + obp_tftp_args->ip_init =3D IP_INIT_DEFAULT; + else { + argncpy(arg_str, 0, arg_buf, 100); + if (strcasecmp(arg_buf, "bootp") =3D=3D 0) { + obp_tftp_args->ip_init =3D IP_INIT_BOOTP; + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(strcasecmp(arg_buf, "dhcp") =3D=3D 0) { + obp_tftp_args->ip_init =3D IP_INIT_DHCP; + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + else if(strcasecmp(arg_buf, "ipv6") =3D=3D 0) { + obp_tftp_args->ip_init =3D IP_INIT_DHCPV6_STATELESS; + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + ip_version =3D 6; + } + else + obp_tftp_args->ip_init =3D IP_INIT_DEFAULT; + } + + if (ip_version =3D=3D 4) { + arg_str =3D parse_ipv4args (arg_str, argc, obp_tftp_args); + } + else if (ip_version =3D=3D 6) { + arg_str =3D parse_ipv6args (arg_str, argc, obp_tftp_args); + } + + // find out bootp-retries + if (argc =3D=3D 0) + obp_tftp_args->bootp_retries =3D DEFAULT_BOOT_RETRIES; + else { + argncpy(arg_str, 0, arg_buf, 100); + if(arg_buf[0] =3D=3D 0) + obp_tftp_args->bootp_retries =3D DEFAULT_BOOT_RETRIES; + else { + obp_tftp_args->bootp_retries =3D strtol(arg_buf, 0, 10); + if(obp_tftp_args->bootp_retries < 0) + obp_tftp_args->bootp_retries =3D DEFAULT_BOOT_RETRIES; + } + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } + + // find out tftp-retries + if (argc =3D=3D 0) + obp_tftp_args->tftp_retries =3D DEFAULT_TFTP_RETRIES; + else { + argncpy(arg_str, 0, arg_buf, 100); + if(arg_buf[0] =3D=3D 0) + obp_tftp_args->tftp_retries =3D DEFAULT_TFTP_RETRIES; + else { + obp_tftp_args->tftp_retries =3D strtol(arg_buf, 0, 10); + if(obp_tftp_args->tftp_retries < 0) + obp_tftp_args->tftp_retries =3D DEFAULT_TFTP_RETRIES; + } + arg_str =3D get_arg_ptr(arg_str, 1); + --argc; + } +} + +/** + * DHCP: Wrapper for obtaining IP and configuration info from DHCP server + * for both IPv4 and IPv6. + * (makes several attempts). + * + * @param ret_buffer buffer for returning BOOTP-REPLY packet data + * @param fn_ip contains the following configuration information: + * client MAC, client IP, TFTP-server MAC, + * TFTP-server IP, Boot file name + * @param retries No. of DHCP attempts + * @param flags flags for specifying type of dhcp attempt (IPv4/I= Pv6) + * ZERO - attempt DHCPv4 followed by DHCPv6 + * F_IPV4 - attempt only DHCPv4 + * F_IPV6 - attempt only DHCPv6 + * @return ZERO - IP and configuration info obtained; + * NON ZERO - error condition occurs. + */ +int dhcp(char *ret_buffer, struct filename_ip *fn_ip, unsigned int retries, + int flags) +{ + int i =3D (int) retries+1; + int rc =3D -1; + + printf(" Requesting information via DHCP%s: ", + flags =3D=3D F_IPV4 ? "v4" : flags =3D=3D F_IPV6 ? "v6" : ""); + + if (flags !=3D F_IPV6) + dhcpv4_generate_transaction_id(); + if (flags !=3D F_IPV4) + dhcpv6_generate_transaction_id(); + + do { + printf("\b\b\b%03d", i-1); + if (getchar() =3D=3D 27) { + printf("\nAborted\n"); + return -1; + } + if (!--i) { + printf("\nGiving up after %d DHCP requests\n", retries); + return -1; + } + if (!flags || (flags =3D=3D F_IPV4)) { + ip_version =3D 4; + rc =3D dhcpv4(ret_buffer, fn_ip); + } + if ((!flags && (rc =3D=3D -1)) || (flags =3D=3D F_IPV6)) { + ip_version =3D 6; + set_ipv6_address(fn_ip->fd, 0); + rc =3D dhcpv6(ret_buffer, fn_ip); + if (rc =3D=3D 0) { + memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16); + break; + } + + } + if (rc !=3D -1) /* either success or non-dhcp failure */ + break; + } while (1); + printf("\b\b\b\bdone\n"); + + return rc; +} + +/** + * Seed the random number generator with our mac and current timestamp + */ +static void seed_rng(uint8_t mac[]) +{ + unsigned int seed; + + asm volatile("mftbl %0" : "=3Dr"(seed)); + seed ^=3D (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; + srand(seed); +} + +int netload(char *buffer, int len, char *ret_buffer, int huge_load, + int block_size, char *args_fs, int alen) +{ + char buf[256]; + int rc; + filename_ip_t fn_ip; + int fd_device; + tftp_err_t tftp_err; + obp_tftp_args_t obp_tftp_args; + char null_ip[4] =3D { 0x00, 0x00, 0x00, 0x00 }; + char null_ip6[16] =3D { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00,=20 + 0x00, 0x00, 0x00, 0x00 }; + uint8_t own_mac[6]; + + puts("\n Initializing NIC"); + memset(&fn_ip, 0, sizeof(filename_ip_t)); + + /*********************************************************** + * + * Initialize network stuff and retrieve boot informations + * + ***********************************************************/ + + /* Wait for link up and get mac_addr from device */ + for(rc=3D0; rc 0) { + set_timer(TICKS_SEC); + while (get_timer() > 0); + } + fd_device =3D socket(0, 0, 0, (char*) own_mac); + if(fd_device !=3D -2) + break; + if(getchar() =3D=3D 27) { + fd_device =3D -2; + break; + } + } + + if (fd_device =3D=3D -1) { + strcpy(buf,"E3000: (net) Could not read MAC address"); + bootmsg_error(0x3000, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -100; + } + else if (fd_device =3D=3D -2) { + strcpy(buf,"E3006: (net) Could not initialize network device"); + bootmsg_error(0x3006, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -101; + } + + fn_ip.fd =3D fd_device; + + printf(" Reading MAC address from device: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + own_mac[0], own_mac[1], own_mac[2], + own_mac[3], own_mac[4], own_mac[5]); + + // init ethernet layer + set_mac_address(own_mac); + + seed_rng(own_mac); + + if (alen > 0) { + char args[256]; + if (alen > sizeof(args) - 1) { + puts("ERROR: Parameter string is too long."); + return -7; + } + /* Convert forth string into NUL-terminated C-string */ + strncpy(args, args_fs, alen); + args[alen] =3D 0; + parse_args(args, &obp_tftp_args); + if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES) + obp_tftp_args.bootp_retries =3D DEFAULT_BOOT_RETRIES; + else + obp_tftp_args.bootp_retries -=3D rc; + } + else { + memset(&obp_tftp_args, 0, sizeof(obp_tftp_args_t)); + obp_tftp_args.ip_init =3D IP_INIT_DEFAULT; + obp_tftp_args.bootp_retries =3D DEFAULT_BOOT_RETRIES; + obp_tftp_args.tftp_retries =3D DEFAULT_TFTP_RETRIES; + } + memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4); + + // reset of error code + rc =3D 0; + + /* if we still have got all necessary parameters, then we don't + need to perform an BOOTP/DHCP-Request */ + if (ip_version =3D=3D 4) { + if (memcmp(obp_tftp_args.ciaddr, null_ip, 4) !=3D 0 + && memcmp(obp_tftp_args.siaddr, null_ip, 4) !=3D 0 + && obp_tftp_args.filename[0] !=3D 0) { + + memcpy(&fn_ip.server_ip, &obp_tftp_args.siaddr, 4); + obp_tftp_args.ip_init =3D IP_INIT_NONE; + } + } + else if (ip_version =3D=3D 6) { + if (memcmp(&obp_tftp_args.si6addr, null_ip6, 16) !=3D 0 + && obp_tftp_args.filename[0] !=3D 0) { + memcpy(&fn_ip.server_ip6.addr[0], + &obp_tftp_args.si6addr.addr, 16); + obp_tftp_args.ip_init =3D IP_INIT_IPV6_MANUAL; + } + else { + obp_tftp_args.ip_init =3D IP_INIT_DHCPV6_STATELESS; + } + } + + // construction of fn_ip from parameter + switch(obp_tftp_args.ip_init) { + case IP_INIT_BOOTP: + // if giaddr in not specified, then we have to identify + // the BOOTP server via broadcasts + if(memcmp(obp_tftp_args.giaddr, null_ip, 4) =3D=3D 0) { + // don't do this, when using DHCP !!! + fn_ip.server_ip =3D 0xFFFFFFFF; + } + // if giaddr is specified, then we have to use this + // IP address as proxy to identify the BOOTP server + else { + memcpy(&fn_ip.server_ip, obp_tftp_args.giaddr, 4); + } + rc =3D bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); + break; + case IP_INIT_DHCP: + rc =3D dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, F_IPV4); + break; + case IP_INIT_DHCPV6_STATELESS: + rc =3D dhcp(ret_buffer, &fn_ip, + obp_tftp_args.bootp_retries, F_IPV6); + break; + case IP_INIT_IPV6_MANUAL: + if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16)) { + set_ipv6_address(fn_ip.fd, &obp_tftp_args.ci6addr); + } else { + /* + * If no client address has been specified, then + * use a link-local or stateless autoconfig address + */ + set_ipv6_address(fn_ip.fd, NULL); + memcpy(&fn_ip.own_ip6, get_ipv6_address(), 16); + } + break; + case IP_INIT_DEFAULT: + rc =3D dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, 0); + break; + case IP_INIT_NONE: + default: + break; + } + + if(rc >=3D 0 && ip_version =3D=3D 4) { + if(memcmp(obp_tftp_args.ciaddr, null_ip, 4) !=3D 0 + && memcmp(obp_tftp_args.ciaddr, &fn_ip.own_ip, 4) !=3D 0) + memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4); + + if(memcmp(obp_tftp_args.siaddr, null_ip, 4) !=3D 0 + && memcmp(obp_tftp_args.siaddr, &fn_ip.server_ip, 4) !=3D 0) + memcpy(&fn_ip.server_ip, obp_tftp_args.siaddr, 4); + + // init IPv4 layer + set_ipv4_address(fn_ip.own_ip); + } + else if (rc >=3D 0 && ip_version =3D=3D 6) { + if(memcmp(&obp_tftp_args.ci6addr.addr, null_ip6, 16) !=3D 0 + && memcmp(&obp_tftp_args.ci6addr.addr, &fn_ip.own_ip6, 16) !=3D 0) + memcpy(&fn_ip.own_ip6, &obp_tftp_args.ci6addr.addr, 16); + + if(memcmp(&obp_tftp_args.si6addr.addr, null_ip6, 16) !=3D 0 + && memcmp(&obp_tftp_args.si6addr.addr, &fn_ip.server_ip6.addr, 16) !=3D = 0) + memcpy(&fn_ip.server_ip6.addr, &obp_tftp_args.si6addr.addr, 16); + } + if (rc =3D=3D -1) { + strcpy(buf,"E3001: (net) Could not get IP address"); + bootmsg_error(0x3001, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + close(fn_ip.fd); + return -101; + } + + if (ip_version =3D=3D 4) { + printf(" Using IPv4 address: %d.%d.%d.%d\n", + ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF), + ((fn_ip.own_ip >> 8) & 0xFF), ( fn_ip.own_ip & 0xFF)); + } else if (ip_version =3D=3D 6) { + char ip6_str[40]; + ipv6_to_str(fn_ip.own_ip6.addr, ip6_str); + printf(" Using IPv6 address: %s\n", ip6_str); + } + + if (rc =3D=3D -2) { + sprintf(buf, + "E3002: (net) ARP request to TFTP server " + "(%d.%d.%d.%d) failed", + ((fn_ip.server_ip >> 24) & 0xFF), + ((fn_ip.server_ip >> 16) & 0xFF), + ((fn_ip.server_ip >> 8) & 0xFF), + ( fn_ip.server_ip & 0xFF)); + bootmsg_error(0x3002, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + close(fn_ip.fd); + return -102; + } + if (rc =3D=3D -4 || rc =3D=3D -3) { + strcpy(buf,"E3008: (net) Can't obtain TFTP server IP address"); + bootmsg_error(0x3008, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + close(fn_ip.fd); + return -107; + } + + + /*********************************************************** + * + * Load file via TFTP into buffer provided by OpenFirmware + * + ***********************************************************/ + + if (obp_tftp_args.filename[0] !=3D 0) { + strncpy((char *) fn_ip.filename, obp_tftp_args.filename, sizeof(fn_ip.fi= lename)-1); + fn_ip.filename[sizeof(fn_ip.filename)-1] =3D 0; + } + + if (ip_version =3D=3D 4) { + printf(" Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n", + fn_ip.filename, + ((fn_ip.server_ip >> 24) & 0xFF), + ((fn_ip.server_ip >> 16) & 0xFF), + ((fn_ip.server_ip >> 8) & 0xFF), + ( fn_ip.server_ip & 0xFF)); + } else if (ip_version =3D=3D 6) { + char ip6_str[40]; + printf(" Requesting file \"%s\" via TFTP from ", fn_ip.filename); + ipv6_to_str(fn_ip.server_ip6.addr, ip6_str); + printf("%s\n", ip6_str); + } + + // accept at most 20 bad packets + // wait at most for 40 packets + rc =3D tftp(&fn_ip, (unsigned char *) buffer, + len, obp_tftp_args.tftp_retries, + &tftp_err, huge_load, block_size, ip_version); + + if(obp_tftp_args.ip_init =3D=3D IP_INIT_DHCP) + dhcp_send_release(fn_ip.fd); + + close(fn_ip.fd); + + if (rc > 0) { + printf(" TFTP: Received %s (%d KBytes)\n", fn_ip.filename, + rc / 1024); + } else if (rc =3D=3D -1) { + bootmsg_error(0x3003, "(net) unknown TFTP error"); + return -103; + } else if (rc =3D=3D -2) { + sprintf(buf, + "E3004: (net) TFTP buffer of %d bytes " + "is too small for %s", + len, fn_ip.filename); + bootmsg_error(0x3004, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -104; + } else if (rc =3D=3D -3) { + sprintf(buf,"E3009: (net) file not found: %s", + fn_ip.filename); + bootmsg_error(0x3009, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -108; + } else if (rc =3D=3D -4) { + strcpy(buf,"E3010: (net) TFTP access violation"); + bootmsg_error(0x3010, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -109; + } else if (rc =3D=3D -5) { + strcpy(buf,"E3011: (net) illegal TFTP operation"); + bootmsg_error(0x3011, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -110; + } else if (rc =3D=3D -6) { + strcpy(buf, "E3012: (net) unknown TFTP transfer ID"); + bootmsg_error(0x3012, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -111; + } else if (rc =3D=3D -7) { + strcpy(buf, "E3013: (net) no such TFTP user"); + bootmsg_error(0x3013, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -112; + } else if (rc =3D=3D -8) { + strcpy(buf, "E3017: (net) TFTP blocksize negotiation failed"); + bootmsg_error(0x3017, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -116; + } else if (rc =3D=3D -9) { + strcpy(buf,"E3018: (net) file exceeds maximum TFTP transfer size"); + bootmsg_error(0x3018, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -117; + } else if (rc <=3D -10 && rc >=3D -15) { + sprintf(buf,"E3005: (net) ICMP ERROR \""); + switch (rc) { + case -ICMP_NET_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"net unreachable"); + break; + case -ICMP_HOST_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"host unreachable"); + break; + case -ICMP_PROTOCOL_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"protocol unreachable"); + break; + case -ICMP_PORT_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"port unreachable"); + break; + case -ICMP_FRAGMENTATION_NEEDED - 10: + sprintf(buf+strlen(buf),"fragmentation needed and DF set"); + break; + case -ICMP_SOURCE_ROUTE_FAILED - 10: + sprintf(buf+strlen(buf),"source route failed"); + break; + default: + sprintf(buf+strlen(buf)," UNKNOWN"); + break; + } + sprintf(buf+strlen(buf),"\""); + bootmsg_error(0x3005, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -105; + } else if (rc =3D=3D -40) { + sprintf(buf, + "E3014: (net) TFTP error occurred after " + "%d bad packets received", + tftp_err.bad_tftp_packets); + bootmsg_error(0x3014, &buf[7]); + write_mm_log(buf, strlen(buf), 0x91); + return -113; + } else if (rc =3D=3D -41) { + sprintf(buf, + "E3015: (net) TFTP error occurred after " + "missing %d responses", + tftp_err.no_packets); + bootmsg_error(0x3015, &buf[7]); + write_mm_log(buf, strlen(buf), 0x91); + return -114; + } else if (rc =3D=3D -42) { + sprintf(buf, + "E3016: (net) TFTP error missing block %d, " + "expected block was %d", + tftp_err.blocks_missed, + tftp_err.blocks_received); + bootmsg_error(0x3016, &buf[7]); + write_mm_log(buf, strlen(buf), 0x91); + return -115; + } + return rc; +} + +/** + * Parses a tftp arguments, extracts all + * parameters and fills server ip according to this + * + * Parameters: + * @param buffer string with arguments, + * @param server_ip server ip as result + * @param filename default filename + * @param fd Socket descriptor + * @param len len of the buffer, + * @return 0 on SUCCESS and -1 on failure + */ +int parse_tftp_args(char buffer[], char *server_ip, char filename[], int f= d, + int len) +{ + char *raw; + char *tmp, *tmp1; + int i, j =3D 0; + char domainname[256]; + uint8_t server_ip6[16]; + + raw =3D malloc(len); + if (raw =3D=3D NULL) { + printf("\n unable to allocate memory, parsing failed\n"); + return -1; + } + strncpy(raw,(const char *)buffer,len); + /*tftp url contains tftp://[fd00:4f53:4444:90:214:5eff:fed9:b200]/testfil= e*/ + if(strncmp(raw,"tftp://",7)){ + printf("\n tftp missing in %s\n",raw); + free(raw); + return -1; + } + tmp =3D strchr(raw,'['); + if(tmp !=3D NULL && *tmp =3D=3D '[') { + /*check for valid ipv6 address*/ + tmp1 =3D strchr(tmp,']'); + if (tmp1 =3D=3D NULL) { + printf("\n missing ] in %s\n",raw); + free(raw); + return -1; + } + i =3D tmp1 - tmp; + /*look for file name*/ + tmp1 =3D strchr(tmp,'/'); + if (tmp1 =3D=3D NULL) { + printf("\n missing filename in %s\n",raw); + free(raw); + return -1; + } + tmp[i] =3D '\0'; + /*check for 16 byte ipv6 address */ + if (!str_to_ipv6((tmp+1), (uint8_t *)(server_ip))) { + printf("\n wrong format IPV6 address in %s\n",raw); + free(raw); + return -1;; + } + else { + /*found filename */ + strcpy(filename,(tmp1+1)); + free(raw); + return 0; + } + } + else { + /*here tftp://hostname/testfile from option request of dhcp*/ + /*look for dns server name */ + tmp1 =3D strchr(raw,'.'); + if(tmp1 =3D=3D NULL) { + printf("\n missing . seperator in %s\n",raw); + free(raw); + return -1; + } + /*look for domain name beyond dns server name + * so ignore the current . and look for one more + */ + tmp =3D strchr((tmp1+1),'.'); + if(tmp =3D=3D NULL) { + printf("\n missing domain in %s\n",raw); + free(raw); + return -1; + } + tmp1 =3D strchr(tmp1,'/'); + if (tmp1 =3D=3D NULL) { + printf("\n missing filename in %s\n",raw); + free(raw); + return -1; + } + j =3D tmp1 - (raw + 7); + tmp =3D raw + 7; + tmp[j] =3D '\0'; + strcpy(domainname, tmp); + if (dns_get_ip(fd, domainname, server_ip6, 6) =3D=3D 0) { + printf("\n DNS failed for IPV6\n"); + return -1; + } + ipv6_to_str(server_ip6, server_ip); + + strcpy(filename,(tmp1+1)); + free(raw); + return 0; + } + +} diff --git a/pc-bios/s390-ccw/libnet/tcp.c b/pc-bios/s390-ccw/libnet/tcp.c new file mode 100644 index 0000000..faa0b83 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/tcp.c @@ -0,0 +1,46 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +/************************ DEFINITIONS & DECLARATIONS *********************/ + +#include +#include + +/****************************** LOCAL VARIABLES **************************/ + +/****************************** IMPLEMENTATION ***************************/ + +/** + * TCP: Handles TCP-packets according to Receive-handle diagram. + * + * @param tcp_packet TCP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + */ +int8_t handle_tcp(uint8_t * tcp_packet, int32_t packetsize) +{ + return -1; +} + +/** + * NET: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending TCP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + * @param packet original TCP-packet + * @param packetsize length of the packet + * @see handle_icmp + */ +void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err= _code) +{ +} diff --git a/pc-bios/s390-ccw/libnet/tcp.h b/pc-bios/s390-ccw/libnet/tcp.h new file mode 100644 index 0000000..375afd7 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/tcp.h @@ -0,0 +1,27 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _TCP_H +#define _TCP_H + +#include + +#define IPTYPE_TCP 6 + +/* Handles TCP-packets that are detected by any network layer. */ +extern int8_t handle_tcp(uint8_t * udp_packet, int32_t packetsize); + +/* Handles TCP related ICMP-Dest.Unreachable packets that are detected by + * the network layers. */ +extern void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint= 8_t err_code); + +#endif diff --git a/pc-bios/s390-ccw/libnet/tftp.c b/pc-bios/s390-ccw/libnet/tftp.c new file mode 100644 index 0000000..d0c2f13 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/tftp.c @@ -0,0 +1,594 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +//#define __DEBUG__ + +#define MAX_BLOCKSIZE 1428 +#define BUFFER_LEN 256 + +#define ENOTFOUND 1 +#define EACCESS 2 +#define EBADOP 4 +#define EBADID 5 +#define ENOUSER 7 +//#define EUNDEF 0 +//#define ENOSPACE 3 +//#define EEXISTS 6 + +#define RRQ 1 +#define WRQ 2 +#define DATA 3 +#define ACK 4 +#define ERROR 5 +#define OACK 6 + +/* Local variables */ +static unsigned char packet[BUFFER_LEN]; +static unsigned char *buffer =3D NULL; +static unsigned short block; +static unsigned short blocksize; +static char blocksize_str[6]; /* Blocksize string for read request */ +static int received_len; +static unsigned int retries; +static int huge_load; +static int len; +static int tftp_finished; +static int lost_packets; +static int tftp_errno; +static int ip_version; +static short port_number; +static tftp_err_t *tftp_err; +static filename_ip_t *fn_ip; +static int progress_first; +static int progress_last_bytes; + +/** + * dump_package - Prints a package. + * + * @package: package which is to print + * @len: length of the package + */ +#ifdef __DEBUG__ + +static void dump_package(unsigned char *buffer, unsigned int len) +{ + int i; + + for (i =3D 1; i <=3D len; i++) { + printf("%02x%02x ", buffer[i - 1], buffer[i]); + i++; + if ((i % 16) =3D=3D 0) + printf("\n"); + } + printf("\n"); +} +#endif + +/** + * send_rrq - Sends a read request package. + * + * @fd: Socket Descriptor + */ +static void send_rrq(int fd) +{ + int ip_len =3D 0; + int ip6_payload_len =3D 0; + unsigned short udp_len =3D 0; + unsigned char mode[] =3D "octet"; + char *ptr =3D NULL; + struct iphdr *ip =3D NULL; + struct ip6hdr *ip6 =3D NULL; + struct udphdr *udph =3D NULL; + struct tftphdr *tftp =3D NULL; + + memset(packet, 0, BUFFER_LEN); + + if (4 =3D=3D ip_version) { + ip =3D (struct iphdr *) packet; + udph =3D (struct udphdr *) (ip + 1); + ip_len =3D sizeof(struct iphdr) + sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } + else if (6 =3D=3D ip_version) { + ip6 =3D (struct ip6hdr *) packet; + udph =3D (struct udphdr *) (ip6 + 1); + ip6_payload_len =3D sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2; + ip_len =3D sizeof(struct ip6hdr) + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_addr= ess(), + &(fn_ip->server_ip6)); + + } + udp_len =3D htons(sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(69)); + + tftp =3D (struct tftphdr *) (udph + 1); + tftp->th_opcode =3D htons(RRQ); + + ptr =3D (char *) &tftp->th_data; + memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1); + + ptr +=3D strlen((char *) fn_ip->filename) + 1; + memcpy(ptr, mode, strlen((char *) mode) + 1); + + ptr +=3D strlen((char *) mode) + 1; + memcpy(ptr, "blksize", strlen("blksize") + 1); + + ptr +=3D strlen("blksize") + 1; + memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1); + + send_ip (fd, packet, ip_len); + +#ifdef __DEBUG__ + printf("tftp RRQ with %d bytes transmitted.\n", ip_len); +#endif + return; +} + +/** + * send_ack - Sends a acknowlege package. + * + * @blckno: block number + * @dport: UDP destination port + */ +static void send_ack(int fd, int blckno, unsigned short dport) +{ + int ip_len =3D 0; + int ip6_payload_len =3D 0; + unsigned short udp_len =3D 0; + struct iphdr *ip =3D NULL; + struct ip6hdr *ip6 =3D NULL; + struct udphdr *udph =3D NULL; + struct tftphdr *tftp =3D NULL; + + memset(packet, 0, BUFFER_LEN); + + if (4 =3D=3D ip_version) { + ip =3D (struct iphdr *) packet; + udph =3D (struct udphdr *) (ip + 1); + ip_len =3D sizeof(struct iphdr) + sizeof(struct udphdr) + 4; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } + else if (6 =3D=3D ip_version) { + ip6 =3D (struct ip6hdr *) packet; + udph =3D (struct udphdr *) (ip6 + 1); + ip6_payload_len =3D sizeof(struct udphdr) + 4; + ip_len =3D sizeof(struct ip6hdr) + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_addr= ess(), + &(fn_ip->server_ip6)); + } + udp_len =3D htons(sizeof(struct udphdr) + 4); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport)); + + tftp =3D (struct tftphdr *) (udph + 1); + tftp->th_opcode =3D htons(ACK); + tftp->th_data =3D htons(blckno); + + send_ip(fd, packet, ip_len); + +#ifdef __DEBUG__ + printf("tftp ACK %d bytes transmitted.\n", ip_len); +#endif + + return; +} + +/** + * send_error - Sends an error package. + * + * @fd: Socket Descriptor + * @error_code: Used sub code for error packet + * @dport: UDP destination port + */ +static void send_error(int fd, int error_code, unsigned short dport) +{ + int ip_len =3D 0; + int ip6_payload_len =3D 0; + unsigned short udp_len =3D 0; + struct ip6hdr *ip6 =3D NULL; + struct iphdr *ip =3D NULL; + struct udphdr *udph =3D NULL; + struct tftphdr *tftp =3D NULL; + + memset(packet, 0, BUFFER_LEN); + + if (4 =3D=3D ip_version) { + ip =3D (struct iphdr *) packet; + udph =3D (struct udphdr *) (ip + 1); + ip_len =3D sizeof(struct iphdr) + sizeof(struct udphdr) + 5; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } + else if (6 =3D=3D ip_version) { + ip6 =3D (struct ip6hdr *) packet; + udph =3D (struct udphdr *) (ip6 + 1); + ip6_payload_len =3D sizeof(struct udphdr) + 5; + ip_len =3D sizeof(struct ip6hdr) + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_addr= ess(), + &(fn_ip->server_ip6)); + } + udp_len =3D htons(sizeof(struct udphdr) + 5); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport)); + + tftp =3D (struct tftphdr *) (udph + 1); + tftp->th_opcode =3D htons(ERROR); + tftp->th_data =3D htons(error_code); + ((char *) &tftp->th_data)[2] =3D 0; + + send_ip(fd, packet, ip_len); + +#ifdef __DEBUG__ + printf("tftp ERROR %d bytes transmitted.\n", ip_len); +#endif + + return; +} + +static void print_progress(int urgent, int received_bytes) +{ + static unsigned int i =3D 1; + char buffer[100]; + char *ptr; + + // 1MB steps or 0x400 times or urgent + if(((received_bytes - progress_last_bytes) >> 20) > 0 + || (i & 0x3FF) =3D=3D 0 || urgent) { + if (!progress_first) { + sprintf(buffer, "%d KBytes", (progress_last_bytes >> 10)); + for(ptr =3D buffer; *ptr !=3D 0; ++ptr) + *ptr =3D '\b'; + printf(buffer); + } + printf("%d KBytes", (received_bytes >> 10)); + i =3D 1; + progress_first =3D 0; + progress_last_bytes =3D received_bytes; + } + ++i; +} + +/** + * get_blksize tries to extract the blksize from the OACK package + * the TFTP returned. From RFC 1782 + * The OACK packet has the following format: + * + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * + * @param buffer the network packet + * @param len the length of the network packet + * @return the blocksize the server supports or 0 for error + */ +static int get_blksize(unsigned char *buffer, unsigned int len) +{ + unsigned char *orig =3D buffer; + /* skip all headers until tftp has been reached */ + buffer +=3D sizeof(struct udphdr); + /* skip opc */ + buffer +=3D 2; + while (buffer < orig + len) { + if (!memcmp(buffer, "blksize", strlen("blksize") + 1)) + return (unsigned short) strtoul((char *) (buffer + + strlen("blksize") + 1), + (char **) NULL, 10); + else { + /* skip the option name */ + buffer =3D (unsigned char *) strchr((char *) buffer, 0); + if (!buffer) + return 0; + buffer++; + /* skip the option value */ + buffer =3D (unsigned char *) strchr((char *) buffer, 0); + if (!buffer) + return 0; + buffer++; + } + } + return 0; +} + +/** + * Handle incoming tftp packets after read request was sent + * + * this function also prints out some status characters + * \|-/ for each packet received + * A for an arp packet + * I for an ICMP packet + * #+* for different unexpected TFTP packets (not very good) + * + * @param fd socket descriptor + * @param packet points to the UDP header of the packet + * @param len the length of the network packet + * @return ZERO if packet was handled successfully + * ERRORCODE if error occurred + */ +int32_t handle_tftp(int fd, uint8_t *pkt, int32_t packetsize) +{ + struct udphdr *udph; + struct tftphdr *tftp; + + /* buffer is only set if we are handling TFTP */ + if (buffer =3D=3D NULL ) + return 0; + +#ifndef __DEBUG__ + print_progress(0, received_len); +#endif + udph =3D (struct udphdr *) pkt; + tftp =3D (struct tftphdr *) ((void *) udph + sizeof(struct udphdr)); + set_timer(TICKS_SEC); + +#ifdef __DEBUG__ + dump_package(pkt, packetsize); +#endif + + port_number =3D udph->uh_sport; + if (tftp->th_opcode =3D=3D htons(OACK)) { + /* an OACK means that the server answers our blocksize request */ + blocksize =3D get_blksize(pkt, packetsize); + if (!blocksize || blocksize > MAX_BLOCKSIZE) { + send_error(fd, 8, port_number); + tftp_errno =3D -8; + goto error; + } + send_ack(fd, 0, port_number); + } else if (tftp->th_opcode =3D=3D htons(ACK)) { + /* an ACK means that the server did not answers + * our blocksize request, therefore we will set the blocksize + * to the default value of 512 */ + blocksize =3D 512; + send_ack(fd, 0, port_number); + } else if ((unsigned char) tftp->th_opcode =3D=3D ERROR) { +#ifdef __DEBUG__ + printf("tftp->th_opcode : %x\n", tftp->th_opcode); + printf("tftp->th_data : %x\n", tftp->th_data); +#endif + switch ( (uint8_t) tftp->th_data) { + case ENOTFOUND: + tftp_errno =3D -3; // ERROR: file not found + break; + case EACCESS: + tftp_errno =3D -4; // ERROR: access violation + break; + case EBADOP: + tftp_errno =3D -5; // ERROR: illegal TFTP operation + break; + case EBADID: + tftp_errno =3D -6; // ERROR: unknown transfer ID + break; + case ENOUSER: + tftp_errno =3D -7; // ERROR: no such user + break; + default: + tftp_errno =3D -1; // ERROR: unknown error + } + goto error; + } else if (tftp->th_opcode =3D=3D DATA) { + /* DATA PACKAGE */ + if (block + 1 =3D=3D tftp->th_data) { + ++block; + } + else if( block =3D=3D 0xffff && huge_load !=3D 0 + && (tftp->th_data =3D=3D 0 || tftp->th_data =3D=3D 1) ) { + block =3D tftp->th_data; + } + else if (tftp->th_data =3D=3D block) { +#ifdef __DEBUG__ + printf + ("\nTFTP: Received block %x, expected block was %x\n", + tftp->th_data, block + 1); + printf("\b+ "); +#endif + send_ack(fd, tftp->th_data, port_number); + lost_packets++; + tftp_err->bad_tftp_packets++; + return 0; + } else if (tftp->th_data < block) { +#ifdef __DEBUG__ + printf + ("\nTFTP: Received block %x, expected block was %x\n", + tftp->th_data, block + 1); + printf("\b* "); +#endif + /* This means that an old data packet appears (again); + * this happens sometimes if we don't answer fast enough + * and a timeout is generated on the server side; + * as we already have this packet we just ignore it */ + tftp_err->bad_tftp_packets++; + return 0; + } else { + tftp_err->blocks_missed =3D block + 1; + tftp_err->blocks_received =3D tftp->th_data; + tftp_errno =3D -42; + goto error; + } + tftp_err->bad_tftp_packets =3D 0; + /* check if our buffer is large enough */ + if (received_len + udph->uh_ulen - 12 > len) { + tftp_errno =3D -2; + goto error; + } + memcpy(buffer + received_len, &tftp->th_data + 1, + udph->uh_ulen - 12); + send_ack(fd, tftp->th_data, port_number); + received_len +=3D udph->uh_ulen - 12; + /* Last packet reached if the payload of the UDP packet + * is smaller than blocksize + 12 + * 12 =3D UDP header (8) + 4 bytes TFTP payload */ + if (udph->uh_ulen < blocksize + 12) { + tftp_finished =3D 1; + return 0; + } + /* 0xffff is the highest block number possible + * see the TFTP RFCs */ + + if (block >=3D 0xffff && huge_load =3D=3D 0) { + tftp_errno =3D -9; + goto error; + } + } else { +#ifdef __DEBUG__ + printf("Unknown packet %x\n", tftp->th_opcode); + printf("\b# "); +#endif + tftp_err->bad_tftp_packets++; + return 0; + } + + return 0; + +error: +#ifdef __DEBUG__ + printf("\nTFTP errno: %d\n", tftp_errno); +#endif + tftp_finished =3D 1; + return tftp_errno; +} + +/** + * TFTP: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending TFTP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + */ +void handle_tftp_dun(uint8_t err_code) +{ + tftp_errno =3D - err_code - 10; + tftp_finished =3D 1; +} + +/** + * TFTP: Interface function to load files via TFTP. + * + * @param _fn_ip contains the following configuration information: + * client IP, TFTP-server IP, filename to be loaded + * @param _buffer destination buffer for the file + * @param _len size of destination buffer + * @param _retries max number of retries + * @param _tftp_err contains info about TFTP-errors (e.g. lost packet= s) + * @param _mode NON ZERO - multicast, ZERO - unicast + * @param _blocksize blocksize for DATA-packets + * @return ZERO - error condition occurs + * NON ZERO - size of received file + */ +int tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len, + unsigned int _retries, tftp_err_t * _tftp_err, + int32_t _mode, int32_t _blocksize, int _ip_version) +{ + retries =3D _retries; + fn_ip =3D _fn_ip; + len =3D _len; + huge_load =3D _mode; + ip_version =3D _ip_version; + tftp_errno =3D 0; + tftp_err =3D _tftp_err; + tftp_err->bad_tftp_packets =3D 0; + tftp_err->no_packets =3D 0; + + block =3D 0; + received_len =3D 0; + tftp_finished =3D 0; + lost_packets =3D 0; + port_number =3D -1; + progress_first =3D -1; + progress_last_bytes =3D 0; + + /* Default blocksize must be 512 for TFTP servers + * which do not support the RRQ blocksize option */ + blocksize =3D 512; + + /* Preferred blocksize - used as option for the read request */ + if (_blocksize < 8) + _blocksize =3D 8; + else if (_blocksize > MAX_BLOCKSIZE) + _blocksize =3D MAX_BLOCKSIZE; + sprintf(blocksize_str, "%d", _blocksize); + + printf(" Receiving data: "); + print_progress(-1, 0); + + // Setting buffer to a non-zero address enabled handling of received TFTP= packets. + buffer =3D _buffer; + + set_timer(TICKS_SEC); + send_rrq(fn_ip->fd); + + while (! tftp_finished) { + /* if timeout (no packet received) */ + if(get_timer() <=3D 0) { + /* the server doesn't seem to retry let's help out a bit */ + if (tftp_err->no_packets > 4 && port_number !=3D -1 + && block > 1) { + send_ack(fn_ip->fd, block, port_number); + } + else if (port_number =3D=3D -1 && block =3D=3D 0 + && (tftp_err->no_packets&3) =3D=3D 3) { + printf("\nRepeating TFTP read request...\n"); + send_rrq(fn_ip->fd); + } + tftp_err->no_packets++; + set_timer(TICKS_SEC); + } + + /* handle received packets */ + receive_ether(fn_ip->fd); + + /* bad_tftp_packets are counted whenever we receive a TFTP packet + * which was not expected; if this gets larger than 'retries' + * we just exit */ + if (tftp_err->bad_tftp_packets > retries) { + tftp_errno =3D -40; + break; + } + + /* no_packets counts the times we have returned from receive_ether() + * without any packet received; if this gets larger than 'retries' + * we also just exit */ + if (tftp_err->no_packets > retries) { + tftp_errno =3D -41; + break; + } + } + + // Setting buffer to NULL disables handling of received TFTP packets. + buffer =3D NULL; + + if (tftp_errno) + return tftp_errno; + + print_progress(-1, received_len); + printf("\n"); + if (lost_packets) + printf("Lost ACK packets: %d\n", lost_packets); + + return received_len; +} diff --git a/pc-bios/s390-ccw/libnet/tftp.h b/pc-bios/s390-ccw/libnet/tftp.h new file mode 100644 index 0000000..303feaf --- /dev/null +++ b/pc-bios/s390-ccw/libnet/tftp.h @@ -0,0 +1,52 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + + +#ifndef _TFTP_H_ +#define _TFTP_H_ + +#include +#include "ipv6.h" + +struct tftphdr { + int16_t th_opcode; + uint16_t th_data; +}; + +struct filename_ip { + uint32_t own_ip; + ip6_addr_t own_ip6; + uint32_t server_ip; + ip6_addr_t server_ip6; + ip6_addr_t dns_ip6; + int8_t filename[256]; + int fd; +} __attribute__ ((packed)); +typedef struct filename_ip filename_ip_t; + +typedef struct { + uint32_t bad_tftp_packets; + uint32_t no_packets; + uint32_t blocks_missed; + uint32_t blocks_received; +} tftp_err_t; + +int tftp(filename_ip_t *, unsigned char *, int, unsigned int, + tftp_err_t *, int32_t mode, int32_t blocksize, int ip_version); +int tftp_netsave(filename_ip_t *, uint8_t * buffer, int len, + int use_ci, unsigned int retries, tftp_err_t * tftp_err); + +int32_t handle_tftp(int fd, uint8_t *, int32_t); +void handle_tftp_dun(uint8_t err_code); +int parse_tftp_args(char buffer[], char *server_ip, char filename[], int f= d, int len); + +#endif diff --git a/pc-bios/s390-ccw/libnet/time.h b/pc-bios/s390-ccw/libnet/time.h new file mode 100644 index 0000000..fcd5cd5 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/time.h @@ -0,0 +1,6 @@ + +extern void set_timer(int); +extern int get_timer(void); +extern int get_sec_ticks(void); + +#define TICKS_SEC get_sec_ticks() diff --git a/pc-bios/s390-ccw/libnet/udp.c b/pc-bios/s390-ccw/libnet/udp.c new file mode 100644 index 0000000..d6982ea --- /dev/null +++ b/pc-bios/s390-ccw/libnet/udp.c @@ -0,0 +1,115 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +/************************ DEFINITIONS & DECLARATIONS *********************/ + +#include +#include +#include +#include +#include +#include + + +/****************************** IMPLEMENTATION ***************************/ + + +/** + * NET: Handles UDP-packets according to Receive-handle diagram. + * + * @param udp_packet UDP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see udphdr + */ +int8_t handle_udp(int fd, uint8_t * udp_packet, uint32_t packetsize) +{ + struct udphdr * udph =3D (struct udphdr *) udp_packet; + + if (packetsize < sizeof(struct udphdr)) + return -1; // packet is too small + + switch (htons(udph -> uh_dport)) { + case UDPPORT_BOOTPC: + if (udph -> uh_sport =3D=3D htons(UDPPORT_BOOTPS)) + return handle_dhcp(fd, udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else + return -1; + case UDPPORT_DNSC: + if (udph -> uh_sport =3D=3D htons(UDPPORT_DNSS)) + return handle_dns(udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else + return -1; + case UDPPORT_DHCPV6C: + return handle_dhcpv6(udp_packet+sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + case UDPPORT_TFTPC: + return handle_tftp(fd, udp_packet, packetsize); + default: + return -1; + } +} + +/** + * NET: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending UDP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + * @param packet original UDP-packet + * @param packetsize length of the packet + * @see handle_icmp + */ +void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err= _code) +{ + struct udphdr * udph =3D (struct udphdr *) udp_packet; + + if (packetsize < sizeof(struct udphdr)) + return; // packet is too small + + switch (htons(udph -> uh_sport)) { + case UDPPORT_TFTPC: + handle_tftp_dun(err_code); + break; + } +} + +/** + * NET: Creates UDP-packet. Places UDP-header in a packet and fills it + * with corresponding information. + *

+ * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_iphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where UDP-header must be placed. + * @param packetsize Size of the packet in bytes incl. this hdr and data. + * @param src_port UDP source port + * @param dest_port UDP destination port + * @see udphdr + * @see fill_ethhdr + * @see fill_iphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void fill_udphdr(uint8_t * packet, uint16_t packetsize, + uint16_t src_port, uint16_t dest_port) +{ + struct udphdr * udph =3D (struct udphdr *) packet; + + udph -> uh_sport =3D htons(src_port); + udph -> uh_dport =3D htons(dest_port); + udph -> uh_ulen =3D htons(packetsize); + udph -> uh_sum =3D htons(0); +} diff --git a/pc-bios/s390-ccw/libnet/udp.h b/pc-bios/s390-ccw/libnet/udp.h new file mode 100644 index 0000000..e716e04 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/udp.h @@ -0,0 +1,53 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +#ifndef _UDP_H +#define _UDP_H + +#include + +#define IPTYPE_UDP 17 + +#define UDPPORT_BOOTPS 67 /**< UDP port of BootP/DHCP-server */ +#define UDPPORT_BOOTPC 68 /**< UDP port of BootP/DHCP-client */ +#define UDPPORT_DNSS 53 /**< UDP port of DNS-server */ +#define UDPPORT_DNSC 32769 /**< UDP port of DNS-client */ +#define UDPPORT_TFTPC 2001 /**< UDP port of TFTP-client */ +#define UDPPORT_DHCPV6C 546 /**< UDP port of DHCPv6-client */ + +/** \struct udphdr + * A header for UDP-packets. + * For more information see RFC 768. + */ +struct udphdr { + uint16_t uh_sport; /**< Source port */ + uint16_t uh_dport; /**< Destinantion port */ + uint16_t uh_ulen; /**< Length in octets, incl. this header and data */ + uint16_t uh_sum; /**< Checksum */ +}; +typedef struct udphdr udp_hdr_t; + +typedef int32_t *(*handle_upper_udp_t)(uint8_t *, int32_t); +typedef void *(*handle_upper_udp_dun_t)(uint8_t); + +/* Handles UDP-packets that are detected by any network layer. */ +extern int8_t handle_udp(int fd, uint8_t * udp_packet, uint32_t packetsize= ); + +/* Handles UDP related ICMP-Dest.Unreachable packets that are detected by + * the network layers. */ +extern void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint= 8_t err_code); + +/* fills udp header */ +extern void fill_udphdr(uint8_t *packet, uint16_t packetsize, + uint16_t src_port, uint16_t dest_port); + +#endif --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564331358735.4960692227319; Tue, 27 Jun 2017 04:52:11 -0700 (PDT) Received: from localhost ([::1]:51853 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp2Q-0002J4-4W for importer@patchew.org; Tue, 27 Jun 2017 07:52:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54813) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPoz6-00084f-4z for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPoz3-0003mf-08 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:44 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54086) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPoz2-0003lk-QT for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:40 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C49B13DBC8; Tue, 27 Jun 2017 11:48:39 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id E352153CF7; Tue, 27 Jun 2017 11:48:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com C49B13DBC8 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com C49B13DBC8 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:12 +0200 Message-Id: <1498564100-10045-7-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 27 Jun 2017 11:48:40 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 06/14] libnet: Remove remainders of netsave code X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The code does not exist in the repository, so it does not make sense to keep the prototypes and the Forth wrapper around. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libnet/netapps.h | 1 - pc-bios/s390-ccw/libnet/tftp.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/pc-bios/s390-ccw/libnet/netapps.h b/pc-bios/s390-ccw/libnet/ne= tapps.h index 91c1ebd..2fea4a7 100644 --- a/pc-bios/s390-ccw/libnet/netapps.h +++ b/pc-bios/s390-ccw/libnet/netapps.h @@ -20,7 +20,6 @@ struct filename_ip; =20 extern int netload(char *buffer, int len, char *ret_buffer, int huge_load, int block_size, char *args_fs, int alen); -extern int netsave(int argc, char *argv[]); extern int ping(char *args_fs, int alen); extern int dhcp(char *ret_buffer, struct filename_ip *fn_ip, unsigned int retries, int flags); diff --git a/pc-bios/s390-ccw/libnet/tftp.h b/pc-bios/s390-ccw/libnet/tftp.h index 303feaf..b1dbc21 100644 --- a/pc-bios/s390-ccw/libnet/tftp.h +++ b/pc-bios/s390-ccw/libnet/tftp.h @@ -42,8 +42,6 @@ typedef struct { =20 int tftp(filename_ip_t *, unsigned char *, int, unsigned int, tftp_err_t *, int32_t mode, int32_t blocksize, int ip_version); -int tftp_netsave(filename_ip_t *, uint8_t * buffer, int len, - int use_ci, unsigned int retries, tftp_err_t * tftp_err); =20 int32_t handle_tftp(int fd, uint8_t *, int32_t); void handle_tftp_dun(uint8_t err_code); --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564539514714.2156228266361; Tue, 27 Jun 2017 04:55:39 -0700 (PDT) Received: from localhost ([::1]:51873 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp5m-0005LY-4t for importer@patchew.org; Tue, 27 Jun 2017 07:55:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54868) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozA-00087h-QF for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPoz9-0003q4-DJ for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:48 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57322) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPoz9-0003pi-4A for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:47 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0F95B5AFC8; Tue, 27 Jun 2017 11:48:46 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 30BA617DE7; Tue, 27 Jun 2017 11:48:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 0F95B5AFC8 Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 0F95B5AFC8 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:13 +0200 Message-Id: <1498564100-10045-8-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 27 Jun 2017 11:48:46 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 07/14] libnet: Rework error message printing X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" There is a repetive pattern of code in netload.c to print out error message: snprintf(buf, ...) + bootmsg_error() + write_mm_log(). The code can be simplified / shortened quite a bit by consolidating this pattern in a helper function. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libnet/netload.c | 126 +++++++++++++---------------------= ---- 1 file changed, 44 insertions(+), 82 deletions(-) diff --git a/pc-bios/s390-ccw/libnet/netload.c b/pc-bios/s390-ccw/libnet/ne= tload.c index cd3720a..8afe341 100644 --- a/pc-bios/s390-ccw/libnet/netload.c +++ b/pc-bios/s390-ccw/libnet/netload.c @@ -52,6 +52,23 @@ typedef struct { int tftp_retries; } obp_tftp_args_t; =20 +/** + * Print error with preceeding error code + */ +static void netload_error(int errcode, const char *format, ...) +{ + va_list vargs; + char buf[256]; + + sprintf(buf, "E%04X: (net) ", errcode); + + va_start(vargs, format); + vsnprintf(&buf[13], sizeof(buf) - 13, format, vargs); + va_end(vargs); + + bootmsg_error(errcode, &buf[7]); + write_mm_log(buf, strlen(buf), 0x91); +} =20 /** * Parses a argument string for IPv6 booting, extracts all @@ -389,7 +406,6 @@ static void seed_rng(uint8_t mac[]) int netload(char *buffer, int len, char *ret_buffer, int huge_load, int block_size, char *args_fs, int alen) { - char buf[256]; int rc; filename_ip_t fn_ip; int fd_device; @@ -427,17 +443,11 @@ int netload(char *buffer, int len, char *ret_buffer, = int huge_load, } =20 if (fd_device =3D=3D -1) { - strcpy(buf,"E3000: (net) Could not read MAC address"); - bootmsg_error(0x3000, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3000, "Could not read MAC address"); return -100; } else if (fd_device =3D=3D -2) { - strcpy(buf,"E3006: (net) Could not initialize network device"); - bootmsg_error(0x3006, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3006, "Could not initialize network device"); return -101; } =20 @@ -567,10 +577,7 @@ int netload(char *buffer, int len, char *ret_buffer, i= nt huge_load, memcpy(&fn_ip.server_ip6.addr, &obp_tftp_args.si6addr.addr, 16); } if (rc =3D=3D -1) { - strcpy(buf,"E3001: (net) Could not get IP address"); - bootmsg_error(0x3001, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3001, "Could not get IP address"); close(fn_ip.fd); return -101; } @@ -586,29 +593,21 @@ int netload(char *buffer, int len, char *ret_buffer, = int huge_load, } =20 if (rc =3D=3D -2) { - sprintf(buf, - "E3002: (net) ARP request to TFTP server " + netload_error(0x3002, "ARP request to TFTP server " "(%d.%d.%d.%d) failed", ((fn_ip.server_ip >> 24) & 0xFF), ((fn_ip.server_ip >> 16) & 0xFF), ((fn_ip.server_ip >> 8) & 0xFF), ( fn_ip.server_ip & 0xFF)); - bootmsg_error(0x3002, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); close(fn_ip.fd); return -102; } if (rc =3D=3D -4 || rc =3D=3D -3) { - strcpy(buf,"E3008: (net) Can't obtain TFTP server IP address"); - bootmsg_error(0x3008, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3008, "Can't obtain TFTP server IP address"); close(fn_ip.fd); return -107; } =20 - /*********************************************************** * * Load file via TFTP into buffer provided by OpenFirmware @@ -649,114 +648,77 @@ int netload(char *buffer, int len, char *ret_buffer,= int huge_load, printf(" TFTP: Received %s (%d KBytes)\n", fn_ip.filename, rc / 1024); } else if (rc =3D=3D -1) { - bootmsg_error(0x3003, "(net) unknown TFTP error"); + netload_error(0x3003, "unknown TFTP error"); return -103; } else if (rc =3D=3D -2) { - sprintf(buf, - "E3004: (net) TFTP buffer of %d bytes " + netload_error(0x3004, "TFTP buffer of %d bytes " "is too small for %s", len, fn_ip.filename); - bootmsg_error(0x3004, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); return -104; } else if (rc =3D=3D -3) { - sprintf(buf,"E3009: (net) file not found: %s", - fn_ip.filename); - bootmsg_error(0x3009, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3009, "file not found: %s", + fn_ip.filename); return -108; } else if (rc =3D=3D -4) { - strcpy(buf,"E3010: (net) TFTP access violation"); - bootmsg_error(0x3010, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3010, "TFTP access violation"); return -109; } else if (rc =3D=3D -5) { - strcpy(buf,"E3011: (net) illegal TFTP operation"); - bootmsg_error(0x3011, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3011, "illegal TFTP operation"); return -110; } else if (rc =3D=3D -6) { - strcpy(buf, "E3012: (net) unknown TFTP transfer ID"); - bootmsg_error(0x3012, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3012, "unknown TFTP transfer ID"); return -111; } else if (rc =3D=3D -7) { - strcpy(buf, "E3013: (net) no such TFTP user"); - bootmsg_error(0x3013, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3013, "no such TFTP user"); return -112; } else if (rc =3D=3D -8) { - strcpy(buf, "E3017: (net) TFTP blocksize negotiation failed"); - bootmsg_error(0x3017, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3017, "TFTP blocksize negotiation failed"); return -116; } else if (rc =3D=3D -9) { - strcpy(buf,"E3018: (net) file exceeds maximum TFTP transfer size"); - bootmsg_error(0x3018, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3018, "file exceeds maximum TFTP transfer size"); return -117; } else if (rc <=3D -10 && rc >=3D -15) { - sprintf(buf,"E3005: (net) ICMP ERROR \""); + char *icmp_err_str; switch (rc) { case -ICMP_NET_UNREACHABLE - 10: - sprintf(buf+strlen(buf),"net unreachable"); + icmp_err_str =3D "net unreachable"; break; case -ICMP_HOST_UNREACHABLE - 10: - sprintf(buf+strlen(buf),"host unreachable"); + icmp_err_str =3D "host unreachable"; break; case -ICMP_PROTOCOL_UNREACHABLE - 10: - sprintf(buf+strlen(buf),"protocol unreachable"); + icmp_err_str =3D "protocol unreachable"; break; case -ICMP_PORT_UNREACHABLE - 10: - sprintf(buf+strlen(buf),"port unreachable"); + icmp_err_str =3D "port unreachable"; break; case -ICMP_FRAGMENTATION_NEEDED - 10: - sprintf(buf+strlen(buf),"fragmentation needed and DF set"); + icmp_err_str =3D "fragmentation needed and DF set"; break; case -ICMP_SOURCE_ROUTE_FAILED - 10: - sprintf(buf+strlen(buf),"source route failed"); + icmp_err_str =3D "source route failed"; break; default: - sprintf(buf+strlen(buf)," UNKNOWN"); + icmp_err_str =3D " UNKNOWN"; break; } - sprintf(buf+strlen(buf),"\""); - bootmsg_error(0x3005, &buf[7]); - - write_mm_log(buf, strlen(buf), 0x91); + netload_error(0x3005, "ICMP ERROR \"%s\"", icmp_err_str); return -105; } else if (rc =3D=3D -40) { - sprintf(buf, - "E3014: (net) TFTP error occurred after " + netload_error(0x3014, "TFTP error occurred after " "%d bad packets received", tftp_err.bad_tftp_packets); - bootmsg_error(0x3014, &buf[7]); - write_mm_log(buf, strlen(buf), 0x91); return -113; } else if (rc =3D=3D -41) { - sprintf(buf, - "E3015: (net) TFTP error occurred after " + netload_error(0x3015, "TFTP error occurred after " "missing %d responses", tftp_err.no_packets); - bootmsg_error(0x3015, &buf[7]); - write_mm_log(buf, strlen(buf), 0x91); return -114; } else if (rc =3D=3D -42) { - sprintf(buf, - "E3016: (net) TFTP error missing block %d, " + netload_error(0x3016, "TFTP error missing block %d, " "expected block was %d", tftp_err.blocks_missed, tftp_err.blocks_received); - bootmsg_error(0x3016, &buf[7]); - write_mm_log(buf, strlen(buf), 0x91); return -115; } return rc; --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564273785446.7022611199643; Tue, 27 Jun 2017 04:51:13 -0700 (PDT) Received: from localhost ([::1]:51851 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp1U-0001aB-8H for importer@patchew.org; Tue, 27 Jun 2017 07:51:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54901) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozD-0008A7-40 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPozB-0003sG-KT for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:51 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46440) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPozB-0003rn-C6 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:49 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4AC9F7F3E5; Tue, 27 Jun 2017 11:48:48 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 676F418EEE; Tue, 27 Jun 2017 11:48:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 4AC9F7F3E5 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 4AC9F7F3E5 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:14 +0200 Message-Id: <1498564100-10045-9-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 27 Jun 2017 11:48:48 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 08/14] libnet: Refactor some code of netload() into a separate function X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" netload() is a huge function, it's easy to lose track here. So let's refactor the TFTP-related loading and error printing code into a separate function instead. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libnet/netload.c | 177 ++++++++++++++++++++--------------= ---- 1 file changed, 93 insertions(+), 84 deletions(-) diff --git a/pc-bios/s390-ccw/libnet/netload.c b/pc-bios/s390-ccw/libnet/ne= tload.c index 8afe341..f872884 100644 --- a/pc-bios/s390-ccw/libnet/netload.c +++ b/pc-bios/s390-ccw/libnet/netload.c @@ -403,13 +403,101 @@ static void seed_rng(uint8_t mac[]) srand(seed); } =20 +static int tftp_load(filename_ip_t *fnip, unsigned char *buffer, int len, + unsigned int retries, int ip_vers) +{ + tftp_err_t tftp_err; + int rc; + + rc =3D tftp(fnip, buffer, len, retries, &tftp_err, 1, 1428, ip_vers); + + if (rc > 0) { + printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename, + rc / 1024); + } else if (rc =3D=3D -1) { + netload_error(0x3003, "unknown TFTP error"); + return -103; + } else if (rc =3D=3D -2) { + netload_error(0x3004, "TFTP buffer of %d bytes " + "is too small for %s", + len, fnip->filename); + return -104; + } else if (rc =3D=3D -3) { + netload_error(0x3009, "file not found: %s", + fnip->filename); + return -108; + } else if (rc =3D=3D -4) { + netload_error(0x3010, "TFTP access violation"); + return -109; + } else if (rc =3D=3D -5) { + netload_error(0x3011, "illegal TFTP operation"); + return -110; + } else if (rc =3D=3D -6) { + netload_error(0x3012, "unknown TFTP transfer ID"); + return -111; + } else if (rc =3D=3D -7) { + netload_error(0x3013, "no such TFTP user"); + return -112; + } else if (rc =3D=3D -8) { + netload_error(0x3017, "TFTP blocksize negotiation failed"); + return -116; + } else if (rc =3D=3D -9) { + netload_error(0x3018, "file exceeds maximum TFTP transfer size"); + return -117; + } else if (rc <=3D -10 && rc >=3D -15) { + char *icmp_err_str; + switch (rc) { + case -ICMP_NET_UNREACHABLE - 10: + icmp_err_str =3D "net unreachable"; + break; + case -ICMP_HOST_UNREACHABLE - 10: + icmp_err_str =3D "host unreachable"; + break; + case -ICMP_PROTOCOL_UNREACHABLE - 10: + icmp_err_str =3D "protocol unreachable"; + break; + case -ICMP_PORT_UNREACHABLE - 10: + icmp_err_str =3D "port unreachable"; + break; + case -ICMP_FRAGMENTATION_NEEDED - 10: + icmp_err_str =3D "fragmentation needed and DF set"; + break; + case -ICMP_SOURCE_ROUTE_FAILED - 10: + icmp_err_str =3D "source route failed"; + break; + default: + icmp_err_str =3D " UNKNOWN"; + break; + } + netload_error(0x3005, "ICMP ERROR \"%s\"", icmp_err_str); + return -105; + } else if (rc =3D=3D -40) { + netload_error(0x3014, "TFTP error occurred after " + "%d bad packets received", + tftp_err.bad_tftp_packets); + return -113; + } else if (rc =3D=3D -41) { + netload_error(0x3015, "TFTP error occurred after " + "missing %d responses", + tftp_err.no_packets); + return -114; + } else if (rc =3D=3D -42) { + netload_error(0x3016, "TFTP error missing block %d, " + "expected block was %d", + tftp_err.blocks_missed, + tftp_err.blocks_received); + return -115; + } + + return rc; +} + int netload(char *buffer, int len, char *ret_buffer, int huge_load, int block_size, char *args_fs, int alen) { int rc; filename_ip_t fn_ip; int fd_device; - tftp_err_t tftp_err; obp_tftp_args_t obp_tftp_args; char null_ip[4] =3D { 0x00, 0x00, 0x00, 0x00 }; char null_ip6[16] =3D { 0x00, 0x00, 0x00, 0x00, @@ -633,94 +721,15 @@ int netload(char *buffer, int len, char *ret_buffer, = int huge_load, printf("%s\n", ip6_str); } =20 - // accept at most 20 bad packets - // wait at most for 40 packets - rc =3D tftp(&fn_ip, (unsigned char *) buffer, - len, obp_tftp_args.tftp_retries, - &tftp_err, huge_load, block_size, ip_version); + /* Do the TFTP load and print error message if necessary */ + rc =3D tftp_load(&fn_ip, (unsigned char *)buffer, len, + obp_tftp_args.tftp_retries, ip_version); =20 - if(obp_tftp_args.ip_init =3D=3D IP_INIT_DHCP) + if (obp_tftp_args.ip_init =3D=3D IP_INIT_DHCP) dhcp_send_release(fn_ip.fd); =20 close(fn_ip.fd); =20 - if (rc > 0) { - printf(" TFTP: Received %s (%d KBytes)\n", fn_ip.filename, - rc / 1024); - } else if (rc =3D=3D -1) { - netload_error(0x3003, "unknown TFTP error"); - return -103; - } else if (rc =3D=3D -2) { - netload_error(0x3004, "TFTP buffer of %d bytes " - "is too small for %s", - len, fn_ip.filename); - return -104; - } else if (rc =3D=3D -3) { - netload_error(0x3009, "file not found: %s", - fn_ip.filename); - return -108; - } else if (rc =3D=3D -4) { - netload_error(0x3010, "TFTP access violation"); - return -109; - } else if (rc =3D=3D -5) { - netload_error(0x3011, "illegal TFTP operation"); - return -110; - } else if (rc =3D=3D -6) { - netload_error(0x3012, "unknown TFTP transfer ID"); - return -111; - } else if (rc =3D=3D -7) { - netload_error(0x3013, "no such TFTP user"); - return -112; - } else if (rc =3D=3D -8) { - netload_error(0x3017, "TFTP blocksize negotiation failed"); - return -116; - } else if (rc =3D=3D -9) { - netload_error(0x3018, "file exceeds maximum TFTP transfer size"); - return -117; - } else if (rc <=3D -10 && rc >=3D -15) { - char *icmp_err_str; - switch (rc) { - case -ICMP_NET_UNREACHABLE - 10: - icmp_err_str =3D "net unreachable"; - break; - case -ICMP_HOST_UNREACHABLE - 10: - icmp_err_str =3D "host unreachable"; - break; - case -ICMP_PROTOCOL_UNREACHABLE - 10: - icmp_err_str =3D "protocol unreachable"; - break; - case -ICMP_PORT_UNREACHABLE - 10: - icmp_err_str =3D "port unreachable"; - break; - case -ICMP_FRAGMENTATION_NEEDED - 10: - icmp_err_str =3D "fragmentation needed and DF set"; - break; - case -ICMP_SOURCE_ROUTE_FAILED - 10: - icmp_err_str =3D "source route failed"; - break; - default: - icmp_err_str =3D " UNKNOWN"; - break; - } - netload_error(0x3005, "ICMP ERROR \"%s\"", icmp_err_str); - return -105; - } else if (rc =3D=3D -40) { - netload_error(0x3014, "TFTP error occurred after " - "%d bad packets received", - tftp_err.bad_tftp_packets); - return -113; - } else if (rc =3D=3D -41) { - netload_error(0x3015, "TFTP error occurred after " - "missing %d responses", - tftp_err.no_packets); - return -114; - } else if (rc =3D=3D -42) { - netload_error(0x3016, "TFTP error missing block %d, " - "expected block was %d", - tftp_err.blocks_missed, - tftp_err.blocks_received); - return -115; - } return rc; } =20 --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564721665915.20059748961; Tue, 27 Jun 2017 04:58:41 -0700 (PDT) Received: from localhost ([::1]:51884 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp8i-0007s6-DG for importer@patchew.org; Tue, 27 Jun 2017 07:58:40 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54962) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozI-0008Fm-5s for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPozE-0003tX-Gq for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:56 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57456) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPozE-0003t5-8O for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:52 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2B66B61BAA; Tue, 27 Jun 2017 11:48:51 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id A4C2060600; Tue, 27 Jun 2017 11:48:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 2B66B61BAA Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 2B66B61BAA From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:15 +0200 Message-Id: <1498564100-10045-10-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 27 Jun 2017 11:48:51 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 09/14] pc-bios/s390-ccw: Make the basic libnet code compilable X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Adjust the Makefiles, remove non-required code and fix some spots that generated compiler warnings / errors with the s390-ccw firmware CFLAGS. Signed-off-by: Thomas Huth --- configure | 3 +- pc-bios/s390-ccw/Makefile | 6 +- pc-bios/s390-ccw/libnet/Makefile | 38 ++--- pc-bios/s390-ccw/libnet/netapps.h | 4 +- pc-bios/s390-ccw/libnet/netload.c | 319 ++--------------------------------= ---- pc-bios/s390-ccw/libnet/tftp.c | 2 +- 6 files changed, 33 insertions(+), 339 deletions(-) diff --git a/configure b/configure index 954c286..0ac761e 100755 --- a/configure +++ b/configure @@ -6378,7 +6378,7 @@ fi DIRS=3D"tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/q= api-schema tests/tcg/xtensa tests/qemu-iotests" DIRS=3D"$DIRS docs docs/interop fsdev" DIRS=3D"$DIRS pc-bios/optionrom pc-bios/spapr-rtas" -DIRS=3D"$DIRS pc-bios/s390-ccw pc-bios/s390-ccw/libc" +DIRS=3D"$DIRS pc-bios/s390-ccw pc-bios/s390-ccw/libc pc-bios/s390-ccw/libn= et" DIRS=3D"$DIRS roms/seabios roms/vgabios" DIRS=3D"$DIRS qapi-generated" FILES=3D"Makefile tests/tcg/Makefile qdict-test-data.txt" @@ -6387,6 +6387,7 @@ FILES=3D"$FILES tests/tcg/lm32/Makefile tests/tcg/xte= nsa/Makefile po/Makefile" FILES=3D"$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES=3D"$FILES pc-bios/spapr-rtas/Makefile" FILES=3D"$FILES pc-bios/s390-ccw/Makefile pc-bios/s390-ccw/libc/Makefile" +FILES=3D"$FILES pc-bios/s390-ccw/libnet/Makefile" FILES=3D"$FILES roms/seabios/Makefile roms/vgabios/Makefile" FILES=3D"$FILES pc-bios/qemu-icon.bmp" FILES=3D"$FILES .gdbinit scripts" # scripts needed by relative path in .gd= binit diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 8fbefe8..02b9b08 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -7,7 +7,7 @@ include $(SRC_PATH)/rules.mak =20 $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) =20 -.PHONY : all clean build-all libc.a +.PHONY : all clean build-all libc.a libnet.a =20 OBJECTS =3D start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o OBJECTS +=3D libc.a sbrk.o @@ -26,6 +26,9 @@ s390-ccw.elf: $(OBJECTS) libc.a: @$(MAKE) -C libc V=3D"$(V)" =20 +libnet.a: + @$(MAKE) -C libnet V=3D"$(V)" + STRIP ?=3D strip =20 s390-ccw.img: s390-ccw.elf @@ -36,3 +39,4 @@ $(OBJECTS): Makefile clean: rm -f *.o *.d *.img *.elf *~ @$(MAKE) -C libc clean + @$(MAKE) -C libnet clean diff --git a/pc-bios/s390-ccw/libnet/Makefile b/pc-bios/s390-ccw/libnet/Mak= efile index 83ac1e5..72e12d7 100644 --- a/pc-bios/s390-ccw/libnet/Makefile +++ b/pc-bios/s390-ccw/libnet/Makefile @@ -10,16 +10,21 @@ # * IBM Corporation - initial implementation # ************************************************************************= ****/ =20 -ifndef TOP - TOP =3D $(shell while ! test -e make.rules; do cd .. ; done; pwd) - export TOP -endif -include $(TOP)/make.rules +include ../../../config-host.mak +include $(SRC_PATH)/rules.mak =20 -CFLAGS +=3D -I. -I.. -I../libc/include -I$(TOP)/include +$(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw/libnet) =20 -SRCS =3D ethernet.c ipv4.c udp.c tcp.c dns.c bootp.c dhcp.c tftp.c \ - ipv6.c dhcpv6.c icmpv6.c ndp.c netload.c ping.c args.c +QEMU_CFLAGS :=3D $(filter -W%, $(QEMU_CFLAGS)) +QEMU_CFLAGS +=3D -ffreestanding -fno-delete-null-pointer-checks -msoft-flo= at +QEMU_CFLAGS +=3D -march=3Dz900 -fPIE -fno-strict-aliasing -Wno-redundant-d= ecls +QEMU_CFLAGS +=3D -I$(SRC_PATH)/pc-bios/s390-ccw/libnet +QEMU_CFLAGS +=3D -I$(SRC_PATH)/pc-bios/s390-ccw/libc/include +QEMU_CFLAGS +=3D $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector) +LDFLAGS +=3D -Wl,-pie -nostdlib + +SRCS =3D ethernet.c ipv4.c udp.c tcp.c dns.c dhcp.c tftp.c \ + ipv6.c dhcpv6.c icmpv6.c ndp.c netload.c args.c =20 OBJS =3D $(SRCS:%.c=3D%.o) =20 @@ -28,23 +33,10 @@ TARGET =3D ../libnet.a all: $(TARGET) =20 $(TARGET): $(OBJS) - $(AR) -rc $@ $(OBJS) - $(RANLIB) $@ + $(call quiet-command,$(AR) -rc $@ $(OBJS),"AR","$(TARGET_DIR)$@") =20 clean: - $(RM) $(TARGET) $(OBJS) + rm -f $(TARGET) $(OBJS) =20 distclean: clean - $(RM) Makefile.dep - - -# Rules for creating the dependency file: -depend: - $(RM) Makefile.dep - $(MAKE) Makefile.dep - -Makefile.dep: Makefile - $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep =20 -# Include dependency file if available: --include Makefile.dep diff --git a/pc-bios/s390-ccw/libnet/netapps.h b/pc-bios/s390-ccw/libnet/ne= tapps.h index 2fea4a7..d2283af 100644 --- a/pc-bios/s390-ccw/libnet/netapps.h +++ b/pc-bios/s390-ccw/libnet/netapps.h @@ -18,9 +18,7 @@ =20 struct filename_ip; =20 -extern int netload(char *buffer, int len, char *ret_buffer, int huge_load, - int block_size, char *args_fs, int alen); -extern int ping(char *args_fs, int alen); +extern int netload(char *buffer, int len, char *ret_buffer); extern int dhcp(char *ret_buffer, struct filename_ip *fn_ip, unsigned int retries, int flags); =20 diff --git a/pc-bios/s390-ccw/libnet/netload.c b/pc-bios/s390-ccw/libnet/ne= tload.c index f872884..eae8333 100644 --- a/pc-bios/s390-ccw/libnet/netload.c +++ b/pc-bios/s390-ccw/libnet/netload.c @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include "args.h" #include "netapps.h" =20 @@ -66,266 +64,7 @@ static void netload_error(int errcode, const char *form= at, ...) vsnprintf(&buf[13], sizeof(buf) - 13, format, vargs); va_end(vargs); =20 - bootmsg_error(errcode, &buf[7]); - write_mm_log(buf, strlen(buf), 0x91); -} - -/** - * Parses a argument string for IPv6 booting, extracts all - * parameters and fills a structure accordingly - * - * @param arg_str string with arguments, separated with ',' - * @param argc number of arguments - * @param obp_tftp_args structure which contains the result - * @return updated arg_str - */ -static const char *=20 -parse_ipv6args (const char *arg_str, unsigned int argc, - obp_tftp_args_t *obp_tftp_args) -{ - char *ptr =3D NULL; - char arg_buf[100]; - - // find out siaddr - if (argc =3D=3D 0) - memset(&obp_tftp_args->si6addr.addr, 0, 16); - else { - argncpy(arg_str, 0, arg_buf, 100); - if(str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) { - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(arg_buf[0] =3D=3D 0) { - memset(&obp_tftp_args->si6addr.addr, 0, 16); - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else - memset(&obp_tftp_args->si6addr.addr, 0, 16); - } - - // find out filename - if (argc =3D=3D 0) - obp_tftp_args->filename[0] =3D 0; - else { - argncpy(arg_str, 0, obp_tftp_args->filename, 100); - for(ptr =3D obp_tftp_args->filename; *ptr !=3D 0; ++ptr) - if(*ptr =3D=3D '\\') { - *ptr =3D '/'; - } - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - - // find out ciaddr - if (argc =3D=3D 0) - memset(&obp_tftp_args->ci6addr, 0, 16); - else { - argncpy(arg_str, 0, arg_buf, 100); - if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr[0])))= { - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(arg_buf[0] =3D=3D 0) { - memset(&obp_tftp_args->ci6addr.addr, 0, 16); - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else - memset(&obp_tftp_args->ci6addr.addr, 0, 16); - } - - // find out giaddr - if (argc =3D=3D 0) - memset(&obp_tftp_args->gi6addr, 0, 16); - else { - argncpy(arg_str, 0, arg_buf, 100); - if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) { - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(arg_buf[0] =3D=3D 0) { - memset(&obp_tftp_args->gi6addr, 0, 16); - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else - memset(&obp_tftp_args->gi6addr.addr, 0, 16); - } - - return arg_str; -} - - -/** - * Parses a argument string for IPv4 booting, extracts all - * parameters and fills a structure accordingly - * - * @param arg_str string with arguments, separated with ',' - * @param argc number of arguments - * @param obp_tftp_args structure which contains the result - * @return updated arg_str - */ -static const char *=20 -parse_ipv4args (const char *arg_str, unsigned int argc, - obp_tftp_args_t *obp_tftp_args) -{ - char *ptr =3D NULL; - char arg_buf[100]; - - // find out siaddr - if(argc=3D=3D0) { - memset(obp_tftp_args->siaddr, 0, 4); - } else { - argncpy(arg_str, 0, arg_buf, 100); - if(strtoip(arg_buf, obp_tftp_args->siaddr)) { - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(arg_buf[0] =3D=3D 0) { - memset(obp_tftp_args->siaddr, 0, 4); - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else - memset(obp_tftp_args->siaddr, 0, 4); - } - - // find out filename - if(argc=3D=3D0) - obp_tftp_args->filename[0] =3D 0; - else { - argncpy(arg_str, 0, obp_tftp_args->filename, 100); - for(ptr =3D obp_tftp_args->filename; *ptr !=3D 0; ++ptr) - if(*ptr =3D=3D '\\') - *ptr =3D '/'; - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - - // find out ciaddr - if(argc=3D=3D0) - memset(obp_tftp_args->ciaddr, 0, 4); - else { - argncpy(arg_str, 0, arg_buf, 100); - if(strtoip(arg_buf, obp_tftp_args->ciaddr)) { - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(arg_buf[0] =3D=3D 0) { - memset(obp_tftp_args->ciaddr, 0, 4); - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else - memset(obp_tftp_args->ciaddr, 0, 4); - } - - // find out giaddr - if(argc=3D=3D0) - memset(obp_tftp_args->giaddr, 0, 4); - else { - argncpy(arg_str, 0, arg_buf, 100); - if(strtoip(arg_buf, obp_tftp_args->giaddr)) { - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(arg_buf[0] =3D=3D 0) { - memset(obp_tftp_args->giaddr, 0, 4); - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else - memset(obp_tftp_args->giaddr, 0, 4); - } - - return arg_str; -} - -/** - * Parses a argument string which is given by netload, extracts all - * parameters and fills a structure according to this - * - * Netload-Parameters: - * [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries - * - * @param arg_str string with arguments, separated with ',' - * @param obp_tftp_args structure which contains the result - * @return none - */ -static void -parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args) -{ - unsigned int argc; - char arg_buf[100]; - - memset(obp_tftp_args, 0, sizeof(*obp_tftp_args)); - - argc =3D get_args_count(arg_str); - - // find out if we should use BOOTP or DHCP - if(argc=3D=3D0) - obp_tftp_args->ip_init =3D IP_INIT_DEFAULT; - else { - argncpy(arg_str, 0, arg_buf, 100); - if (strcasecmp(arg_buf, "bootp") =3D=3D 0) { - obp_tftp_args->ip_init =3D IP_INIT_BOOTP; - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(strcasecmp(arg_buf, "dhcp") =3D=3D 0) { - obp_tftp_args->ip_init =3D IP_INIT_DHCP; - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - else if(strcasecmp(arg_buf, "ipv6") =3D=3D 0) { - obp_tftp_args->ip_init =3D IP_INIT_DHCPV6_STATELESS; - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - ip_version =3D 6; - } - else - obp_tftp_args->ip_init =3D IP_INIT_DEFAULT; - } - - if (ip_version =3D=3D 4) { - arg_str =3D parse_ipv4args (arg_str, argc, obp_tftp_args); - } - else if (ip_version =3D=3D 6) { - arg_str =3D parse_ipv6args (arg_str, argc, obp_tftp_args); - } - - // find out bootp-retries - if (argc =3D=3D 0) - obp_tftp_args->bootp_retries =3D DEFAULT_BOOT_RETRIES; - else { - argncpy(arg_str, 0, arg_buf, 100); - if(arg_buf[0] =3D=3D 0) - obp_tftp_args->bootp_retries =3D DEFAULT_BOOT_RETRIES; - else { - obp_tftp_args->bootp_retries =3D strtol(arg_buf, 0, 10); - if(obp_tftp_args->bootp_retries < 0) - obp_tftp_args->bootp_retries =3D DEFAULT_BOOT_RETRIES; - } - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } - - // find out tftp-retries - if (argc =3D=3D 0) - obp_tftp_args->tftp_retries =3D DEFAULT_TFTP_RETRIES; - else { - argncpy(arg_str, 0, arg_buf, 100); - if(arg_buf[0] =3D=3D 0) - obp_tftp_args->tftp_retries =3D DEFAULT_TFTP_RETRIES; - else { - obp_tftp_args->tftp_retries =3D strtol(arg_buf, 0, 10); - if(obp_tftp_args->tftp_retries < 0) - obp_tftp_args->tftp_retries =3D DEFAULT_TFTP_RETRIES; - } - arg_str =3D get_arg_ptr(arg_str, 1); - --argc; - } + puts(buf); } =20 /** @@ -361,10 +100,6 @@ int dhcp(char *ret_buffer, struct filename_ip *fn_ip, = unsigned int retries, =20 do { printf("\b\b\b%03d", i-1); - if (getchar() =3D=3D 27) { - printf("\nAborted\n"); - return -1; - } if (!--i) { printf("\nGiving up after %d DHCP requests\n", retries); return -1; @@ -396,9 +131,9 @@ int dhcp(char *ret_buffer, struct filename_ip *fn_ip, u= nsigned int retries, */ static void seed_rng(uint8_t mac[]) { - unsigned int seed; + uint64_t seed; =20 - asm volatile("mftbl %0" : "=3Dr"(seed)); + asm volatile(" stck %0 " : : "Q"(seed) : "memory"); seed ^=3D (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; srand(seed); } @@ -445,7 +180,7 @@ static int tftp_load(filename_ip_t *fnip, unsigned char= *buffer, int len, netload_error(0x3018, "file exceeds maximum TFTP transfer size"); return -117; } else if (rc <=3D -10 && rc >=3D -15) { - char *icmp_err_str; + const char *icmp_err_str; switch (rc) { case -ICMP_NET_UNREACHABLE - 10: icmp_err_str =3D "net unreachable"; @@ -492,8 +227,7 @@ static int tftp_load(filename_ip_t *fnip, unsigned char= *buffer, int len, return rc; } =20 -int netload(char *buffer, int len, char *ret_buffer, int huge_load, - int block_size, char *args_fs, int alen) +int netload(char *buffer, int len, char *ret_buffer) { int rc; filename_ip_t fn_ip; @@ -524,10 +258,6 @@ int netload(char *buffer, int len, char *ret_buffer, i= nt huge_load, fd_device =3D socket(0, 0, 0, (char*) own_mac); if(fd_device !=3D -2) break; - if(getchar() =3D=3D 27) { - fd_device =3D -2; - break; - } } =20 if (fd_device =3D=3D -1) { @@ -551,27 +281,10 @@ int netload(char *buffer, int len, char *ret_buffer, = int huge_load, =20 seed_rng(own_mac); =20 - if (alen > 0) { - char args[256]; - if (alen > sizeof(args) - 1) { - puts("ERROR: Parameter string is too long."); - return -7; - } - /* Convert forth string into NUL-terminated C-string */ - strncpy(args, args_fs, alen); - args[alen] =3D 0; - parse_args(args, &obp_tftp_args); - if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES) - obp_tftp_args.bootp_retries =3D DEFAULT_BOOT_RETRIES; - else - obp_tftp_args.bootp_retries -=3D rc; - } - else { - memset(&obp_tftp_args, 0, sizeof(obp_tftp_args_t)); - obp_tftp_args.ip_init =3D IP_INIT_DEFAULT; - obp_tftp_args.bootp_retries =3D DEFAULT_BOOT_RETRIES; - obp_tftp_args.tftp_retries =3D DEFAULT_TFTP_RETRIES; - } + memset(&obp_tftp_args, 0, sizeof(obp_tftp_args_t)); + obp_tftp_args.ip_init =3D IP_INIT_DEFAULT; + obp_tftp_args.bootp_retries =3D DEFAULT_BOOT_RETRIES; + obp_tftp_args.tftp_retries =3D DEFAULT_TFTP_RETRIES; memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4); =20 // reset of error code @@ -602,20 +315,6 @@ int netload(char *buffer, int len, char *ret_buffer, i= nt huge_load, =20 // construction of fn_ip from parameter switch(obp_tftp_args.ip_init) { - case IP_INIT_BOOTP: - // if giaddr in not specified, then we have to identify - // the BOOTP server via broadcasts - if(memcmp(obp_tftp_args.giaddr, null_ip, 4) =3D=3D 0) { - // don't do this, when using DHCP !!! - fn_ip.server_ip =3D 0xFFFFFFFF; - } - // if giaddr is specified, then we have to use this - // IP address as proxy to identify the BOOTP server - else { - memcpy(&fn_ip.server_ip, obp_tftp_args.giaddr, 4); - } - rc =3D bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); - break; case IP_INIT_DHCP: rc =3D dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, F_IPV4); break; diff --git a/pc-bios/s390-ccw/libnet/tftp.c b/pc-bios/s390-ccw/libnet/tftp.c index d0c2f13..34f448c 100644 --- a/pc-bios/s390-ccw/libnet/tftp.c +++ b/pc-bios/s390-ccw/libnet/tftp.c @@ -265,7 +265,7 @@ static void print_progress(int urgent, int received_byt= es) sprintf(buffer, "%d KBytes", (progress_last_bytes >> 10)); for(ptr =3D buffer; *ptr !=3D 0; ++ptr) *ptr =3D '\b'; - printf(buffer); + printf("%s", buffer); } printf("%d KBytes", (received_bytes >> 10)); i =3D 1; --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 14985646371602.8211471038797526; Tue, 27 Jun 2017 04:57:17 -0700 (PDT) Received: from localhost ([::1]:51877 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp7L-0006MO-Hj for importer@patchew.org; Tue, 27 Jun 2017 07:57:15 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54961) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozI-0008Fl-5i for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPozG-0003w2-NZ for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:56 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44054) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPozG-0003vk-HV for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:54 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 80EC18047F; Tue, 27 Jun 2017 11:48:53 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8465B17DE7; Tue, 27 Jun 2017 11:48:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 80EC18047F Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 80EC18047F From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:16 +0200 Message-Id: <1498564100-10045-11-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 27 Jun 2017 11:48:53 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 10/14] pc-bios/s390-ccw: Add timer code for the libnet X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The libnet expects certain timer functions to exist, so that it is able to deal with timeouts etc. This patch implements these timer functions via the STORE CLOCK (stck) CPU instruction. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libnet/Makefile | 2 +- pc-bios/s390-ccw/libnet/timer.c | 40 ++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 pc-bios/s390-ccw/libnet/timer.c diff --git a/pc-bios/s390-ccw/libnet/Makefile b/pc-bios/s390-ccw/libnet/Mak= efile index 72e12d7..c8235f3 100644 --- a/pc-bios/s390-ccw/libnet/Makefile +++ b/pc-bios/s390-ccw/libnet/Makefile @@ -24,7 +24,7 @@ QEMU_CFLAGS +=3D $(call cc-option, $(QEMU_CFLAGS), -fno-s= tack-protector) LDFLAGS +=3D -Wl,-pie -nostdlib =20 SRCS =3D ethernet.c ipv4.c udp.c tcp.c dns.c dhcp.c tftp.c \ - ipv6.c dhcpv6.c icmpv6.c ndp.c netload.c args.c + ipv6.c dhcpv6.c icmpv6.c ndp.c netload.c args.c timer.c =20 OBJS =3D $(SRCS:%.c=3D%.o) =20 diff --git a/pc-bios/s390-ccw/libnet/timer.c b/pc-bios/s390-ccw/libnet/time= r.c new file mode 100644 index 0000000..ddbd7a2 --- /dev/null +++ b/pc-bios/s390-ccw/libnet/timer.c @@ -0,0 +1,40 @@ +/* + * Timer functions for libnet + * + * Copyright 2017 Thomas Huth, Red Hat Inc. + * + * This code 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 2 of the License, or (at your + * option) any later version. + */ + +#include +#include "time.h" + +static uint64_t dest_timer; + +static uint64_t get_timer_ms(void) +{ + uint64_t clk; + + asm volatile(" stck %0 " : : "Q"(clk) : "memory"); + + /* Bit 51 is incrememented each microsecond */ + return (clk >> (63 - 51)) / 1000; +} + +void set_timer(int val) +{ + dest_timer =3D get_timer_ms() + val; +} + +int get_timer(void) +{ + return dest_timer - get_timer_ms(); +} + +int get_sec_ticks(void) +{ + return 1000; /* number of ticks in 1 second */ +} --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564795239533.408441151923; Tue, 27 Jun 2017 04:59:55 -0700 (PDT) Received: from localhost ([::1]:51888 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp9t-0008Up-OS for importer@patchew.org; Tue, 27 Jun 2017 07:59:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54994) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozK-0008IR-Ot for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPozJ-0003wf-Au for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:58 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54416) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPozJ-0003wU-2W for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:57 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id F121F3F723; Tue, 27 Jun 2017 11:48:55 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id DB0AC53CE3; Tue, 27 Jun 2017 11:48:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com F121F3F723 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com F121F3F723 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:17 +0200 Message-Id: <1498564100-10045-12-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 27 Jun 2017 11:48:56 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 11/14] pc-bios/s390-ccw: Add virtio-net driver code X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This virtio-net driver contains the recv() and send() functions that are required by libnet to receive and send packets. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/Makefile | 2 +- pc-bios/s390-ccw/virtio-net.c | 125 ++++++++++++++++++++++++++++++++++++++= ++++ pc-bios/s390-ccw/virtio.c | 16 ++++-- pc-bios/s390-ccw/virtio.h | 11 ++++ 4 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 pc-bios/s390-ccw/virtio-net.c diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 02b9b08..369bd65 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) =20 .PHONY : all clean build-all libc.a libnet.a =20 -OBJECTS =3D start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o +OBJECTS =3D start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o virtio-= net.o OBJECTS +=3D libc.a sbrk.o QEMU_CFLAGS :=3D $(filter -W%, $(QEMU_CFLAGS)) QEMU_CFLAGS +=3D -ffreestanding -fno-delete-null-pointer-checks -msoft-flo= at diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c new file mode 100644 index 0000000..5c2f439 --- /dev/null +++ b/pc-bios/s390-ccw/virtio-net.c @@ -0,0 +1,125 @@ +/* + * Virtio-net driver for the s390-ccw firmware + * + * Copyright 2017 Thomas Huth, Red Hat Inc. + * + * This code 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 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include "libnet/ethernet.h" +#include "virtio.h" + +#define VQ_RX 0 /* Receive queue */ +#define VQ_TX 1 /* Transmit queue */ + +struct VirtioNetHdr { + uint8_t flags; + uint8_t gso_type; + uint16_t hdr_len; + uint16_t gso_size; + uint16_t csum_start; + uint16_t csum_offset; + /*uint16_t num_buffers;*/ /* Only with VIRTIO_NET_F_MRG_RXBUF or VIRTI= O1 */ +}; +typedef struct VirtioNetHdr VirtioNetHdr; + +static uint16_t rx_last_idx; /* Last index in receive queue "used" ring */ + +int socket(int domain, int type, int proto, char *mac_addr) +{ + VDev *vdev =3D virtio_get_device(); + VRing *rxvq =3D &vdev->vrings[VQ_RX]; + void *buf; + int i; + + memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN); + + for (i =3D 0; i < 64; i++) { + buf =3D malloc(ETH_MTU_SIZE + sizeof(VirtioNetHdr)); + IPL_assert(buf !=3D NULL, "Can not allocate memory for receive buf= fers"); + vring_send_buf(rxvq, buf, ETH_MTU_SIZE + sizeof(VirtioNetHdr), + VRING_DESC_F_WRITE); + } + vring_notify(rxvq); + + return 0; +} + +int send(int fd, const void *buf, int len, int flags) +{ + VirtioNetHdr tx_hdr; + VDev *vdev =3D virtio_get_device(); + VRing *txvq =3D &vdev->vrings[VQ_TX]; + + /* Set up header - we do not use anything special, so simply clear it = */ + memset(&tx_hdr, 0, sizeof(tx_hdr)); + + vring_send_buf(txvq, &tx_hdr, sizeof(tx_hdr), VRING_DESC_F_NEXT); + vring_send_buf(txvq, (void *)buf, len, VRING_HIDDEN_IS_CHAIN); + while (!vr_poll(txvq)) { + yield(); + } + if (drain_irqs(txvq->schid)) { + puts("send: drain irqs failed"); + return -1; + } + + return len; +} + +int recv(int fd, void *buf, int maxlen, int flags) +{ + VDev *vdev =3D virtio_get_device(); + VRing *rxvq =3D &vdev->vrings[VQ_RX]; + int len, id; + uint8_t *pkt; + + if (rx_last_idx =3D=3D rxvq->used->idx) { + return 0; + } + + len =3D rxvq->used->ring[rx_last_idx % rxvq->num].len - sizeof(VirtioN= etHdr); + if (len > maxlen) { + puts("virtio-net: Receive buffer too small"); + len =3D maxlen; + } + id =3D rxvq->used->ring[rx_last_idx % rxvq->num].id % rxvq->num; + pkt =3D (uint8_t *)(rxvq->desc[id].addr + sizeof(VirtioNetHdr)); + +#if 0 + /* Dump packet */ + printf("\nbuf %p: len=3D%i\n", (void*)rxvq->desc[id].addr, len); + int i; + for (i =3D 0; i < 64; i++) { + printf(" %02x", pkt[i]); + if ((i%16)=3D=3D15) + printf("\n"); + } + printf("\n"); +#endif + + /* Copy data to destination buffer */ + memcpy(buf, pkt, len); + + /* Mark buffer as available to the host again */ + rxvq->avail->ring[rxvq->avail->idx % rxvq->num] =3D id; + rxvq->avail->idx =3D rxvq->avail->idx + 1; + vring_notify(rxvq); + + /* Move index to next entry */ + rx_last_idx =3D rx_last_idx + 1; + + return len; +} + +int close(int fd) +{ + return 0; +} diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 6ee93d5..b5219aa 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -69,7 +69,7 @@ static long virtio_notify(SubChannelId schid, int vq_idx,= long cookie) * Virtio functions * ***********************************************/ =20 -static int drain_irqs(SubChannelId schid) +int drain_irqs(SubChannelId schid) { Irb irb =3D {}; int r =3D 0; @@ -148,13 +148,13 @@ static void vring_init(VRing *vr, VqInfo *info) debug_print_addr("init vr", vr); } =20 -static bool vring_notify(VRing *vr) +bool vring_notify(VRing *vr) { vr->cookie =3D virtio_notify(vr->schid, vr->id, vr->cookie); return vr->cookie >=3D 0; } =20 -static void vring_send_buf(VRing *vr, void *p, int len, int flags) +void vring_send_buf(VRing *vr, void *p, int len, int flags) { /* For follow-up chains we need to keep the first entry point */ if (!(flags & VRING_HIDDEN_IS_CHAIN)) { @@ -187,7 +187,7 @@ ulong get_second(void) return (get_clock() >> 12) / 1000000; } =20 -static int vr_poll(VRing *vr) +int vr_poll(VRing *vr) { if (vr->used->idx =3D=3D vr->used_idx) { vring_notify(vr); @@ -495,6 +495,11 @@ static void virtio_setup_ccw(VDev *vdev) run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); =20 switch (vdev->senseid.cu_model) { + case VIRTIO_ID_NET: + vdev->nr_vqs =3D 3; + vdev->cmd_vr_idx =3D 0; + cfg_size =3D sizeof(vdev->config.net); + break; case VIRTIO_ID_BLOCK: vdev->nr_vqs =3D 1; vdev->cmd_vr_idx =3D 0; @@ -549,6 +554,9 @@ void virtio_setup_device(SubChannelId schid) virtio_setup_ccw(&vdev); =20 switch (vdev.senseid.cu_model) { + case VIRTIO_ID_NET: + sclp_print("Using virtio-net.\n"); + break; case VIRTIO_ID_BLOCK: sclp_print("Using virtio-blk.\n"); if (!virtio_ipl_disk_is_valid()) { diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index 1eaf865..b4e0f41 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -254,6 +254,12 @@ struct ScsiDevice { }; typedef struct ScsiDevice ScsiDevice; =20 +struct VirtioNetConfig { + uint8_t mac[6]; + uint16_t status; +}; +typedef struct VirtioNetConfig VirtioNetConfig; + struct VDev { int nr_vqs; VRing *vrings; @@ -266,6 +272,7 @@ struct VDev { union { VirtioBlkConfig blk; VirtioScsiConfig scsi; + VirtioNetConfig net; } config; ScsiDevice *scsi_device; bool is_cdrom; @@ -291,6 +298,10 @@ struct VirtioCmd { }; typedef struct VirtioCmd VirtioCmd; =20 +bool vring_notify(VRing *vr); +int drain_irqs(SubChannelId schid); +void vring_send_buf(VRing *vr, void *p, int len, int flags); +int vr_poll(VRing *vr); int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd); =20 #endif /* VIRTIO_H */ --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564873631844.327222628149; Tue, 27 Jun 2017 05:01:13 -0700 (PDT) Received: from localhost ([::1]:52041 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPpBA-00013b-CP for importer@patchew.org; Tue, 27 Jun 2017 08:01:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55027) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozM-0008Mv-Lu for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPozL-0003xz-HU for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:00 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58175) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPozL-0003xG-9S for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:48:59 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 39456FEF02; Tue, 27 Jun 2017 11:48:58 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5663560600; Tue, 27 Jun 2017 11:48:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 39456FEF02 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 39456FEF02 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:18 +0200 Message-Id: <1498564100-10045-13-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 27 Jun 2017 11:48:58 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 12/14] pc-bios/s390-ccw: Load file via an intermediate .INS file X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We need to know which files have to be loaded at which address. Normally you need at least two files, a kernel image and an initrd image. Since the normal DHCP information only provides one file, we now load an intermediate .INS file first which has to contain the information about the other files. The .INS file has the same syntax as the .INS files that are already used on s390x Linux distribution CD-ROMs: First line is the title (starting with "* "), and in the following lines you can find the file names followed by the address where they should be loaded. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libnet/netapps.h | 2 +- pc-bios/s390-ccw/libnet/netload.c | 72 +++++++++++++++++++++++++++++++++++= +--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/pc-bios/s390-ccw/libnet/netapps.h b/pc-bios/s390-ccw/libnet/ne= tapps.h index d2283af..61e8a11 100644 --- a/pc-bios/s390-ccw/libnet/netapps.h +++ b/pc-bios/s390-ccw/libnet/netapps.h @@ -18,7 +18,7 @@ =20 struct filename_ip; =20 -extern int netload(char *buffer, int len, char *ret_buffer); +extern int netload(void); extern int dhcp(char *ret_buffer, struct filename_ip *fn_ip, unsigned int retries, int flags); =20 diff --git a/pc-bios/s390-ccw/libnet/netload.c b/pc-bios/s390-ccw/libnet/ne= tload.c index eae8333..28e8711 100644 --- a/pc-bios/s390-ccw/libnet/netload.c +++ b/pc-bios/s390-ccw/libnet/netload.c @@ -26,6 +26,8 @@ #include "args.h" #include "netapps.h" =20 +#define MAX_INS_FILE_LEN 16384 + #define IP_INIT_DEFAULT 5 #define IP_INIT_NONE 0 #define IP_INIT_BOOTP 1 @@ -138,7 +140,7 @@ static void seed_rng(uint8_t mac[]) srand(seed); } =20 -static int tftp_load(filename_ip_t *fnip, unsigned char *buffer, int len, +static int tftp_load(filename_ip_t *fnip, void *buffer, int len, unsigned int retries, int ip_vers) { tftp_err_t tftp_err; @@ -227,7 +229,56 @@ static int tftp_load(filename_ip_t *fnip, unsigned cha= r *buffer, int len, return rc; } =20 -int netload(char *buffer, int len, char *ret_buffer) +static int load_from_ins_file(char *insbuf, filename_ip_t *fn_ip, int retr= ies, + int ip_version) +{ + char *ptr; + int rc =3D -1, llen; + void *destaddr; + + ptr =3D strchr(insbuf, '\n'); + + if (!ptr || insbuf[0] !=3D '*' || insbuf[1] !=3D ' ') { + puts("Does not seem to be a valid .INS file"); + return -1; + } + + *ptr =3D 0; + printf("\nParsing .INS file:\n %s\n", &insbuf[2]); + + insbuf =3D ptr + 1; + while (*insbuf) { + ptr =3D strchr(insbuf, '\n'); + if (ptr) { + *ptr =3D 0; + } + llen =3D strlen(insbuf); + if (!llen) { + insbuf =3D ptr + 1; + continue; + } + ptr =3D strchr(insbuf, ' '); + if (!ptr) { + puts("Missing space separator in .INS file"); + return -1; + } + *ptr =3D 0; + strncpy((char *)fn_ip->filename, insbuf, + sizeof(fn_ip->filename)); + destaddr =3D (char *)atol(ptr + 1); + printf("\n Loading file \"%s\" via TFTP to %p\n", insbuf, + destaddr); + rc =3D tftp_load(fn_ip, destaddr, 50000000, retries, ip_version); + if (rc <=3D 0) { + break; + } + insbuf +=3D llen + 1; + } + + return rc; +} + +int netload(void) { int rc; filename_ip_t fn_ip; @@ -239,6 +290,7 @@ int netload(char *buffer, int len, char *ret_buffer) 0x00, 0x00, 0x00, 0x00,=20 0x00, 0x00, 0x00, 0x00 }; uint8_t own_mac[6]; + char *ins_buf, *ret_buffer =3D NULL; =20 puts("\n Initializing NIC"); memset(&fn_ip, 0, sizeof(filename_ip_t)); @@ -420,9 +472,19 @@ int netload(char *buffer, int len, char *ret_buffer) printf("%s\n", ip6_str); } =20 - /* Do the TFTP load and print error message if necessary */ - rc =3D tftp_load(&fn_ip, (unsigned char *)buffer, len, - obp_tftp_args.tftp_retries, ip_version); + ins_buf =3D malloc(MAX_INS_FILE_LEN); + if (!ins_buf) { + puts("Failed to allocate memory for the .INS file"); + return -1; + } + memset(ins_buf, 0, MAX_INS_FILE_LEN); + rc =3D tftp_load(&fn_ip, ins_buf, MAX_INS_FILE_LEN - 1, + obp_tftp_args.tftp_retries, ip_version); + if (rc > 0) { + rc =3D load_from_ins_file(ins_buf, &fn_ip, + obp_tftp_args.tftp_retries, ip_version); + } + free(ins_buf); =20 if (obp_tftp_args.ip_init =3D=3D IP_INIT_DHCP) dhcp_send_release(fn_ip.fd); --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564549933411.23332129982725; Tue, 27 Jun 2017 04:55:49 -0700 (PDT) Received: from localhost ([::1]:51874 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPp5w-0005RF-0S for importer@patchew.org; Tue, 27 Jun 2017 07:55:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55101) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozU-0008S0-D7 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPozP-0003zU-JF for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:08 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37558) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPozP-0003zG-D5 for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:03 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 52061C056788; Tue, 27 Jun 2017 11:49:02 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id 93F9753CE3; Tue, 27 Jun 2017 11:48:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 52061C056788 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 52061C056788 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:19 +0200 Message-Id: <1498564100-10045-14-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 27 Jun 2017 11:49:02 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 13/14] pc-bios/s390-ccw: Allow loading to address 0 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Kernels are normally loaded to address 0, so the check for NULL in the TFTP code has to be replaced. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/libnet/tftp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pc-bios/s390-ccw/libnet/tftp.c b/pc-bios/s390-ccw/libnet/tftp.c index 34f448c..108092b 100644 --- a/pc-bios/s390-ccw/libnet/tftp.c +++ b/pc-bios/s390-ccw/libnet/tftp.c @@ -26,6 +26,7 @@ =20 #define MAX_BLOCKSIZE 1428 #define BUFFER_LEN 256 +#define INVALID_BUFFER ((void *)-1L) =20 #define ENOTFOUND 1 #define EACCESS 2 @@ -45,7 +46,7 @@ =20 /* Local variables */ static unsigned char packet[BUFFER_LEN]; -static unsigned char *buffer =3D NULL; +static unsigned char *buffer =3D INVALID_BUFFER; static unsigned short block; static unsigned short blocksize; static char blocksize_str[6]; /* Blocksize string for read request */ @@ -337,7 +338,7 @@ int32_t handle_tftp(int fd, uint8_t *pkt, int32_t packe= tsize) struct tftphdr *tftp; =20 /* buffer is only set if we are handling TFTP */ - if (buffer =3D=3D NULL ) + if (buffer =3D=3D INVALID_BUFFER) return 0; =20 #ifndef __DEBUG__ @@ -536,7 +537,7 @@ int tftp(filename_ip_t * _fn_ip, unsigned char *_buffer= , int _len, printf(" Receiving data: "); print_progress(-1, 0); =20 - // Setting buffer to a non-zero address enabled handling of received TFTP= packets. + /* Set buffer to a valid address, enables handling of received packets */ buffer =3D _buffer; =20 set_timer(TICKS_SEC); @@ -579,8 +580,8 @@ int tftp(filename_ip_t * _fn_ip, unsigned char *_buffer= , int _len, } } =20 - // Setting buffer to NULL disables handling of received TFTP packets. - buffer =3D NULL; + /* Setting buffer invalid to disable handling of received packets */ + buffer =3D INVALID_BUFFER; =20 if (tftp_errno) return tftp_errno; --=20 1.8.3.1 From nobody Sat Apr 27 06:25:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498564946523339.28677471454375; Tue, 27 Jun 2017 05:02:26 -0700 (PDT) Received: from localhost ([::1]:52052 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPpCF-0001dj-Ok for importer@patchew.org; Tue, 27 Jun 2017 08:02:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55103) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dPozU-0008S1-DF for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dPozR-00040s-TQ for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:08 -0400 Received: from mx1.redhat.com ([209.132.183.28]:47152) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dPozR-00040L-Lj for qemu-devel@nongnu.org; Tue, 27 Jun 2017 07:49:05 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8F0027F3E4; Tue, 27 Jun 2017 11:49:04 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-48.ams2.redhat.com [10.36.116.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id ABADF17F2C; Tue, 27 Jun 2017 11:49:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8F0027F3E4 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 8F0027F3E4 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Tue, 27 Jun 2017 13:48:20 +0200 Message-Id: <1498564100-10045-15-git-send-email-thuth@redhat.com> In-Reply-To: <1498564100-10045-1-git-send-email-thuth@redhat.com> References: <1498564100-10045-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 27 Jun 2017 11:49:04 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 14/14] pc-bios/s390-ccw: Wire up the netload code X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Farman , Farhan Ali , Alexander Graf , Jens Freimann , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Link the libnet.a to the s390-ccw.elf file, call netload() instead of the external network boot image, and jump to loaded kernel at address 0, so that we can finally do a full network boot with the s390-ccw firmware now. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/Makefile | 2 +- pc-bios/s390-ccw/bootmap.c | 10 +++++++++- pc-bios/s390-ccw/main.c | 3 +-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 369bd65..827d7be 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -10,7 +10,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) .PHONY : all clean build-all libc.a libnet.a =20 OBJECTS =3D start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o virtio-= net.o -OBJECTS +=3D libc.a sbrk.o +OBJECTS +=3D libnet.a libc.a sbrk.o QEMU_CFLAGS :=3D $(filter -W%, $(QEMU_CFLAGS)) QEMU_CFLAGS +=3D -ffreestanding -fno-delete-null-pointer-checks -msoft-flo= at QEMU_CFLAGS +=3D -march=3Dz900 -fPIE -fno-strict-aliasing diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 523fa78..32befda 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -11,6 +11,7 @@ #include "s390-ccw.h" #include "bootmap.h" #include "virtio.h" +#include "libnet/netapps.h" =20 #ifdef DEBUG /* #define DEBUG_FALLBACK */ @@ -744,7 +745,14 @@ void zipl_load(void) } =20 if (virtio_get_device_type() =3D=3D VIRTIO_ID_NET) { - jump_to_IPL_code(vdev->netboot_start_addr); + long len; + + len =3D netload(); + if (len < 0) { + panic("Network loading failed"); + } + sclp_print("Netload done, starting kernel...\n"); + asm volatile (" lpsw 0(%0) " : : "r"(0) : "memory"); } =20 ipl_scsi(); diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 1cacc1b..b058e1b 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -150,12 +150,11 @@ static void virtio_setup(void) =20 IPL_assert(found, "No virtio device found"); =20 + virtio_setup_device(blk_schid); if (virtio_get_device_type() =3D=3D VIRTIO_ID_NET) { sclp_print("Network boot device detected\n"); vdev->netboot_start_addr =3D iplb.ccw.netboot_start_addr; } else { - virtio_setup_device(blk_schid); - IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detect= ed"); } } --=20 1.8.3.1