diff options
Diffstat (limited to 'firmware')
378 files changed, 89006 insertions, 0 deletions
diff --git a/firmware/README b/firmware/README new file mode 100644 index 000000000..a010493c8 --- /dev/null +++ b/firmware/README @@ -0,0 +1,4 @@ +This is a placeholder for the firmware code (microblaze and 8051). + +The layout should have a common library of source and header files. +Each usrp-like will have its own device-specific libs and apps. diff --git a/firmware/fx2/.gitignore b/firmware/fx2/.gitignore new file mode 100644 index 000000000..e9fd37231 --- /dev/null +++ b/firmware/fx2/.gitignore @@ -0,0 +1,2 @@ +/build +*.sym diff --git a/firmware/fx2/AUTHORS b/firmware/fx2/AUTHORS new file mode 100644 index 000000000..c9cd35778 --- /dev/null +++ b/firmware/fx2/AUTHORS @@ -0,0 +1,4 @@ +Eric Blossom <eb@comsec.org> +Josh Blum <josh@joshknows.com> +Thomas Tsou <ttsou@vt.edu> +Nick Foster <nick@nerdnetworks.org> diff --git a/firmware/fx2/CMakeLists.txt b/firmware/fx2/CMakeLists.txt new file mode 100644 index 000000000..80f16363f --- /dev/null +++ b/firmware/fx2/CMakeLists.txt @@ -0,0 +1,47 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/config/Toolchain-sdcc.cmake) +PROJECT(USRP1 C) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/config/") +INCLUDE(FindPythonInterp) + +######################################################################## +# Set toolchain to use SDCC +######################################################################## +# we're doing mixed ASM and C +ENABLE_LANGUAGE(ASM_SDCC) + +######################################################################## +# C flags and linking flags +######################################################################## +ADD_DEFINITIONS(-DHAVE_USRP2) +set(CMAKE_C_LINK_FLAGS "--code-loc 0x0000 --code-size 0x1800 --xram-loc 0x1800 --xram-size 0x0800 -Wl '-b USBDESCSEG = 0xE000'") +set(CMAKE_C_FLAGS "--no-xinit-opt") + +######################################################################## +# Setup precompile tools +######################################################################## +set(REG_GENERATOR ${CMAKE_SOURCE_DIR}/utils/generate_regs.py) +set(EDIT_GPIF_USRP1 ${CMAKE_SOURCE_DIR}/utils/edit-gpif.py) +set(BUILD_EEPROM ${CMAKE_SOURCE_DIR}/utils/build_eeprom.py) + +######################################################################## +# Add the subdirectories +######################################################################## +ADD_SUBDIRECTORY(usrp1) diff --git a/firmware/fx2/common/.gitignore b/firmware/fx2/common/.gitignore new file mode 100644 index 000000000..04f253234 --- /dev/null +++ b/firmware/fx2/common/.gitignore @@ -0,0 +1,18 @@ +/*.ihx +/*.lnk +/*.lst +/*.map +/*.mem +/*.rel +/*.rst +/*.sym +/blink_leds.asm +/usrp_common.asm +/command_loop.asm +/fpga.asm +/*.asm +/usrp_gpif.c +/usrp_gpif_inline.h +/*.lib +/Makefile +/Makefile.in diff --git a/firmware/fx2/common/_startup.a51 b/firmware/fx2/common/_startup.a51 new file mode 100644 index 000000000..30a907857 --- /dev/null +++ b/firmware/fx2/common/_startup.a51 @@ -0,0 +1,80 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003,2004 Free Software Foundation, Inc. +;;;  +;;; This file is part of GNU Radio +;;;  +;;; GNU Radio 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 3, or (at your option) +;;; any later version. +;;;  +;;; GNU Radio is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +;;; GNU General Public License for more details. +;;;  +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Radio; see the file COPYING.  If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. + +     +;;; The default external memory initialization provided by sdcc is not +;;; appropriate to the FX2.  This is derived from the sdcc code, but uses  +;;; the FX2 specific _MPAGE sfr. + + +	;; .area XISEG   (XDATA)  ; the initialized external data area +	;; .area XINIT   (CODE)	  ; the code space consts to init XISEG +	.area XSEG    (XDATA)	  ; zero initialized xdata +	.area USBDESCSEG (XDATA)  ; usb descriptors + +	 +	.area CSEG    (CODE) + +	;; sfr that sets upper address byte of MOVX using @r0 or @r1 +	_MPAGE	=	0x0092 + +__sdcc_external_startup:: +	;; This system is now compiled with the --no-xinit-opt  +	;; which means that any initialized XDATA is handled +	;; inline by code in the GSINIT segs emitted for each file. +	;;  +	;; We zero XSEG and all of the internal ram to ensure  +	;; a known good state for uninitialized variables. + +;	_mcs51_genRAMCLEAR() start +	mov	r0,#l_XSEG +	mov	a,r0 +	orl	a,#(l_XSEG >> 8) +	jz	00002$ +	mov	r1,#((l_XSEG + 255) >> 8) +	mov	dptr,#s_XSEG +	clr     a +	 +00001$:	movx	@dptr,a +	inc	dptr +	djnz	r0,00001$ +	djnz	r1,00001$ +	 +	;; We're about to clear internal memory.  This will overwrite +	;; the stack which contains our return address. +	;; Pop our return address into DPH, DPL +00002$:	pop	dph +	pop	dpl +	 +	;; R0 and A contain 0.  This loop will execute 256 times. +	;;  +	;; FWIW the first iteration writes direct address 0x00, +	;; which is the location of r0.  We get lucky, we're  +	;; writing the correct value (0) +	 +00003$:	mov	@r0,a +	djnz	r0,00003$ + +	push	dpl		; restore our return address +	push	dph + +	mov	dpl,#0		; indicate that data init is still required +	ret diff --git a/firmware/fx2/common/_startup.a51.brittle b/firmware/fx2/common/_startup.a51.brittle new file mode 100644 index 000000000..2996275cf --- /dev/null +++ b/firmware/fx2/common/_startup.a51.brittle @@ -0,0 +1,78 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003 Free Software Foundation, Inc. +;;;  +;;; This file is part of GNU Radio +;;;  +;;; GNU Radio 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 3, or (at your option) +;;; any later version. +;;;  +;;; GNU Radio is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +;;; GNU General Public License for more details. +;;;  +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Radio; see the file COPYING.  If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. + +     +;;; The default external memory initialization provided by sdcc is not +;;; appropriate to the FX2.  This is derived from the sdcc code, but uses  +;;; the FX2 specific _MPAGE sfr. + + +	.area XISEG   (XDATA)	; the initialized external data area +	.area XINIT   (CODE)	; the code space consts to init XISEG +	.area XSEG    (XDATA)	; zero initialized xdata +	.area USBDESCSEG (XDATA); usb descriptors + +	 +	;; BIG TIME KLUDGE! +	;; Look at usrp_main.rst and count the bytes from our +	;; "normal return location" to the first instruction following +	;; the comment:	"_mcs51_getRAMCLEAR () start" +	 +	INSTRUCTION_BYTES_TO_SKIP = 0x29	 ; valid for sdcc 2.4.0  +	 + +	.area CSEG    (CODE) + +	;; sfr that sets upper address byte of MOVX using @r0 or @r1 +	_MPAGE	=	0x0092 + +__sdcc_external_startup:: +;	_mcs51_genXINIT() start +	mov	r1,#l_XINIT +	mov	a,r1 +	orl	a,#(l_XINIT >> 8) +	jz	00003$ +	mov	r2,#((l_XINIT+255) >> 8) +	mov	dptr,#s_XINIT +	mov	r0,#s_XISEG +	mov	_MPAGE,#(s_XISEG >> 8) +00001$:	clr	a +	movc	a,@a+dptr +	movx	@r0,a +	inc	dptr +	inc	r0 +	cjne	r0,#0,00002$ +	inc	_MPAGE +00002$:	djnz	r1,00001$ +	djnz	r2,00001$ +	mov	_MPAGE,#0xFF +00003$: + +	;; Danger! Total KLUDGE! +	;; We pop the return address, add a magic number to it +	;; then jump to that address.  Believe it or not, this +	;; looks like the least kludgy way to handle this, +	;; short of patching the compiler... + +	pop	dph +	pop	dpl +	mov	a,#INSTRUCTION_BYTES_TO_SKIP +	jmp	@a+dptr diff --git a/firmware/fx2/common/delay.c b/firmware/fx2/common/delay.c new file mode 100644 index 000000000..13cf0eec8 --- /dev/null +++ b/firmware/fx2/common/delay.c @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * Delay approximately 1 microsecond (including overhead in udelay). + */ +static void +udelay1 (void) _naked +{ +  _asm				; lcall that got us here took 4 bus cycles +	ret			; 4 bus cycles +  _endasm; +} + +/* + * delay for approximately usecs microseconds + */ +void +udelay (unsigned char usecs) +{ +  do { +    udelay1 (); +  } while (--usecs != 0); +} + + +/* + * Delay approximately 1 millisecond. + * We're running at 48 MHz, so we need 48,000 clock cycles. + * + * Note however, that each bus cycle takes 4 clock cycles (not obvious, + * but explains the factor of 4 problem below). + */ +static void +mdelay1 (void) _naked +{ +  _asm +	mov	dptr,#(-1200 & 0xffff) +002$:	 +	inc	dptr		; 3 bus cycles +	mov	a, dpl		; 2 bus cycles +	orl	a, dph		; 2 bus cycles +	jnz	002$		; 3 bus cycles + +	ret +  _endasm; +} + +void +mdelay (unsigned int msecs) +{ +  do { +    mdelay1 (); +  } while (--msecs != 0); +} + +	 diff --git a/firmware/fx2/common/delay.h b/firmware/fx2/common/delay.h new file mode 100644 index 000000000..f5df779e1 --- /dev/null +++ b/firmware/fx2/common/delay.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _DELAY_H_ +#define _DELAY_H_ + +/* + * delay for approximately usecs microseconds + * Note limit of 255 usecs. + */ +void udelay (unsigned char usecs); + +/* + * delay for approximately msecs milliseconds + */ +void mdelay (unsigned short msecs); + + +#endif /* _DELAY_H_ */ diff --git a/firmware/fx2/common/eeprom_boot.a51 b/firmware/fx2/common/eeprom_boot.a51 new file mode 100644 index 000000000..65e452668 --- /dev/null +++ b/firmware/fx2/common/eeprom_boot.a51 @@ -0,0 +1,573 @@ +;-------------------------------------------------------- +; Hand tweaked minimal eeprom boot code +;-------------------------------------------------------- +	.module eeprom_boot +	.optsdcc -mmcs51 --model-small +	 +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- +	.globl _eeprom_init +	.globl _EP8FIFOBUF +	.globl _EP6FIFOBUF +	.globl _EP4FIFOBUF +	.globl _EP2FIFOBUF +	.globl _EP1INBUF +	.globl _EP1OUTBUF +	.globl _EP0BUF +	.globl _CT4 +	.globl _CT3 +	.globl _CT2 +	.globl _CT1 +	.globl _USBTEST +	.globl _TESTCFG +	.globl _DBUG +	.globl _UDMACRCQUAL +	.globl _UDMACRCL +	.globl _UDMACRCH +	.globl _GPIFHOLDAMOUNT +	.globl _FLOWSTBHPERIOD +	.globl _FLOWSTBEDGE +	.globl _FLOWSTB +	.globl _FLOWHOLDOFF +	.globl _FLOWEQ1CTL +	.globl _FLOWEQ0CTL +	.globl _FLOWLOGIC +	.globl _FLOWSTATE +	.globl _GPIFABORT +	.globl _GPIFREADYSTAT +	.globl _GPIFREADYCFG +	.globl _XGPIFSGLDATLNOX +	.globl _XGPIFSGLDATLX +	.globl _XGPIFSGLDATH +	.globl _EP8GPIFTRIG +	.globl _EP8GPIFPFSTOP +	.globl _EP8GPIFFLGSEL +	.globl _EP6GPIFTRIG +	.globl _EP6GPIFPFSTOP +	.globl _EP6GPIFFLGSEL +	.globl _EP4GPIFTRIG +	.globl _EP4GPIFPFSTOP +	.globl _EP4GPIFFLGSEL +	.globl _EP2GPIFTRIG +	.globl _EP2GPIFPFSTOP +	.globl _EP2GPIFFLGSEL +	.globl _GPIFTCB0 +	.globl _GPIFTCB1 +	.globl _GPIFTCB2 +	.globl _GPIFTCB3 +	.globl _GPIFADRL +	.globl _GPIFADRH +	.globl _GPIFCTLCFG +	.globl _GPIFIDLECTL +	.globl _GPIFIDLECS +	.globl _GPIFWFSELECT +	.globl _SETUPDAT +	.globl _SUDPTRCTL +	.globl _SUDPTRL +	.globl _SUDPTRH +	.globl _EP8FIFOBCL +	.globl _EP8FIFOBCH +	.globl _EP6FIFOBCL +	.globl _EP6FIFOBCH +	.globl _EP4FIFOBCL +	.globl _EP4FIFOBCH +	.globl _EP2FIFOBCL +	.globl _EP2FIFOBCH +	.globl _EP8FIFOFLGS +	.globl _EP6FIFOFLGS +	.globl _EP4FIFOFLGS +	.globl _EP2FIFOFLGS +	.globl _EP8CS +	.globl _EP6CS +	.globl _EP4CS +	.globl _EP2CS +	.globl _EP1INCS +	.globl _EP1OUTCS +	.globl _EP0CS +	.globl _EP8BCL +	.globl _EP8BCH +	.globl _EP6BCL +	.globl _EP6BCH +	.globl _EP4BCL +	.globl _EP4BCH +	.globl _EP2BCL +	.globl _EP2BCH +	.globl _EP1INBC +	.globl _EP1OUTBC +	.globl _EP0BCL +	.globl _EP0BCH +	.globl _FNADDR +	.globl _MICROFRAME +	.globl _USBFRAMEL +	.globl _USBFRAMEH +	.globl _TOGCTL +	.globl _WAKEUPCS +	.globl _SUSPEND +	.globl _USBCS +	.globl _XAUTODAT2 +	.globl _XAUTODAT1 +	.globl _I2CTL +	.globl _I2DAT +	.globl _I2CS +	.globl _PORTECFG +	.globl _PORTCCFG +	.globl _PORTACFG +	.globl _INTSETUP +	.globl _INT4IVEC +	.globl _INT2IVEC +	.globl _CLRERRCNT +	.globl _ERRCNTLIM +	.globl _USBERRIRQ +	.globl _USBERRIE +	.globl _GPIFIRQ +	.globl _GPIFIE +	.globl _EPIRQ +	.globl _EPIE +	.globl _USBIRQ +	.globl _USBIE +	.globl _NAKIRQ +	.globl _NAKIE +	.globl _IBNIRQ +	.globl _IBNIE +	.globl _EP8FIFOIRQ +	.globl _EP8FIFOIE +	.globl _EP6FIFOIRQ +	.globl _EP6FIFOIE +	.globl _EP4FIFOIRQ +	.globl _EP4FIFOIE +	.globl _EP2FIFOIRQ +	.globl _EP2FIFOIE +	.globl _OUTPKTEND +	.globl _INPKTEND +	.globl _EP8ISOINPKTS +	.globl _EP6ISOINPKTS +	.globl _EP4ISOINPKTS +	.globl _EP2ISOINPKTS +	.globl _EP8FIFOPFL +	.globl _EP8FIFOPFH +	.globl _EP6FIFOPFL +	.globl _EP6FIFOPFH +	.globl _EP4FIFOPFL +	.globl _EP4FIFOPFH +	.globl _EP2FIFOPFL +	.globl _EP2FIFOPFH +	.globl _EP8AUTOINLENL +	.globl _EP8AUTOINLENH +	.globl _EP6AUTOINLENL +	.globl _EP6AUTOINLENH +	.globl _EP4AUTOINLENL +	.globl _EP4AUTOINLENH +	.globl _EP2AUTOINLENL +	.globl _EP2AUTOINLENH +	.globl _EP8FIFOCFG +	.globl _EP6FIFOCFG +	.globl _EP4FIFOCFG +	.globl _EP2FIFOCFG +	.globl _EP8CFG +	.globl _EP6CFG +	.globl _EP4CFG +	.globl _EP2CFG +	.globl _EP1INCFG +	.globl _EP1OUTCFG +	.globl _REVCTL +	.globl _REVID +	.globl _FIFOPINPOLAR +	.globl _UART230 +	.globl _BPADDRL +	.globl _BPADDRH +	.globl _BREAKPT +	.globl _FIFORESET +	.globl _PINFLAGSCD +	.globl _PINFLAGSAB +	.globl _IFCONFIG +	.globl _CPUCS +	.globl _RES_WAVEDATA_END +	.globl _GPIF_WAVE_DATA +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +_IOA	=	0x0080 +_SP	=	0x0081 +_DPL	=	0x0082 +_DPH	=	0x0083 +_DPL1	=	0x0084 +_DPH1	=	0x0085 +_DPS	=	0x0086 +_PCON	=	0x0087 +_TCON	=	0x0088 +_TMOD	=	0x0089 +_TL0	=	0x008a +_TL1	=	0x008b +_TH0	=	0x008c +_TH1	=	0x008d +_CKCON	=	0x008e +_IOB	=	0x0090 +_EXIF	=	0x0091 +_MPAGE	=	0x0092 +_SCON0	=	0x0098 +_SBUF0	=	0x0099 +_APTR1H	=	0x009a +_APTR1L	=	0x009b +_AUTODAT1	=	0x009c +_AUTOPTRH2	=	0x009d +_AUTOPTRL2	=	0x009e +_AUTODAT2	=	0x009f +_IOC	=	0x00a0 +_INT2CLR	=	0x00a1 +_INT4CLR	=	0x00a2 +_IE	=	0x00a8 +_EP2468STAT	=	0x00aa +_EP24FIFOFLGS	=	0x00ab +_EP68FIFOFLGS	=	0x00ac +_AUTOPTRSETUP	=	0x00af +_IOD	=	0x00b0 +_IOE	=	0x00b1 +_OEA	=	0x00b2 +_OEB	=	0x00b3 +_OEC	=	0x00b4 +_OED	=	0x00b5 +_OEE	=	0x00b6 +_IP	=	0x00b8 +_EP01STAT	=	0x00ba +_GPIFTRIG	=	0x00bb +_GPIFSGLDATH	=	0x00bd +_GPIFSGLDATLX	=	0x00be +_GPIFSGLDATLNOX	=	0x00bf +_SCON1	=	0x00c0 +_SBUF1	=	0x00c1 +_T2CON	=	0x00c8 +_RCAP2L	=	0x00ca +_RCAP2H	=	0x00cb +_TL2	=	0x00cc +_TH2	=	0x00cd +_PSW	=	0x00d0 +_EICON	=	0x00d8 +_ACC	=	0x00e0 +_EIE	=	0x00e8 +_B	=	0x00f0 +_EIP	=	0x00f8 +;-------------------------------------------------------- +; special function bits  +;-------------------------------------------------------- +_SEL	=	0x0086 +_IT0	=	0x0088 +_IE0	=	0x0089 +_IT1	=	0x008a +_IE1	=	0x008b +_TR0	=	0x008c +_TF0	=	0x008d +_TR1	=	0x008e +_TF1	=	0x008f +_RI	=	0x0098 +_TI	=	0x0099 +_RB8	=	0x009a +_TB8	=	0x009b +_REN	=	0x009c +_SM2	=	0x009d +_SM1	=	0x009e +_SM0	=	0x009f +_EX0	=	0x00a8 +_ET0	=	0x00a9 +_EX1	=	0x00aa +_ET1	=	0x00ab +_ES0	=	0x00ac +_ET2	=	0x00ad +_ES1	=	0x00ae +_EA	=	0x00af +_PX0	=	0x00b8 +_PT0	=	0x00b9 +_PX1	=	0x00ba +_PT1	=	0x00bb +_PS0	=	0x00bc +_PT2	=	0x00bd +_PS1	=	0x00be +_RI1	=	0x00c0 +_TI1	=	0x00c1 +_RB81	=	0x00c2 +_TB81	=	0x00c3 +_REN1	=	0x00c4 +_SM21	=	0x00c5 +_SM11	=	0x00c6 +_SM01	=	0x00c7 +_CP_RL2	=	0x00c8 +_C_T2	=	0x00c9 +_TR2	=	0x00ca +_EXEN2	=	0x00cb +_TCLK	=	0x00cc +_RCLK	=	0x00cd +_EXF2	=	0x00ce +_TF2	=	0x00cf +_P	=	0x00d0 +_FL	=	0x00d1 +_OV	=	0x00d2 +_RS0	=	0x00d3 +_RS1	=	0x00d4 +_F0	=	0x00d5 +_AC	=	0x00d6 +_CY	=	0x00d7 +_INT6	=	0x00db +_RESI	=	0x00dc +_ERESI	=	0x00dd +_SMOD1	=	0x00df +_EIUSB	=	0x00e8 +_EI2C	=	0x00e9 +_EIEX4	=	0x00ea +_EIEX5	=	0x00eb +_EIEX6	=	0x00ec +_PUSB	=	0x00f8 +_PI2C	=	0x00f9 +_EIPX4	=	0x00fa +_EIPX5	=	0x00fb +_EIPX6	=	0x00fc +_bitS_CLK	=	0x0080 +_bitS_OUT	=	0x0081 +_bitS_IN	=	0x0082 +_bitALTERA_DATA0	=	0x00a1 +_bitALTERA_DCLK	=	0x00a3 +;-------------------------------------------------------- +; overlayable register banks  +;-------------------------------------------------------- +	.area REG_BANK_0	(REL,OVR,DATA) +	.ds 8 +;-------------------------------------------------------- +; internal ram data +;-------------------------------------------------------- +	.area DSEG    (DATA) +;-------------------------------------------------------- +; overlayable items in internal ram  +;-------------------------------------------------------- +	.area OSEG    (OVR,DATA) +;-------------------------------------------------------- +; Stack segment in internal ram  +;-------------------------------------------------------- +	.area	SSEG	(DATA) +__start__stack: +	.ds	1 + +;-------------------------------------------------------- +; indirectly addressable internal ram data +;-------------------------------------------------------- +	.area ISEG    (DATA) +;-------------------------------------------------------- +; bit data +;-------------------------------------------------------- +	.area BSEG    (BIT) +;-------------------------------------------------------- +; external ram data +;-------------------------------------------------------- +	.area XSEG    (XDATA) +_GPIF_WAVE_DATA	=	0xe400 +_RES_WAVEDATA_END	=	0xe480 +_CPUCS	=	0xe600 +_IFCONFIG	=	0xe601 +_PINFLAGSAB	=	0xe602 +_PINFLAGSCD	=	0xe603 +_FIFORESET	=	0xe604 +_BREAKPT	=	0xe605 +_BPADDRH	=	0xe606 +_BPADDRL	=	0xe607 +_UART230	=	0xe608 +_FIFOPINPOLAR	=	0xe609 +_REVID	=	0xe60a +_REVCTL	=	0xe60b +_EP1OUTCFG	=	0xe610 +_EP1INCFG	=	0xe611 +_EP2CFG	=	0xe612 +_EP4CFG	=	0xe613 +_EP6CFG	=	0xe614 +_EP8CFG	=	0xe615 +_EP2FIFOCFG	=	0xe618 +_EP4FIFOCFG	=	0xe619 +_EP6FIFOCFG	=	0xe61a +_EP8FIFOCFG	=	0xe61b +_EP2AUTOINLENH	=	0xe620 +_EP2AUTOINLENL	=	0xe621 +_EP4AUTOINLENH	=	0xe622 +_EP4AUTOINLENL	=	0xe623 +_EP6AUTOINLENH	=	0xe624 +_EP6AUTOINLENL	=	0xe625 +_EP8AUTOINLENH	=	0xe626 +_EP8AUTOINLENL	=	0xe627 +_EP2FIFOPFH	=	0xe630 +_EP2FIFOPFL	=	0xe631 +_EP4FIFOPFH	=	0xe632 +_EP4FIFOPFL	=	0xe633 +_EP6FIFOPFH	=	0xe634 +_EP6FIFOPFL	=	0xe635 +_EP8FIFOPFH	=	0xe636 +_EP8FIFOPFL	=	0xe637 +_EP2ISOINPKTS	=	0xe640 +_EP4ISOINPKTS	=	0xe641 +_EP6ISOINPKTS	=	0xe642 +_EP8ISOINPKTS	=	0xe643 +_INPKTEND	=	0xe648 +_OUTPKTEND	=	0xe649 +_EP2FIFOIE	=	0xe650 +_EP2FIFOIRQ	=	0xe651 +_EP4FIFOIE	=	0xe652 +_EP4FIFOIRQ	=	0xe653 +_EP6FIFOIE	=	0xe654 +_EP6FIFOIRQ	=	0xe655 +_EP8FIFOIE	=	0xe656 +_EP8FIFOIRQ	=	0xe657 +_IBNIE	=	0xe658 +_IBNIRQ	=	0xe659 +_NAKIE	=	0xe65a +_NAKIRQ	=	0xe65b +_USBIE	=	0xe65c +_USBIRQ	=	0xe65d +_EPIE	=	0xe65e +_EPIRQ	=	0xe65f +_GPIFIE	=	0xe660 +_GPIFIRQ	=	0xe661 +_USBERRIE	=	0xe662 +_USBERRIRQ	=	0xe663 +_ERRCNTLIM	=	0xe664 +_CLRERRCNT	=	0xe665 +_INT2IVEC	=	0xe666 +_INT4IVEC	=	0xe667 +_INTSETUP	=	0xe668 +_PORTACFG	=	0xe670 +_PORTCCFG	=	0xe671 +_PORTECFG	=	0xe672 +_I2CS	=	0xe678 +_I2DAT	=	0xe679 +_I2CTL	=	0xe67a +_XAUTODAT1	=	0xe67b +_XAUTODAT2	=	0xe67c +_USBCS	=	0xe680 +_SUSPEND	=	0xe681 +_WAKEUPCS	=	0xe682 +_TOGCTL	=	0xe683 +_USBFRAMEH	=	0xe684 +_USBFRAMEL	=	0xe685 +_MICROFRAME	=	0xe686 +_FNADDR	=	0xe687 +_EP0BCH	=	0xe68a +_EP0BCL	=	0xe68b +_EP1OUTBC	=	0xe68d +_EP1INBC	=	0xe68f +_EP2BCH	=	0xe690 +_EP2BCL	=	0xe691 +_EP4BCH	=	0xe694 +_EP4BCL	=	0xe695 +_EP6BCH	=	0xe698 +_EP6BCL	=	0xe699 +_EP8BCH	=	0xe69c +_EP8BCL	=	0xe69d +_EP0CS	=	0xe6a0 +_EP1OUTCS	=	0xe6a1 +_EP1INCS	=	0xe6a2 +_EP2CS	=	0xe6a3 +_EP4CS	=	0xe6a4 +_EP6CS	=	0xe6a5 +_EP8CS	=	0xe6a6 +_EP2FIFOFLGS	=	0xe6a7 +_EP4FIFOFLGS	=	0xe6a8 +_EP6FIFOFLGS	=	0xe6a9 +_EP8FIFOFLGS	=	0xe6aa +_EP2FIFOBCH	=	0xe6ab +_EP2FIFOBCL	=	0xe6ac +_EP4FIFOBCH	=	0xe6ad +_EP4FIFOBCL	=	0xe6ae +_EP6FIFOBCH	=	0xe6af +_EP6FIFOBCL	=	0xe6b0 +_EP8FIFOBCH	=	0xe6b1 +_EP8FIFOBCL	=	0xe6b2 +_SUDPTRH	=	0xe6b3 +_SUDPTRL	=	0xe6b4 +_SUDPTRCTL	=	0xe6b5 +_SETUPDAT	=	0xe6b8 +_GPIFWFSELECT	=	0xe6c0 +_GPIFIDLECS	=	0xe6c1 +_GPIFIDLECTL	=	0xe6c2 +_GPIFCTLCFG	=	0xe6c3 +_GPIFADRH	=	0xe6c4 +_GPIFADRL	=	0xe6c5 +_GPIFTCB3	=	0xe6ce +_GPIFTCB2	=	0xe6cf +_GPIFTCB1	=	0xe6d0 +_GPIFTCB0	=	0xe6d1 +_EP2GPIFFLGSEL	=	0xe6d2 +_EP2GPIFPFSTOP	=	0xe6d3 +_EP2GPIFTRIG	=	0xe6d4 +_EP4GPIFFLGSEL	=	0xe6da +_EP4GPIFPFSTOP	=	0xe6db +_EP4GPIFTRIG	=	0xe6dc +_EP6GPIFFLGSEL	=	0xe6e2 +_EP6GPIFPFSTOP	=	0xe6e3 +_EP6GPIFTRIG	=	0xe6e4 +_EP8GPIFFLGSEL	=	0xe6ea +_EP8GPIFPFSTOP	=	0xe6eb +_EP8GPIFTRIG	=	0xe6ec +_XGPIFSGLDATH	=	0xe6f0 +_XGPIFSGLDATLX	=	0xe6f1 +_XGPIFSGLDATLNOX	=	0xe6f2 +_GPIFREADYCFG	=	0xe6f3 +_GPIFREADYSTAT	=	0xe6f4 +_GPIFABORT	=	0xe6f5 +_FLOWSTATE	=	0xe6c6 +_FLOWLOGIC	=	0xe6c7 +_FLOWEQ0CTL	=	0xe6c8 +_FLOWEQ1CTL	=	0xe6c9 +_FLOWHOLDOFF	=	0xe6ca +_FLOWSTB	=	0xe6cb +_FLOWSTBEDGE	=	0xe6cc +_FLOWSTBHPERIOD	=	0xe6cd +_GPIFHOLDAMOUNT	=	0xe60c +_UDMACRCH	=	0xe67d +_UDMACRCL	=	0xe67e +_UDMACRCQUAL	=	0xe67f +_DBUG	=	0xe6f8 +_TESTCFG	=	0xe6f9 +_USBTEST	=	0xe6fa +_CT1	=	0xe6fb +_CT2	=	0xe6fc +_CT3	=	0xe6fd +_CT4	=	0xe6fe +_EP0BUF	=	0xe740 +_EP1OUTBUF	=	0xe780 +_EP1INBUF	=	0xe7c0 +_EP2FIFOBUF	=	0xf000 +_EP4FIFOBUF	=	0xf400 +_EP6FIFOBUF	=	0xf800 +_EP8FIFOBUF	=	0xfc00 +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; interrupt vector  +;-------------------------------------------------------- +	.area CSEG    (CODE) +__interrupt_vect: +	ljmp	__sdcc_gsinit_startup +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- +	.area GSINIT  (CODE) +	.area GSFINAL (CODE) +	.area GSINIT  (CODE) +__sdcc_gsinit_startup: +	mov	sp,#__start__stack - 1 +	lcall	__sdcc_external_startup +	mov	a,dpl +	jz	__sdcc_init_data +	ljmp	__sdcc_program_startup +__sdcc_init_data: +	.area GSFINAL (CODE) +	ljmp	__sdcc_program_startup +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- +	.area HOME    (CODE) +	.area CSEG    (CODE) +;-------------------------------------------------------- +; code +;-------------------------------------------------------- +	.area CSEG    (CODE) +__sdcc_program_startup: +	lcall	_eeprom_init +;	return from _eeprom_init will spin here +	sjmp . +	.area CSEG    (CODE) diff --git a/firmware/fx2/common/eeprom_init.c b/firmware/fx2/common/eeprom_init.c new file mode 100644 index 000000000..07902dcca --- /dev/null +++ b/firmware/fx2/common/eeprom_init.c @@ -0,0 +1,75 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usrp_common.h" +#include "usrp_commands.h" + +/* + * the host side fpga loader code pushes an MD5 hash of the bitstream + * into hash1. + */ +#define	  USRP_HASH_SIZE      16 +xdata at USRP_HASH_SLOT_0_ADDR unsigned char hash0[USRP_HASH_SIZE]; + + +#define REG_RX_PWR_DN		 1 +#define	REG_TX_PWR_DN		 8 +#define	REG_TX_MODULATOR	20 + +void eeprom_init (void) +{ +  unsigned short counter; +  unsigned char	 i; + +  // configure IO ports (B and D are used by GPIF) + +  IOA = bmPORT_A_INITIAL;	// Port A initial state +  OEA = bmPORT_A_OUTPUTS;	// Port A direction register + +  IOC = bmPORT_C_INITIAL;	// Port C initial state +  OEC = bmPORT_C_OUTPUTS;	// Port C direction register + +  IOE = bmPORT_E_INITIAL;	// Port E initial state +  OEE = bmPORT_E_OUTPUTS;	// Port E direction register + +  EP0BCH = 0;			SYNCDELAY; + +  // USBCS &= ~bmRENUM;		// chip firmware handles commands +  USBCS = 0;			// chip firmware handles commands + +  //USRP_PC &= ~bmPC_nRESET;	// active low reset +  //USRP_PC |=  bmPC_nRESET; + +  // zero firmware hash slot +  i = 0; +  do { +    hash0[i] = 0; +    i++; +  } while (i != USRP_HASH_SIZE); + +  counter = 0; +  while (1){ +    counter++; +    if (counter & 0x8000) +      IOC ^= bmPC_LED0; +  } +} diff --git a/firmware/fx2/common/fpga.h b/firmware/fx2/common/fpga.h new file mode 100644 index 000000000..6cd5de8e2 --- /dev/null +++ b/firmware/fx2/common/fpga.h @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_FPGA_H +#define INCLUDED_FPGA_H + +#include "fpga_load.h" + +#if defined(HAVE_USRP2) +#include "fpga_rev2.h" +#endif + +#endif /* INCLUDED_FPGA_H */ diff --git a/firmware/fx2/common/fpga_load.h b/firmware/fx2/common/fpga_load.h new file mode 100644 index 000000000..7c36a04c8 --- /dev/null +++ b/firmware/fx2/common/fpga_load.h @@ -0,0 +1,28 @@ +/*  + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +#ifndef INCLUDED_FPGA_LOAD_H +#define INCLUDED_FPGA_LOAD_H + +unsigned char fpga_load_begin (void); +unsigned char fpga_load_xfer (xdata unsigned char *p, unsigned char len); +unsigned char fpga_load_end (void); + +#endif /* INCLUDED_FPGA_LOAD_H */ diff --git a/firmware/fx2/common/fpga_regs0.h b/firmware/fx2/common/fpga_regs0.h new file mode 100644 index 000000000..883798301 --- /dev/null +++ b/firmware/fx2/common/fpga_regs0.h @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _FPGA_REGS0_H_ +#define _FPGA_REGS0_H_ + +#define FR_RX_FREQ_0	   0 +#define FR_RX_FREQ_1	   1 +#define FR_RX_FREQ_2	   2 +#define FR_RX_FREQ_3	   3 +#define FR_TX_FREQ_0	   4 +#define FR_TX_FREQ_1	   5 +#define FR_TX_FREQ_2	   6 +#define FR_TX_FREQ_3	   7 +#define FR_COMBO	   8 + + +#define FR_ADC_CLK_DIV   128	// pseudo regs mapped to FR_COMBO by f/w +#define FR_EXT_CLK_DIV	 129	 +#define FR_INTERP	 130 +#define FR_DECIM	 131 + +#endif diff --git a/firmware/fx2/common/fpga_regs_common.h b/firmware/fx2/common/fpga_regs_common.h new file mode 100644 index 000000000..b4a496af7 --- /dev/null +++ b/firmware/fx2/common/fpga_regs_common.h @@ -0,0 +1,150 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.	If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_FPGA_REGS_COMMON_H +#define INCLUDED_FPGA_REGS_COMMON_H + +// This file defines registers common to all FPGA configurations. +// Registers 0 to 31 are reserved for use in this file. + + +// The FPGA needs to know the rate that samples are coming from and +// going to the A/D's and D/A's.  div = 128e6 / sample_rate + +#define	FR_TX_SAMPLE_RATE_DIV	 0 +#define	FR_RX_SAMPLE_RATE_DIV	 1 + +// 2 and 3 are defined in the ATR section + +#define	FR_MASTER_CTRL		 4	// master enable and reset controls +#  define  bmFR_MC_ENABLE_TX		(1 << 0) +#  define  bmFR_MC_ENABLE_RX		(1 << 1) +#  define  bmFR_MC_RESET_TX		(1 << 2) +#  define  bmFR_MC_RESET_RX		(1 << 3) + +// i/o direction registers for pins that go to daughterboards. +// Setting the bit makes it an output from the FPGA to the d'board. +// top 16 is mask, low 16 is value + +#define	FR_OE_0			 5	// slot 0 +#define	FR_OE_1			 6 +#define	FR_OE_2			 7 +#define	FR_OE_3			 8 + +// i/o registers for pins that go to daughterboards. +// top 16 is a mask, low 16 is value + +#define	FR_IO_0			 9	// slot 0 +#define	FR_IO_1			10 +#define	FR_IO_2			11 +#define	FR_IO_3			12 + +#define	FR_MODE			13 +#  define  bmFR_MODE_NORMAL		      0 +#  define  bmFR_MODE_LOOPBACK		(1 << 0)	// enable digital loopback +#  define  bmFR_MODE_RX_COUNTING	(1 << 1)	// Rx is counting +#  define  bmFR_MODE_RX_COUNTING_32BIT	(1 << 2)	// Rx is counting with a 32 bit counter +                                                    // low and high 16 bits are multiplexed across channel I and Q + + +// If the corresponding bit is set, internal FPGA debug circuitry +// controls the i/o pins for the associated bank of daughterboard +// i/o pins.  Typically used for debugging FPGA designs. + +#define FR_DEBUG_EN             14 +#  define bmFR_DEBUG_EN_TX_A           (1 << 0)        // debug controls TX_A i/o +#  define bmFR_DEBUG_EN_RX_A           (1 << 1)        // debug controls RX_A i/o +#  define bmFR_DEBUG_EN_TX_B           (1 << 2)        // debug controls TX_B i/o +#  define bmFR_DEBUG_EN_RX_B           (1 << 3)        // debug controls RX_B i/o + + +// If the corresponding bit is set, enable the automatic DC +// offset correction control loop. +// +// The 4 low bits are significant: +// +//   ADC0 = (1 << 0) +//   ADC1 = (1 << 1) +//   ADC2 = (1 << 2) +//   ADC3 = (1 << 3) +// +// This control loop works if the attached daugherboard blocks DC. +// Currently all daughterboards do block DC.  This includes: +// basic rx, dbs_rx, tv_rx, flex_xxx_rx. + +#define FR_DC_OFFSET_CL_EN	15			// DC Offset Control Loop Enable + + +// offset corrections for ADC's and DAC's (2's complement) + +#define	FR_ADC_OFFSET_0	 	16 +#define	FR_ADC_OFFSET_1		17 +#define	FR_ADC_OFFSET_2	 	18 +#define	FR_ADC_OFFSET_3		19 + + +// ------------------------------------------------------------------------ +// Automatic Transmit/Receive switching +// +// If automatic transmit/receive (ATR) switching is enabled in the +// FR_ATR_CTL register, the presence or absence of data in the FPGA +// transmit fifo selects between two sets of values for each of the 4 +// banks of daughterboard i/o pins. +// +// Each daughterboard slot has 3 16-bit registers associated with it: +//   FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_* +// +// FR_ATR_MASK_{0,1,2,3}:  +// +//   These registers determine which of the daugherboard i/o pins are +//   affected by ATR switching.  If a bit in the mask is set, the +//   corresponding i/o bit is controlled by ATR, else it's output +//   value comes from the normal i/o pin output register: +//   FR_IO_{0,1,2,3}. +// +// FR_ATR_TXVAL_{0,1,2,3}: +// FR_ATR_RXVAL_{0,1,2,3}: +// +//   If the Tx fifo contains data, then the bits from TXVAL that are +//   selected by MASK are output.  Otherwise, the bits from RXVAL that +//   are selected by MASK are output. +                       +#define FR_ATR_MASK_0		20	// slot 0 +#define	FR_ATR_TXVAL_0		21 +#define FR_ATR_RXVAL_0		22 + +#define FR_ATR_MASK_1		23	// slot 1 +#define	FR_ATR_TXVAL_1		24 +#define FR_ATR_RXVAL_1		25 + +#define FR_ATR_MASK_2		26	// slot 2 +#define	FR_ATR_TXVAL_2		27 +#define FR_ATR_RXVAL_2		28 + +#define FR_ATR_MASK_3		29	// slot 3 +#define	FR_ATR_TXVAL_3		30 +#define FR_ATR_RXVAL_3		31 + +// Clock ticks to delay rising and falling edge of T/R signal +#define FR_ATR_TX_DELAY          2 +#define FR_ATR_RX_DELAY          3 + +#endif /* INCLUDED_FPGA_REGS_COMMON_H */ diff --git a/firmware/fx2/common/fpga_regs_common.v b/firmware/fx2/common/fpga_regs_common.v new file mode 100644 index 000000000..8035d8565 --- /dev/null +++ b/firmware/fx2/common/fpga_regs_common.v @@ -0,0 +1,117 @@ +// +// This file is machine generated from ./fpga_regs_common.h +// Do not edit by hand; your edits will be overwritten. +// + +// This file defines registers common to all FPGA configurations. +// Registers 0 to 31 are reserved for use in this file. + + +// The FPGA needs to know the rate that samples are coming from and +// going to the A/D's and D/A's.  div = 128e6 / sample_rate + +`define FR_TX_SAMPLE_RATE_DIV     7'd0 +`define FR_RX_SAMPLE_RATE_DIV     7'd1 + +// 2 and 3 are defined in the ATR section + +`define FR_MASTER_CTRL            7'd4	// master enable and reset controls + +// i/o direction registers for pins that go to daughterboards. +// Setting the bit makes it an output from the FPGA to the d'board. +// top 16 is mask, low 16 is value + +`define FR_OE_0                   7'd5	// slot 0 +`define FR_OE_1                   7'd6 +`define FR_OE_2                   7'd7 +`define FR_OE_3                   7'd8 + +// i/o registers for pins that go to daughterboards. +// top 16 is a mask, low 16 is value + +`define FR_IO_0                   7'd9	// slot 0 +`define FR_IO_1                   7'd10 +`define FR_IO_2                   7'd11 +`define FR_IO_3                   7'd12 + +`define FR_MODE                   7'd13 + + +// If the corresponding bit is set, internal FPGA debug circuitry +// controls the i/o pins for the associated bank of daughterboard +// i/o pins.  Typically used for debugging FPGA designs. + +`define FR_DEBUG_EN               7'd14 + + +// If the corresponding bit is set, enable the automatic DC +// offset correction control loop. +// +// The 4 low bits are significant: +// +//   ADC0 = (1 << 0) +//   ADC1 = (1 << 1) +//   ADC2 = (1 << 2) +//   ADC3 = (1 << 3) +// +// This control loop works if the attached daugherboard blocks DC. +// Currently all daughterboards do block DC.  This includes: +// basic rx, dbs_rx, tv_rx, flex_xxx_rx. + +`define FR_DC_OFFSET_CL_EN        7'd15			// DC Offset Control Loop Enable + + +// offset corrections for ADC's and DAC's (2's complement) + +`define FR_ADC_OFFSET_0           7'd16 +`define FR_ADC_OFFSET_1           7'd17 +`define FR_ADC_OFFSET_2           7'd18 +`define FR_ADC_OFFSET_3           7'd19 + + +// ------------------------------------------------------------------------ +// Automatic Transmit/Receive switching +// +// If automatic transmit/receive (ATR) switching is enabled in the +// FR_ATR_CTL register, the presence or absence of data in the FPGA +// transmit fifo selects between two sets of values for each of the 4 +// banks of daughterboard i/o pins. +// +// Each daughterboard slot has 3 16-bit registers associated with it: +//   FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_* +// +// FR_ATR_MASK_{0,1,2,3}:  +// +//   These registers determine which of the daugherboard i/o pins are +//   affected by ATR switching.  If a bit in the mask is set, the +//   corresponding i/o bit is controlled by ATR, else it's output +//   value comes from the normal i/o pin output register: +//   FR_IO_{0,1,2,3}. +// +// FR_ATR_TXVAL_{0,1,2,3}: +// FR_ATR_RXVAL_{0,1,2,3}: +// +//   If the Tx fifo contains data, then the bits from TXVAL that are +//   selected by MASK are output.  Otherwise, the bits from RXVAL that +//   are selected by MASK are output. +                       +`define FR_ATR_MASK_0             7'd20	// slot 0 +`define FR_ATR_TXVAL_0            7'd21 +`define FR_ATR_RXVAL_0            7'd22 + +`define FR_ATR_MASK_1             7'd23	// slot 1 +`define FR_ATR_TXVAL_1            7'd24 +`define FR_ATR_RXVAL_1            7'd25 + +`define FR_ATR_MASK_2             7'd26	// slot 2 +`define FR_ATR_TXVAL_2            7'd27 +`define FR_ATR_RXVAL_2            7'd28 + +`define FR_ATR_MASK_3             7'd29	// slot 3 +`define FR_ATR_TXVAL_3            7'd30 +`define FR_ATR_RXVAL_3            7'd31 + +// Clock ticks to delay rising and falling edge of T/R signal +`define FR_ATR_TX_DELAY           7'd2 +`define FR_ATR_RX_DELAY           7'd3 + diff --git a/firmware/fx2/common/fpga_regs_standard.h b/firmware/fx2/common/fpga_regs_standard.h new file mode 100644 index 000000000..7485e2bab --- /dev/null +++ b/firmware/fx2/common/fpga_regs_standard.h @@ -0,0 +1,300 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2004,2006 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.	If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_FPGA_REGS_STANDARD_H +#define INCLUDED_FPGA_REGS_STANDARD_H + +// Register numbers 0 to 31 are reserved for use in fpga_regs_common.h. +// Registers 64 to 79 are available for custom FPGA builds. + + +// DDC / DUC + +#define	FR_INTERP_RATE		32	// [1,1024] +#define	FR_DECIM_RATE		33	// [1,256] + +// DDC center freq + +#define FR_RX_FREQ_0		34 +#define FR_RX_FREQ_1		35 +#define FR_RX_FREQ_2		36 +#define FR_RX_FREQ_3		37 + +// See below for DDC Starting Phase + +// ------------------------------------------------------------------------ +//  configure FPGA Rx mux +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------+-------+-------+-------+-------+-+-----+ +// |      must be zero     | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH | +// +-----------------------+-------+-------+-------+-------+-+-----+ +// +// There are a maximum of 4 digital downconverters in the the FPGA. +// Each DDC has two 16-bit inputs, I and Q, and two 16-bit outputs, I & Q. +// +// DDC I inputs are specified by the two bit fields I3, I2, I1 & I0 +// +//   0 = DDC input is from ADC 0 +//   1 = DDC input is from ADC 1 +//   2 = DDC input is from ADC 2 +//   3 = DDC input is from ADC 3 +// +// If Z == 1, all DDC Q inputs are set to zero +// If Z == 0, DDC Q inputs are specified by the two bit fields Q3, Q2, Q1 & Q0 +// +// NCH specifies the number of complex channels that are sent across +// the USB.  The legal values are 1, 2 or 4, corresponding to 2, 4 or +// 8 16-bit values. + +#define	FR_RX_MUX		38 + +// ------------------------------------------------------------------------ +//  configure FPGA Tx Mux. +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------+-------+-------+-------+-------+-+-----+ +// |                       | DAC3  | DAC2  | DAC1  |  DAC0 |0| NCH | +// +-----------------------------------------------+-------+-+-----+ +// +// NCH specifies the number of complex channels that are sent across +// the USB.  The legal values are 1 or 2, corresponding to 2 or 4 +// 16-bit values. +// +// There are two interpolators with complex inputs and outputs. +// There are four DACs.  (We use the DUC in each AD9862.) +// +// Each 4-bit DACx field specifies the source for the DAC and +// whether or not that DAC is enabled.  Each subfield is coded +// like this:  +// +//    3 2 1 0 +//   +-+-----+ +//   |E|  N  | +//   +-+-----+ +// +// Where E is set if the DAC is enabled, and N specifies which +// interpolator output is connected to this DAC. +// +//  N   which interp output +// ---  ------------------- +//  0   chan 0 I +//  1   chan 0 Q +//  2   chan 1 I +//  3   chan 1 Q + +#define	FR_TX_MUX		39 + +// ------------------------------------------------------------------------ +// REFCLK control +// +// Control whether a reference clock is sent to the daughterboards, +// and what frequency.  The refclk is sent on d'board i/o pin 0. +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------------+-+------------+ +// |             Reserved (Must be zero)           |E|   DIVISOR  | +// +-----------------------------------------------+-+------------+ + +// +// Bit 7  -- 1 turns on refclk, 0 allows IO use +// Bits 6:0 Divider value + +#define FR_TX_A_REFCLK          40 +#define FR_RX_A_REFCLK          41 +#define FR_TX_B_REFCLK          42 +#define FR_RX_B_REFCLK          43 + +#  define bmFR_REFCLK_EN	   0x80 +#  define bmFR_REFCLK_DIVISOR_MASK 0x7f + +// ------------------------------------------------------------------------ +// DDC Starting Phase + +#define FR_RX_PHASE_0		44 +#define FR_RX_PHASE_1		45 +#define FR_RX_PHASE_2		46 +#define FR_RX_PHASE_3		47 + +// ------------------------------------------------------------------------ +// Tx data format control register +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-------------------------------------------------------+-------+ +// |                    Reserved (Must be zero)            |  FMT  | +// +-------------------------------------------------------+-------+ +// +//  FMT values: + +#define FR_TX_FORMAT		48 +#  define bmFR_TX_FORMAT_16_IQ		0	// 16-bit I, 16-bit Q + +// ------------------------------------------------------------------------ +// Rx data format control register +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------+-+-+---------+-------+ +// |          Reserved (Must be zero)        |B|Q|  WIDTH  | SHIFT | +// +-----------------------------------------+-+-+---------+-------+ +// +//  FMT values: + +#define FR_RX_FORMAT		49 + +#  define bmFR_RX_FORMAT_SHIFT_MASK	(0x0f <<  0)	// arithmetic right shift [0, 15] +#  define bmFR_RX_FORMAT_SHIFT_SHIFT	0 +#  define bmFR_RX_FORMAT_WIDTH_MASK	(0x1f <<  4)    // data width in bits [1, 16] (not all valid) +#  define bmFR_RX_FORMAT_WIDTH_SHIFT    4 +#  define bmFR_RX_FORMAT_WANT_Q		(0x1  <<  9)    // deliver both I & Q, else just I +#  define bmFR_RX_FORMAT_BYPASS_HB	(0x1  << 10)    // bypass half-band filter + +// The valid combinations currently are: +// +//   B  Q  WIDTH  SHIFT +//   0  1    16     0 +//   0  1     8     8 + + +// Possible future values of WIDTH = {4, 2, 1} +// 12 takes a bit more work, since we need to know packet alignment. + +// ------------------------------------------------------------------------ +// FIXME register numbers 50 to 63 are available + +// ------------------------------------------------------------------------ +// Registers 64 to 95 are reserved for user custom FPGA builds. +// The standard USRP software will not touch these. + +#define FR_USER_0	64 +#define FR_USER_1	65 +#define FR_USER_2	66 +#define FR_USER_3	67 +#define FR_USER_4	68 +#define FR_USER_5	69 +#define FR_USER_6	70 +#define FR_USER_7	71 +#define FR_USER_8	72 +#define FR_USER_9	73 +#define FR_USER_10	74 +#define FR_USER_11	75 +#define FR_USER_12	76 +#define FR_USER_13	77 +#define FR_USER_14	78 +#define FR_USER_15	79 +#define FR_USER_16	80 +#define FR_USER_17	81 +#define FR_USER_18	82 +#define FR_USER_19	83 +#define FR_USER_20	84 +#define FR_USER_21	85 +#define FR_USER_22	86 +#define FR_USER_23	87 +#define FR_USER_24	88 +#define FR_USER_25	89 +#define FR_USER_26	90 +#define FR_USER_27	91 +#define FR_USER_28	92 +#define FR_USER_29	93 +#define FR_USER_30	94 +#define FR_USER_31	95 + +//Registers needed for multi usrp master/slave configuration +// +//Rx Master/slave control register (FR_RX_MASTER_SLAVE = FR_USER_0) +// +#define FR_RX_MASTER_SLAVE		64 +#define bitnoFR_RX_SYNC			0 +#define bitnoFR_RX_SYNC_MASTER		1 +#define bitnoFR_RX_SYNC_SLAVE		2 +#  define bmFR_RX_SYNC          (1 <<bitnoFR_RX_SYNC) //1 If this is a master "sync now" and send sync to slave. +                                                      //  If this is a slave "sync now" (testing purpose only) +                                                      //  Sync is allmost the same as reset (clear all counters and buffers)  +                                                      //  except that the io outputs and settings don't get reset (otherwise it couldn't send the sync to the slave) +                                                      //0 Normal operation + +#  define bmFR_RX_SYNC_MASTER (1 <<bitnoFR_RX_SYNC_MASTER) //1 This is a rx sync master, output sync_rx on rx_a_io[15] +                                                           //0 This is not a rx sync master +#  define bmFR_RX_SYNC_SLAVE  (1 <<bitnoFR_RX_SYNC_SLAVE) //1 This is a rx sync slave, follow sync_rx on rx_a_io[bitnoFR_RX_SYNC_INPUT_IOPIN] +                                                          //0 This is not an rx sync slave. + +//Caution The master settings will output values on the io lines. +//They inheritely enable these lines as output. If you have a daughtercard which uses these lines also as output then you will burn your usrp and daughtercard. +//If you set the slave bits then your usrp won't do anything if you don't connect a master. +// Rx Master/slave control register +// +// The way this is supposed to be used is connecting a (short) 16pin flatcable from an rx daughterboard in RXA master io_rx[8..15] to slave io_rx[8..15] on RXA of slave usrp +// This can be done with basic_rx boards or dbsrx boards +//dbsrx: connect master-J25 to slave-J25 +//basic rx: connect J25 to slave-J25 +//CAUTION: pay attention to the lineup of your connector. +//The red line (pin1) should be at the same side of the daughterboards on master and slave. +//If you turnaround the cable on one end you will burn your usrp. + +//You cannot use a 16pin flatcable if you are using FLEX400 or FLEX2400 daughterboards, since these use a lot of the io pins. +//You can still link them but you must use only a 2pin or 1pin cable +//You can also use a 2-wire link. put a 2pin header on io[15],gnd of the master RXA daughterboard and connect it to io15,gnd of the slave RXA db. +//You can use a cable like the ones found with the leds on the mainbord of a PC. +//Make sure you don't twist the cable, otherwise you connect the sync output to ground. +//To be save you could also just use a single wire from master io[15] to slave io[15], but this is not optimal for signal integrity. + + +// Since rx_io[0] can normally be used as a refclk and is not exported on all daughterboards this line +// still has the refclk function if you use the master/slave setup (it is not touched by the master/slave settings). +// The master/slave circuitry will only use io pin 15 and does not touch any of the other io pins. +#define bitnoFR_RX_SYNC_INPUT_IOPIN		15 +#define bmFR_RX_SYNC_INPUT_IOPIN		(1<<bitnoFR_RX_SYNC_INPUT_IOPIN) +//TODO the output pin is still hardcoded in the verilog code, make it listen to the following define +#define bitnoFR_RX_SYNC_OUTPUT_IOPIN	15 +#define bmFR_RX_SYNC_OUTPUT_IOPIN	(1<<bitnoFR_RX_SYNC_OUTPUT_IOPIN) +// ======================================================================= +// READBACK Registers +// ======================================================================= + +#define FR_RB_IO_RX_A_IO_TX_A	1	// read back a-side i/o pins +#define	FR_RB_IO_RX_B_IO_TX_B	2	// read back b-side i/o pins + +// ------------------------------------------------------------------------ +// FPGA Capability register +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------------+-+-----+-+-----+ +// |                    Reserved (Must be zero)    |T|NDUC |R|NDDC | +// +-----------------------------------------------+-+-----+-+-----+ +// +// Bottom 4-bits are Rx capabilities +// Next   4-bits are Tx capabilities + +#define	FR_RB_CAPS	3 +#  define bmFR_RB_CAPS_NDDC_MASK	(0x7 << 0)   // # of digital down converters 0,1,2,4 +#  define bmFR_RB_CAPS_NDDC_SHIFT	0 +#  define bmFR_RB_CAPS_RX_HAS_HALFBAND	(0x1 << 3) +#  define bmFR_RB_CAPS_NDUC_MASK        (0x7 << 4)   // # of digital up converters 0,1,2 +#  define bmFR_RB_CAPS_NDUC_SHIFT	4 +#  define bmFR_RB_CAPS_TX_HAS_HALFBAND	(0x1 << 7) + + +#endif /* INCLUDED_FPGA_REGS_STANDARD_H */ diff --git a/firmware/fx2/common/fpga_regs_standard.v b/firmware/fx2/common/fpga_regs_standard.v new file mode 100644 index 000000000..d09aa6116 --- /dev/null +++ b/firmware/fx2/common/fpga_regs_standard.v @@ -0,0 +1,256 @@ +// +// This file is machine generated from ./fpga_regs_standard.h +// Do not edit by hand; your edits will be overwritten. +// + +// Register numbers 0 to 31 are reserved for use in fpga_regs_common.h. +// Registers 64 to 79 are available for custom FPGA builds. + + +// DDC / DUC + +`define FR_INTERP_RATE            7'd32	// [1,1024] +`define FR_DECIM_RATE             7'd33	// [1,256] + +// DDC center freq + +`define FR_RX_FREQ_0              7'd34 +`define FR_RX_FREQ_1              7'd35 +`define FR_RX_FREQ_2              7'd36 +`define FR_RX_FREQ_3              7'd37 + +// See below for DDC Starting Phase + +// ------------------------------------------------------------------------ +//  configure FPGA Rx mux +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------+-------+-------+-------+-------+-+-----+ +// |      must be zero     | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH | +// +-----------------------+-------+-------+-------+-------+-+-----+ +// +// There are a maximum of 4 digital downconverters in the the FPGA. +// Each DDC has two 16-bit inputs, I and Q, and two 16-bit outputs, I & Q. +// +// DDC I inputs are specified by the two bit fields I3, I2, I1 & I0 +// +//   0 = DDC input is from ADC 0 +//   1 = DDC input is from ADC 1 +//   2 = DDC input is from ADC 2 +//   3 = DDC input is from ADC 3 +// +// If Z == 1, all DDC Q inputs are set to zero +// If Z == 0, DDC Q inputs are specified by the two bit fields Q3, Q2, Q1 & Q0 +// +// NCH specifies the number of complex channels that are sent across +// the USB.  The legal values are 1, 2 or 4, corresponding to 2, 4 or +// 8 16-bit values. + +`define FR_RX_MUX                 7'd38 + +// ------------------------------------------------------------------------ +//  configure FPGA Tx Mux. +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------+-------+-------+-------+-------+-+-----+ +// |                       | DAC3  | DAC2  | DAC1  |  DAC0 |0| NCH | +// +-----------------------------------------------+-------+-+-----+ +// +// NCH specifies the number of complex channels that are sent across +// the USB.  The legal values are 1 or 2, corresponding to 2 or 4 +// 16-bit values. +// +// There are two interpolators with complex inputs and outputs. +// There are four DACs.  (We use the DUC in each AD9862.) +// +// Each 4-bit DACx field specifies the source for the DAC and +// whether or not that DAC is enabled.  Each subfield is coded +// like this:  +// +//    3 2 1 0 +//   +-+-----+ +//   |E|  N  | +//   +-+-----+ +// +// Where E is set if the DAC is enabled, and N specifies which +// interpolator output is connected to this DAC. +// +//  N   which interp output +// ---  ------------------- +//  0   chan 0 I +//  1   chan 0 Q +//  2   chan 1 I +//  3   chan 1 Q + +`define FR_TX_MUX                 7'd39 + +// ------------------------------------------------------------------------ +// REFCLK control +// +// Control whether a reference clock is sent to the daughterboards, +// and what frequency.  The refclk is sent on d'board i/o pin 0. +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------------+-+------------+ +// |             Reserved (Must be zero)           |E|   DIVISOR  | +// +-----------------------------------------------+-+------------+ + +// +// Bit 7  -- 1 turns on refclk, 0 allows IO use +// Bits 6:0 Divider value + +`define FR_TX_A_REFCLK            7'd40 +`define FR_RX_A_REFCLK            7'd41 +`define FR_TX_B_REFCLK            7'd42 +`define FR_RX_B_REFCLK            7'd43 + + +// ------------------------------------------------------------------------ +// DDC Starting Phase + +`define FR_RX_PHASE_0             7'd44 +`define FR_RX_PHASE_1             7'd45 +`define FR_RX_PHASE_2             7'd46 +`define FR_RX_PHASE_3             7'd47 + +// ------------------------------------------------------------------------ +// Tx data format control register +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-------------------------------------------------------+-------+ +// |                    Reserved (Must be zero)            |  FMT  | +// +-------------------------------------------------------+-------+ +// +//  FMT values: + +`define FR_TX_FORMAT              7'd48 + +// ------------------------------------------------------------------------ +// Rx data format control register +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------+-+-+---------+-------+ +// |          Reserved (Must be zero)        |B|Q|  WIDTH  | SHIFT | +// +-----------------------------------------+-+-+---------+-------+ +// +//  FMT values: + +`define FR_RX_FORMAT              7'd49 + + +// The valid combinations currently are: +// +//   B  Q  WIDTH  SHIFT +//   0  1    16     0 +//   0  1     8     8 + + +// Possible future values of WIDTH = {4, 2, 1} +// 12 takes a bit more work, since we need to know packet alignment. + +// ------------------------------------------------------------------------ +// FIXME register numbers 50 to 63 are available + +// ------------------------------------------------------------------------ +// Registers 64 to 95 are reserved for user custom FPGA builds. +// The standard USRP software will not touch these. + +`define FR_USER_0                 7'd64 +`define FR_USER_1                 7'd65 +`define FR_USER_2                 7'd66 +`define FR_USER_3                 7'd67 +`define FR_USER_4                 7'd68 +`define FR_USER_5                 7'd69 +`define FR_USER_6                 7'd70 +`define FR_USER_7                 7'd71 +`define FR_USER_8                 7'd72 +`define FR_USER_9                 7'd73 +`define FR_USER_10                7'd74 +`define FR_USER_11                7'd75 +`define FR_USER_12                7'd76 +`define FR_USER_13                7'd77 +`define FR_USER_14                7'd78 +`define FR_USER_15                7'd79 +`define FR_USER_16                7'd80 +`define FR_USER_17                7'd81 +`define FR_USER_18                7'd82 +`define FR_USER_19                7'd83 +`define FR_USER_20                7'd84 +`define FR_USER_21                7'd85 +`define FR_USER_22                7'd86 +`define FR_USER_23                7'd87 +`define FR_USER_24                7'd88 +`define FR_USER_25                7'd89 +`define FR_USER_26                7'd90 +`define FR_USER_27                7'd91 +`define FR_USER_28                7'd92 +`define FR_USER_29                7'd93 +`define FR_USER_30                7'd94 +`define FR_USER_31                7'd95 + +//Registers needed for multi usrp master/slave configuration +// +//Rx Master/slave control register (FR_RX_MASTER_SLAVE = FR_USER_0) +// +`define FR_RX_MASTER_SLAVE        7'd64 +`define bitnoFR_RX_SYNC           0 +`define bitnoFR_RX_SYNC_MASTER    1 +`define bitnoFR_RX_SYNC_SLAVE     2 + + +//Caution The master settings will output values on the io lines. +//They inheritely enable these lines as output. If you have a daughtercard which uses these lines also as output then you will burn your usrp and daughtercard. +//If you set the slave bits then your usrp won't do anything if you don't connect a master. +// Rx Master/slave control register +// +// The way this is supposed to be used is connecting a (short) 16pin flatcable from an rx daughterboard in RXA master io_rx[8..15] to slave io_rx[8..15] on RXA of slave usrp +// This can be done with basic_rx boards or dbsrx boards +//dbsrx: connect master-J25 to slave-J25 +//basic rx: connect J25 to slave-J25 +//CAUTION: pay attention to the lineup of your connector. +//The red line (pin1) should be at the same side of the daughterboards on master and slave. +//If you turnaround the cable on one end you will burn your usrp. + +//You cannot use a 16pin flatcable if you are using FLEX400 or FLEX2400 daughterboards, since these use a lot of the io pins. +//You can still link them but you must use only a 2pin or 1pin cable +//You can also use a 2-wire link. put a 2pin header on io[15],gnd of the master RXA daughterboard and connect it to io15,gnd of the slave RXA db. +//You can use a cable like the ones found with the leds on the mainbord of a PC. +//Make sure you don't twist the cable, otherwise you connect the sync output to ground. +//To be save you could also just use a single wire from master io[15] to slave io[15], but this is not optimal for signal integrity. + + +// Since rx_io[0] can normally be used as a refclk and is not exported on all daughterboards this line +// still has the refclk function if you use the master/slave setup (it is not touched by the master/slave settings). +// The master/slave circuitry will only use io pin 15 and does not touch any of the other io pins. +`define bitnoFR_RX_SYNC_INPUT_IOPIN 15 +`define bmFR_RX_SYNC_INPUT_IOPIN  (1<<bitnoFR_RX_SYNC_INPUT_IOPIN) +//TODO the output pin is still hardcoded in the verilog code, make it listen to the following define +`define bitnoFR_RX_SYNC_OUTPUT_IOPIN 15 +`define bmFR_RX_SYNC_OUTPUT_IOPIN (1<<bitnoFR_RX_SYNC_OUTPUT_IOPIN) +// ======================================================================= +// READBACK Registers +// ======================================================================= + +`define FR_RB_IO_RX_A_IO_TX_A     7'd1	// read back a-side i/o pins +`define FR_RB_IO_RX_B_IO_TX_B     7'd2	// read back b-side i/o pins + +// ------------------------------------------------------------------------ +// FPGA Capability register +// +//    3                   2                   1                        +//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------------+-+-----+-+-----+ +// |                    Reserved (Must be zero)    |T|NDUC |R|NDDC | +// +-----------------------------------------------+-+-----+-+-----+ +// +// Bottom 4-bits are Rx capabilities +// Next   4-bits are Tx capabilities + +`define FR_RB_CAPS                7'd3 + + diff --git a/firmware/fx2/common/fx2regs.h b/firmware/fx2/common/fx2regs.h new file mode 100644 index 000000000..2f210f567 --- /dev/null +++ b/firmware/fx2/common/fx2regs.h @@ -0,0 +1,716 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* +//----------------------------------------------------------------------------- +//   File:      FX2regs.h +//   Contents:   EZ-USB FX2 register declarations and bit mask definitions. +// +// $Archive: /USB/Target/Inc/fx2regs.h $ +// $Date$ +// $Revision$ +// +// +//   Copyright (c) 2000 Cypress Semiconductor, All rights reserved +//----------------------------------------------------------------------------- +*/ + + +#ifndef FX2REGS_H   /* Header Sentry */ +#define FX2REGS_H + +#define ALLOCATE_EXTERN		// required for "right thing to happen" with fx2regs.h + +/* +//----------------------------------------------------------------------------- +// FX2 Related Register Assignments +//----------------------------------------------------------------------------- + +// The Ez-USB FX2 registers are defined here. We use FX2regs.h for register  +// address allocation by using "#define ALLOCATE_EXTERN".  +// When using "#define ALLOCATE_EXTERN", you get (for instance):  +// xdata volatile BYTE OUT7BUF[64]   _at_   0x7B40; +// Such lines are created from FX2.h by using the preprocessor.  +// Incidently, these lines will not generate any space in the resulting hex  +// file; they just bind the symbols to the addresses for compilation.  +// You just need to put "#define ALLOCATE_EXTERN" in your main program file;  +// i.e. fw.c or a stand-alone C source file.  +// Without "#define ALLOCATE_EXTERN", you just get the external reference:  +// extern xdata volatile BYTE OUT7BUF[64]   ;//   0x7B40; +// This uses the concatenation operator "##" to insert a comment "//"  +// to cut off the end of the line, "_at_   0x7B40;", which is not wanted. +*/ + + +#ifdef ALLOCATE_EXTERN +#define EXTERN +#define _AT_(a) at a +#else +#define EXTERN extern +#define _AT_ ;/ ## / +#endif + +typedef unsigned char BYTE; +typedef unsigned short WORD; + +EXTERN xdata _AT_(0xE400) volatile BYTE GPIF_WAVE_DATA[128]; +EXTERN xdata _AT_(0xE480) volatile BYTE RES_WAVEDATA_END  ; + +// General Configuration + +EXTERN xdata _AT_(0xE600) volatile BYTE CPUCS             ;  // Control & Status +EXTERN xdata _AT_(0xE601) volatile BYTE IFCONFIG          ;  // Interface Configuration +EXTERN xdata _AT_(0xE602) volatile BYTE PINFLAGSAB        ;  // FIFO FLAGA and FLAGB Assignments +EXTERN xdata _AT_(0xE603) volatile BYTE PINFLAGSCD        ;  // FIFO FLAGC and FLAGD Assignments +EXTERN xdata _AT_(0xE604) volatile BYTE FIFORESET         ;  // Restore FIFOS to default state +EXTERN xdata _AT_(0xE605) volatile BYTE BREAKPT           ;  // Breakpoint +EXTERN xdata _AT_(0xE606) volatile BYTE BPADDRH           ;  // Breakpoint Address H +EXTERN xdata _AT_(0xE607) volatile BYTE BPADDRL           ;  // Breakpoint Address L +EXTERN xdata _AT_(0xE608) volatile BYTE UART230           ;  // 230 Kbaud clock for T0,T1,T2 +EXTERN xdata _AT_(0xE609) volatile BYTE FIFOPINPOLAR      ;  // FIFO polarities +EXTERN xdata _AT_(0xE60A) volatile BYTE REVID             ;  // Chip Revision +EXTERN xdata _AT_(0xE60B) volatile BYTE REVCTL            ;  // Chip Revision Control + +// Endpoint Configuration + +EXTERN xdata _AT_(0xE610) volatile BYTE EP1OUTCFG         ;  // Endpoint 1-OUT Configuration +EXTERN xdata _AT_(0xE611) volatile BYTE EP1INCFG          ;  // Endpoint 1-IN Configuration +EXTERN xdata _AT_(0xE612) volatile BYTE EP2CFG            ;  // Endpoint 2 Configuration +EXTERN xdata _AT_(0xE613) volatile BYTE EP4CFG            ;  // Endpoint 4 Configuration +EXTERN xdata _AT_(0xE614) volatile BYTE EP6CFG            ;  // Endpoint 6 Configuration +EXTERN xdata _AT_(0xE615) volatile BYTE EP8CFG            ;  // Endpoint 8 Configuration +EXTERN xdata _AT_(0xE618) volatile BYTE EP2FIFOCFG        ;  // Endpoint 2 FIFO configuration +EXTERN xdata _AT_(0xE619) volatile BYTE EP4FIFOCFG        ;  // Endpoint 4 FIFO configuration +EXTERN xdata _AT_(0xE61A) volatile BYTE EP6FIFOCFG        ;  // Endpoint 6 FIFO configuration +EXTERN xdata _AT_(0xE61B) volatile BYTE EP8FIFOCFG        ;  // Endpoint 8 FIFO configuration +EXTERN xdata _AT_(0xE620) volatile BYTE EP2AUTOINLENH     ;  // Endpoint 2 Packet Length H (IN only) +EXTERN xdata _AT_(0xE621) volatile BYTE EP2AUTOINLENL     ;  // Endpoint 2 Packet Length L (IN only) +EXTERN xdata _AT_(0xE622) volatile BYTE EP4AUTOINLENH     ;  // Endpoint 4 Packet Length H (IN only) +EXTERN xdata _AT_(0xE623) volatile BYTE EP4AUTOINLENL     ;  // Endpoint 4 Packet Length L (IN only) +EXTERN xdata _AT_(0xE624) volatile BYTE EP6AUTOINLENH     ;  // Endpoint 6 Packet Length H (IN only) +EXTERN xdata _AT_(0xE625) volatile BYTE EP6AUTOINLENL     ;  // Endpoint 6 Packet Length L (IN only) +EXTERN xdata _AT_(0xE626) volatile BYTE EP8AUTOINLENH     ;  // Endpoint 8 Packet Length H (IN only) +EXTERN xdata _AT_(0xE627) volatile BYTE EP8AUTOINLENL     ;  // Endpoint 8 Packet Length L (IN only) +EXTERN xdata _AT_(0xE630) volatile BYTE EP2FIFOPFH        ;  // EP2 Programmable Flag trigger H +EXTERN xdata _AT_(0xE631) volatile BYTE EP2FIFOPFL        ;  // EP2 Programmable Flag trigger L +EXTERN xdata _AT_(0xE632) volatile BYTE EP4FIFOPFH        ;  // EP4 Programmable Flag trigger H +EXTERN xdata _AT_(0xE633) volatile BYTE EP4FIFOPFL        ;  // EP4 Programmable Flag trigger L +EXTERN xdata _AT_(0xE634) volatile BYTE EP6FIFOPFH        ;  // EP6 Programmable Flag trigger H +EXTERN xdata _AT_(0xE635) volatile BYTE EP6FIFOPFL        ;  // EP6 Programmable Flag trigger L +EXTERN xdata _AT_(0xE636) volatile BYTE EP8FIFOPFH        ;  // EP8 Programmable Flag trigger H +EXTERN xdata _AT_(0xE637) volatile BYTE EP8FIFOPFL        ;  // EP8 Programmable Flag trigger L +EXTERN xdata _AT_(0xE640) volatile BYTE EP2ISOINPKTS      ;  // EP2 (if ISO) IN Packets per frame (1-3) +EXTERN xdata _AT_(0xE641) volatile BYTE EP4ISOINPKTS      ;  // EP4 (if ISO) IN Packets per frame (1-3) +EXTERN xdata _AT_(0xE642) volatile BYTE EP6ISOINPKTS      ;  // EP6 (if ISO) IN Packets per frame (1-3) +EXTERN xdata _AT_(0xE643) volatile BYTE EP8ISOINPKTS      ;  // EP8 (if ISO) IN Packets per frame (1-3) +EXTERN xdata _AT_(0xE648) volatile BYTE INPKTEND          ;  // Force IN Packet End +EXTERN xdata _AT_(0xE649) volatile BYTE OUTPKTEND         ;  // Force OUT Packet End + +// Interrupts + +EXTERN xdata _AT_(0xE650) volatile BYTE EP2FIFOIE         ;  // Endpoint 2 Flag Interrupt Enable +EXTERN xdata _AT_(0xE651) volatile BYTE EP2FIFOIRQ        ;  // Endpoint 2 Flag Interrupt Request +EXTERN xdata _AT_(0xE652) volatile BYTE EP4FIFOIE         ;  // Endpoint 4 Flag Interrupt Enable +EXTERN xdata _AT_(0xE653) volatile BYTE EP4FIFOIRQ        ;  // Endpoint 4 Flag Interrupt Request +EXTERN xdata _AT_(0xE654) volatile BYTE EP6FIFOIE         ;  // Endpoint 6 Flag Interrupt Enable +EXTERN xdata _AT_(0xE655) volatile BYTE EP6FIFOIRQ        ;  // Endpoint 6 Flag Interrupt Request +EXTERN xdata _AT_(0xE656) volatile BYTE EP8FIFOIE         ;  // Endpoint 8 Flag Interrupt Enable +EXTERN xdata _AT_(0xE657) volatile BYTE EP8FIFOIRQ        ;  // Endpoint 8 Flag Interrupt Request +EXTERN xdata _AT_(0xE658) volatile BYTE IBNIE             ;  // IN-BULK-NAK Interrupt Enable +EXTERN xdata _AT_(0xE659) volatile BYTE IBNIRQ            ;  // IN-BULK-NAK interrupt Request +EXTERN xdata _AT_(0xE65A) volatile BYTE NAKIE             ;  // Endpoint Ping NAK interrupt Enable +EXTERN xdata _AT_(0xE65B) volatile BYTE NAKIRQ            ;  // Endpoint Ping NAK interrupt Request +EXTERN xdata _AT_(0xE65C) volatile BYTE USBIE             ;  // USB Int Enables +EXTERN xdata _AT_(0xE65D) volatile BYTE USBIRQ            ;  // USB Interrupt Requests +EXTERN xdata _AT_(0xE65E) volatile BYTE EPIE              ;  // Endpoint Interrupt Enables +EXTERN xdata _AT_(0xE65F) volatile BYTE EPIRQ             ;  // Endpoint Interrupt Requests +EXTERN xdata _AT_(0xE660) volatile BYTE GPIFIE            ;  // GPIF Interrupt Enable +EXTERN xdata _AT_(0xE661) volatile BYTE GPIFIRQ           ;  // GPIF Interrupt Request +EXTERN xdata _AT_(0xE662) volatile BYTE USBERRIE          ;  // USB Error Interrupt Enables +EXTERN xdata _AT_(0xE663) volatile BYTE USBERRIRQ         ;  // USB Error Interrupt Requests +EXTERN xdata _AT_(0xE664) volatile BYTE ERRCNTLIM         ;  // USB Error counter and limit +EXTERN xdata _AT_(0xE665) volatile BYTE CLRERRCNT         ;  // Clear Error Counter EC[3..0] +EXTERN xdata _AT_(0xE666) volatile BYTE INT2IVEC          ;  // Interupt 2 (USB) Autovector +EXTERN xdata _AT_(0xE667) volatile BYTE INT4IVEC          ;  // Interupt 4 (FIFOS & GPIF) Autovector +EXTERN xdata _AT_(0xE668) volatile BYTE INTSETUP          ;  // Interrupt 2&4 Setup + +// Input/Output + +EXTERN xdata _AT_(0xE670) volatile BYTE PORTACFG          ;  // I/O PORTA Alternate Configuration +EXTERN xdata _AT_(0xE671) volatile BYTE PORTCCFG          ;  // I/O PORTC Alternate Configuration +EXTERN xdata _AT_(0xE672) volatile BYTE PORTECFG          ;  // I/O PORTE Alternate Configuration +EXTERN xdata _AT_(0xE678) volatile BYTE I2CS              ;  // Control & Status +EXTERN xdata _AT_(0xE679) volatile BYTE I2DAT             ;  // Data +EXTERN xdata _AT_(0xE67A) volatile BYTE I2CTL             ;  // I2C Control +EXTERN xdata _AT_(0xE67B) volatile BYTE XAUTODAT1         ;  // Autoptr1 MOVX access +EXTERN xdata _AT_(0xE67C) volatile BYTE XAUTODAT2         ;  // Autoptr2 MOVX access + +#define EXTAUTODAT1 XAUTODAT1 +#define EXTAUTODAT2 XAUTODAT2 + +// USB Control + +EXTERN xdata _AT_(0xE680) volatile BYTE USBCS             ;  // USB Control & Status +EXTERN xdata _AT_(0xE681) volatile BYTE SUSPEND           ;  // Put chip into suspend +EXTERN xdata _AT_(0xE682) volatile BYTE WAKEUPCS          ;  // Wakeup source and polarity +EXTERN xdata _AT_(0xE683) volatile BYTE TOGCTL            ;  // Toggle Control +EXTERN xdata _AT_(0xE684) volatile BYTE USBFRAMEH         ;  // USB Frame count H +EXTERN xdata _AT_(0xE685) volatile BYTE USBFRAMEL         ;  // USB Frame count L +EXTERN xdata _AT_(0xE686) volatile BYTE MICROFRAME        ;  // Microframe count, 0-7 +EXTERN xdata _AT_(0xE687) volatile BYTE FNADDR            ;  // USB Function address + +// Endpoints + +EXTERN xdata _AT_(0xE68A) volatile BYTE EP0BCH            ;  // Endpoint 0 Byte Count H +EXTERN xdata _AT_(0xE68B) volatile BYTE EP0BCL            ;  // Endpoint 0 Byte Count L +EXTERN xdata _AT_(0xE68D) volatile BYTE EP1OUTBC          ;  // Endpoint 1 OUT Byte Count +EXTERN xdata _AT_(0xE68F) volatile BYTE EP1INBC           ;  // Endpoint 1 IN Byte Count +EXTERN xdata _AT_(0xE690) volatile BYTE EP2BCH            ;  // Endpoint 2 Byte Count H +EXTERN xdata _AT_(0xE691) volatile BYTE EP2BCL            ;  // Endpoint 2 Byte Count L +EXTERN xdata _AT_(0xE694) volatile BYTE EP4BCH            ;  // Endpoint 4 Byte Count H +EXTERN xdata _AT_(0xE695) volatile BYTE EP4BCL            ;  // Endpoint 4 Byte Count L +EXTERN xdata _AT_(0xE698) volatile BYTE EP6BCH            ;  // Endpoint 6 Byte Count H +EXTERN xdata _AT_(0xE699) volatile BYTE EP6BCL            ;  // Endpoint 6 Byte Count L +EXTERN xdata _AT_(0xE69C) volatile BYTE EP8BCH            ;  // Endpoint 8 Byte Count H +EXTERN xdata _AT_(0xE69D) volatile BYTE EP8BCL            ;  // Endpoint 8 Byte Count L +EXTERN xdata _AT_(0xE6A0) volatile BYTE EP0CS             ;  // Endpoint  Control and Status +EXTERN xdata _AT_(0xE6A1) volatile BYTE EP1OUTCS          ;  // Endpoint 1 OUT Control and Status +EXTERN xdata _AT_(0xE6A2) volatile BYTE EP1INCS           ;  // Endpoint 1 IN Control and Status +EXTERN xdata _AT_(0xE6A3) volatile BYTE EP2CS             ;  // Endpoint 2 Control and Status +EXTERN xdata _AT_(0xE6A4) volatile BYTE EP4CS             ;  // Endpoint 4 Control and Status +EXTERN xdata _AT_(0xE6A5) volatile BYTE EP6CS             ;  // Endpoint 6 Control and Status +EXTERN xdata _AT_(0xE6A6) volatile BYTE EP8CS             ;  // Endpoint 8 Control and Status +EXTERN xdata _AT_(0xE6A7) volatile BYTE EP2FIFOFLGS       ;  // Endpoint 2 Flags +EXTERN xdata _AT_(0xE6A8) volatile BYTE EP4FIFOFLGS       ;  // Endpoint 4 Flags +EXTERN xdata _AT_(0xE6A9) volatile BYTE EP6FIFOFLGS       ;  // Endpoint 6 Flags +EXTERN xdata _AT_(0xE6AA) volatile BYTE EP8FIFOFLGS       ;  // Endpoint 8 Flags +EXTERN xdata _AT_(0xE6AB) volatile BYTE EP2FIFOBCH        ;  // EP2 FIFO total byte count H +EXTERN xdata _AT_(0xE6AC) volatile BYTE EP2FIFOBCL        ;  // EP2 FIFO total byte count L +EXTERN xdata _AT_(0xE6AD) volatile BYTE EP4FIFOBCH        ;  // EP4 FIFO total byte count H +EXTERN xdata _AT_(0xE6AE) volatile BYTE EP4FIFOBCL        ;  // EP4 FIFO total byte count L +EXTERN xdata _AT_(0xE6AF) volatile BYTE EP6FIFOBCH        ;  // EP6 FIFO total byte count H +EXTERN xdata _AT_(0xE6B0) volatile BYTE EP6FIFOBCL        ;  // EP6 FIFO total byte count L +EXTERN xdata _AT_(0xE6B1) volatile BYTE EP8FIFOBCH        ;  // EP8 FIFO total byte count H +EXTERN xdata _AT_(0xE6B2) volatile BYTE EP8FIFOBCL        ;  // EP8 FIFO total byte count L +EXTERN xdata _AT_(0xE6B3) volatile BYTE SUDPTRH           ;  // Setup Data Pointer high address byte +EXTERN xdata _AT_(0xE6B4) volatile BYTE SUDPTRL           ;  // Setup Data Pointer low address byte +EXTERN xdata _AT_(0xE6B5) volatile BYTE SUDPTRCTL         ;  // Setup Data Pointer Auto Mode +EXTERN xdata _AT_(0xE6B8) volatile BYTE SETUPDAT[8]       ;  // 8 bytes of SETUP data + +// GPIF + +EXTERN xdata _AT_(0xE6C0) volatile BYTE GPIFWFSELECT      ;  // Waveform Selector +EXTERN xdata _AT_(0xE6C1) volatile BYTE GPIFIDLECS        ;  // GPIF Done, GPIF IDLE drive mode +EXTERN xdata _AT_(0xE6C2) volatile BYTE GPIFIDLECTL       ;  // Inactive Bus, CTL states +EXTERN xdata _AT_(0xE6C3) volatile BYTE GPIFCTLCFG        ;  // CTL OUT pin drive +EXTERN xdata _AT_(0xE6C4) volatile BYTE GPIFADRH          ;  // GPIF Address H +EXTERN xdata _AT_(0xE6C5) volatile BYTE GPIFADRL          ;  // GPIF Address L + +EXTERN xdata _AT_(0xE6CE) volatile BYTE GPIFTCB3          ;  // GPIF Transaction Count Byte 3 +EXTERN xdata _AT_(0xE6CF) volatile BYTE GPIFTCB2          ;  // GPIF Transaction Count Byte 2 +EXTERN xdata _AT_(0xE6D0) volatile BYTE GPIFTCB1          ;  // GPIF Transaction Count Byte 1 +EXTERN xdata _AT_(0xE6D1) volatile BYTE GPIFTCB0          ;  // GPIF Transaction Count Byte 0 + +#define EP2GPIFTCH GPIFTCB1   // these are here for backwards compatibility +#define EP2GPIFTCL GPIFTCB0   // before REVE silicon (ie. REVB and REVD) +#define EP4GPIFTCH GPIFTCB1   // these are here for backwards compatibility +#define EP4GPIFTCL GPIFTCB0   // before REVE silicon (ie. REVB and REVD) +#define EP6GPIFTCH GPIFTCB1   // these are here for backwards compatibility +#define EP6GPIFTCL GPIFTCB0   // before REVE silicon (ie. REVB and REVD) +#define EP8GPIFTCH GPIFTCB1   // these are here for backwards compatibility +#define EP8GPIFTCL GPIFTCB0   // before REVE silicon (ie. REVB and REVD) + +// EXTERN xdata volatile BYTE EP2GPIFTCH     _AT_ 0xE6D0;  // EP2 GPIF Transaction Count High +// EXTERN xdata volatile BYTE EP2GPIFTCL     _AT_ 0xE6D1;  // EP2 GPIF Transaction Count Low +EXTERN xdata _AT_(0xE6D2) volatile BYTE EP2GPIFFLGSEL     ;  // EP2 GPIF Flag select +EXTERN xdata _AT_(0xE6D3) volatile BYTE EP2GPIFPFSTOP     ;  // Stop GPIF EP2 transaction on prog. flag +EXTERN xdata _AT_(0xE6D4) volatile BYTE EP2GPIFTRIG       ;  // EP2 FIFO Trigger +// EXTERN xdata volatile BYTE EP4GPIFTCH     _AT_ 0xE6D8;  // EP4 GPIF Transaction Count High +// EXTERN xdata volatile BYTE EP4GPIFTCL     _AT_ 0xE6D9;  // EP4 GPIF Transactionr Count Low +EXTERN xdata _AT_(0xE6DA) volatile BYTE EP4GPIFFLGSEL     ;  // EP4 GPIF Flag select +EXTERN xdata _AT_(0xE6DB) volatile BYTE EP4GPIFPFSTOP     ;  // Stop GPIF EP4 transaction on prog. flag +EXTERN xdata _AT_(0xE6DC) volatile BYTE EP4GPIFTRIG       ;  // EP4 FIFO Trigger +// EXTERN xdata volatile BYTE EP6GPIFTCH     _AT_ 0xE6E0;  // EP6 GPIF Transaction Count High +// EXTERN xdata volatile BYTE EP6GPIFTCL     _AT_ 0xE6E1;  // EP6 GPIF Transaction Count Low +EXTERN xdata _AT_(0xE6E2) volatile BYTE EP6GPIFFLGSEL     ;  // EP6 GPIF Flag select +EXTERN xdata _AT_(0xE6E3) volatile BYTE EP6GPIFPFSTOP     ;  // Stop GPIF EP6 transaction on prog. flag +EXTERN xdata _AT_(0xE6E4) volatile BYTE EP6GPIFTRIG       ;  // EP6 FIFO Trigger +// EXTERN xdata volatile BYTE EP8GPIFTCH     _AT_ 0xE6E8;  // EP8 GPIF Transaction Count High +// EXTERN xdata volatile BYTE EP8GPIFTCL     _AT_ 0xE6E9;  // EP8GPIF Transaction Count Low +EXTERN xdata _AT_(0xE6EA) volatile BYTE EP8GPIFFLGSEL     ;  // EP8 GPIF Flag select +EXTERN xdata _AT_(0xE6EB) volatile BYTE EP8GPIFPFSTOP     ;  // Stop GPIF EP8 transaction on prog. flag +EXTERN xdata _AT_(0xE6EC) volatile BYTE EP8GPIFTRIG       ;  // EP8 FIFO Trigger +EXTERN xdata _AT_(0xE6F0) volatile BYTE XGPIFSGLDATH      ;  // GPIF Data H (16-bit mode only) +EXTERN xdata _AT_(0xE6F1) volatile BYTE XGPIFSGLDATLX     ;  // Read/Write GPIF Data L & trigger transac +EXTERN xdata _AT_(0xE6F2) volatile BYTE XGPIFSGLDATLNOX   ;  // Read GPIF Data L, no transac trigger +EXTERN xdata _AT_(0xE6F3) volatile BYTE GPIFREADYCFG      ;  // Internal RDY,Sync/Async, RDY5CFG +EXTERN xdata _AT_(0xE6F4) volatile BYTE GPIFREADYSTAT     ;  // RDY pin states +EXTERN xdata _AT_(0xE6F5) volatile BYTE GPIFABORT         ;  // Abort GPIF cycles + +// UDMA + +EXTERN xdata _AT_(0xE6C6) volatile BYTE FLOWSTATE         ; //Defines GPIF flow state +EXTERN xdata _AT_(0xE6C7) volatile BYTE FLOWLOGIC         ; //Defines flow/hold decision criteria +EXTERN xdata _AT_(0xE6C8) volatile BYTE FLOWEQ0CTL        ; //CTL states during active flow state +EXTERN xdata _AT_(0xE6C9) volatile BYTE FLOWEQ1CTL        ; //CTL states during hold flow state +EXTERN xdata _AT_(0xE6CA) volatile BYTE FLOWHOLDOFF       ; +EXTERN xdata _AT_(0xE6CB) volatile BYTE FLOWSTB           ; //CTL/RDY Signal to use as master data strobe  +EXTERN xdata _AT_(0xE6CC) volatile BYTE FLOWSTBEDGE       ; //Defines active master strobe edge +EXTERN xdata _AT_(0xE6CD) volatile BYTE FLOWSTBHPERIOD    ; //Half Period of output master strobe +EXTERN xdata _AT_(0xE60C) volatile BYTE GPIFHOLDAMOUNT    ; //Data delay shift  +EXTERN xdata _AT_(0xE67D) volatile BYTE UDMACRCH          ; //CRC Upper byte +EXTERN xdata _AT_(0xE67E) volatile BYTE UDMACRCL          ; //CRC Lower byte +EXTERN xdata _AT_(0xE67F) volatile BYTE UDMACRCQUAL       ; //UDMA In only, host terminated use only + + +// Debug/Test + +EXTERN xdata _AT_(0xE6F8) volatile BYTE DBUG              ;  // Debug +EXTERN xdata _AT_(0xE6F9) volatile BYTE TESTCFG           ;  // Test configuration +EXTERN xdata _AT_(0xE6FA) volatile BYTE USBTEST           ;  // USB Test Modes +EXTERN xdata _AT_(0xE6FB) volatile BYTE CT1               ;  // Chirp Test--Override +EXTERN xdata _AT_(0xE6FC) volatile BYTE CT2               ;  // Chirp Test--FSM +EXTERN xdata _AT_(0xE6FD) volatile BYTE CT3               ;  // Chirp Test--Control Signals +EXTERN xdata _AT_(0xE6FE) volatile BYTE CT4               ;  // Chirp Test--Inputs + +// Endpoint Buffers + +EXTERN xdata _AT_(0xE740) volatile BYTE EP0BUF[64]        ;  // EP0 IN-OUT buffer +EXTERN xdata _AT_(0xE780) volatile BYTE EP1OUTBUF[64]     ;  // EP1-OUT buffer +EXTERN xdata _AT_(0xE7C0) volatile BYTE EP1INBUF[64]      ;  // EP1-IN buffer +EXTERN xdata _AT_(0xF000) volatile BYTE EP2FIFOBUF[1024]  ;  // 512/1024-byte EP2 buffer (IN or OUT) +EXTERN xdata _AT_(0xF400) volatile BYTE EP4FIFOBUF[1024]  ;  // 512 byte EP4 buffer (IN or OUT) +EXTERN xdata _AT_(0xF800) volatile BYTE EP6FIFOBUF[1024]  ;  // 512/1024-byte EP6 buffer (IN or OUT) +EXTERN xdata _AT_(0xFC00) volatile BYTE EP8FIFOBUF[1024]  ;  // 512 byte EP8 buffer (IN or OUT) + +#undef EXTERN +#undef _AT_ + +/*----------------------------------------------------------------------------- +   Special Function Registers (SFRs) +   The byte registers and bits defined in the following list are based +   on the Synopsis definition of the 8051 Special Function Registers for EZ-USB.  +    If you modify the register definitions below, please regenerate the file  +    "ezregs.inc" which includes the same basic information for assembly inclusion. +-----------------------------------------------------------------------------*/ + +sfr at 0x80 IOA; +sfr at 0x81 SP; +sfr at 0x82 DPL; +sfr at 0x83 DPH; +sfr at 0x84 DPL1; +sfr at 0x85 DPH1; +sfr at 0x86 DPS; +         /*  DPS  */ +         sbit at 0x86+0 SEL; +sfr at 0x87 PCON;   /*  PCON  */ +         //sbit IDLE   = 0x87+0; +         //sbit STOP   = 0x87+1; +         //sbit GF0    = 0x87+2; +         //sbit GF1    = 0x87+3; +         //sbit SMOD0  = 0x87+7; +sfr at 0x88 TCON; +         /*  TCON  */ +         sbit at 0x88+0 IT0; +         sbit at 0x88+1 IE0; +         sbit at 0x88+2 IT1; +         sbit at 0x88+3 IE1; +         sbit at 0x88+4 TR0; +         sbit at 0x88+5 TF0; +         sbit at 0x88+6 TR1; +         sbit at 0x88+7 TF1; +sfr at 0x89 TMOD; +         /*  TMOD  */ +         //sbit M00    = 0x89+0; +         //sbit M10    = 0x89+1; +         //sbit CT0    = 0x89+2; +         //sbit GATE0  = 0x89+3; +         //sbit M01    = 0x89+4; +         //sbit M11    = 0x89+5; +         //sbit CT1    = 0x89+6; +         //sbit GATE1  = 0x89+7; +sfr at 0x8A TL0; +sfr at 0x8B TL1; +sfr at 0x8C TH0; +sfr at 0x8D TH1; +sfr at 0x8E CKCON; +         /*  CKCON  */ +         //sbit MD0    = 0x89+0; +         //sbit MD1    = 0x89+1; +         //sbit MD2    = 0x89+2; +         //sbit T0M    = 0x89+3; +         //sbit T1M    = 0x89+4; +         //sbit T2M    = 0x89+5; +// sfr at 0x8F SPC_FNC; // Was WRS in Reg320 +         /*  CKCON  */ +         //sbit WRS    = 0x8F+0; +sfr at 0x90 IOB; +sfr at 0x91 EXIF; // EXIF Bit Values differ from Reg320 +         /*  EXIF  */ +         //sbit USBINT = 0x91+4; +         //sbit I2CINT = 0x91+5; +         //sbit IE4    = 0x91+6; +         //sbit IE5    = 0x91+7; +sfr at 0x92 MPAGE; +sfr at 0x98 SCON0; +         /*  SCON0  */ +         sbit at 0x98+0 RI; +         sbit at 0x98+1 TI; +         sbit at 0x98+2 RB8; +         sbit at 0x98+3 TB8; +         sbit at 0x98+4 REN; +         sbit at 0x98+5 SM2; +         sbit at 0x98+6 SM1; +         sbit at 0x98+7 SM0; +sfr at 0x99 SBUF0; + +sfr at 0x9A APTR1H; +sfr at 0x9B APTR1L; +sfr at 0x9C AUTODAT1;  +sfr at 0x9D AUTOPTRH2; +sfr at 0x9E AUTOPTRL2;  +sfr at 0x9F AUTODAT2; +sfr at 0xA0 IOC; +sfr at 0xA1 INT2CLR; +sfr at 0xA2 INT4CLR; + +#define	AUTOPTRH1	APTR1H +#define	AUTOPTRL1	APTR1L + +sfr at 0xA8 IE; +         /*  IE  */ +         sbit at 0xA8+0 EX0; +         sbit at 0xA8+1 ET0; +         sbit at 0xA8+2 EX1; +         sbit at 0xA8+3 ET1; +         sbit at 0xA8+4 ES0; +         sbit at 0xA8+5 ET2; +         sbit at 0xA8+6 ES1; +         sbit at 0xA8+7 EA; + +sfr at 0xAA EP2468STAT; +         /* EP2468STAT */ +         //sbit EP2E   = 0xAA+0; +         //sbit EP2F   = 0xAA+1; +         //sbit EP4E   = 0xAA+2; +         //sbit EP4F   = 0xAA+3; +         //sbit EP6E   = 0xAA+4; +         //sbit EP6F   = 0xAA+5; +         //sbit EP8E   = 0xAA+6; +         //sbit EP8F   = 0xAA+7; + +sfr at 0xAB EP24FIFOFLGS; +sfr at 0xAC EP68FIFOFLGS; +sfr at 0xAF AUTOPTRSETUP; +            /* AUTOPTRSETUP */ +            // sbit EXTACC  = 0xAF+0; +            // sbit APTR1FZ = 0xAF+1; +            // sbit APTR2FZ = 0xAF+2; + +sfr at 0xB0 IOD; +sfr at 0xB1 IOE; +sfr at 0xB2 OEA; +sfr at 0xB3 OEB; +sfr at 0xB4 OEC; +sfr at 0xB5 OED; +sfr at 0xB6 OEE; + +sfr at 0xB8 IP; +         /*  IP  */ +         sbit at 0xB8+0 PX0; +         sbit at 0xB8+1 PT0; +         sbit at 0xB8+2 PX1; +         sbit at 0xB8+3 PT1; +         sbit at 0xB8+4 PS0; +         sbit at 0xB8+5 PT2; +         sbit at 0xB8+6 PS1; + +sfr at 0xBA EP01STAT; +sfr at 0xBB GPIFTRIG; +                 +sfr at 0xBD GPIFSGLDATH; +sfr at 0xBE GPIFSGLDATLX; +sfr at 0xBF GPIFSGLDATLNOX; + +sfr at 0xC0 SCON1; +         /*  SCON1  */ +         sbit at 0xC0+0 RI1; +         sbit at 0xC0+1 TI1; +         sbit at 0xC0+2 RB81; +         sbit at 0xC0+3 TB81; +         sbit at 0xC0+4 REN1; +         sbit at 0xC0+5 SM21; +         sbit at 0xC0+6 SM11; +         sbit at 0xC0+7 SM01; +sfr at 0xC1 SBUF1; +sfr at 0xC8 T2CON; +         /*  T2CON  */ +	 sbit at 0xC8+0 CP_RL2; +	 sbit at 0xC8+1 C_T2; +         sbit at 0xC8+2 TR2; +         sbit at 0xC8+3 EXEN2; +         sbit at 0xC8+4 TCLK; +         sbit at 0xC8+5 RCLK; +         sbit at 0xC8+6 EXF2; +         sbit at 0xC8+7 TF2; +sfr at 0xCA RCAP2L; +sfr at 0xCB RCAP2H; +sfr at 0xCC TL2; +sfr at 0xCD TH2; +sfr at 0xD0 PSW; +         /*  PSW  */ +         sbit at 0xD0+0 P; +         sbit at 0xD0+1 FL; +         sbit at 0xD0+2 OV; +         sbit at 0xD0+3 RS0; +         sbit at 0xD0+4 RS1; +         sbit at 0xD0+5 F0; +         sbit at 0xD0+6 AC; +         sbit at 0xD0+7 CY; +sfr at 0xD8 EICON; // Was WDCON in DS80C320 EICON; Bit Values differ from Reg320 +         /*  EICON  */ +         sbit at 0xD8+3 INT6; +         sbit at 0xD8+4 RESI; +         sbit at 0xD8+5 ERESI; +         sbit at 0xD8+7 SMOD1; +sfr at 0xE0 ACC; +sfr at 0xE8 EIE; // EIE Bit Values differ from Reg320 +                        /*  EIE  */ +         sbit at 0xE8+0 EIUSB; +         sbit at 0xE8+1 EI2C; +         sbit at 0xE8+2 EIEX4; +         sbit at 0xE8+3 EIEX5; +         sbit at 0xE8+4 EIEX6; +sfr at 0xF0 B; +sfr at 0xF8 EIP; // EIP Bit Values differ from Reg320 +                        /*  EIP  */ +         sbit at 0xF8+0 PUSB; +         sbit at 0xF8+1 PI2C; +         sbit at 0xF8+2 EIPX4; +         sbit at 0xF8+3 EIPX5; +         sbit at 0xF8+4 EIPX6; + +/*----------------------------------------------------------------------------- +   Bit Masks +-----------------------------------------------------------------------------*/ + +#define bmBIT0	1 +#define bmBIT1	2 +#define bmBIT2	4 +#define bmBIT3	8 +#define bmBIT4	16 +#define bmBIT5	32 +#define bmBIT6	64 +#define bmBIT7	128 + +/* CPU Control & Status Register (CPUCS) */ +#define bmPRTCSTB    bmBIT5 +#define bmCLKSPD     (bmBIT4 | bmBIT3) +#define bmCLKSPD1    bmBIT4 +#define bmCLKSPD0    bmBIT3 +#define bmCLKINV     bmBIT2 +#define bmCLKOE      bmBIT1 +#define bm8051RES    bmBIT0 +/* Port Alternate Configuration Registers */ +/* Port A (PORTACFG) */ +#define bmFLAGD      bmBIT7 +#define bmINT1       bmBIT1 +#define bmINT0       bmBIT0 +/* Port C (PORTCCFG) */ +#define bmGPIFA7     bmBIT7 +#define bmGPIFA6     bmBIT6 +#define bmGPIFA5     bmBIT5 +#define bmGPIFA4     bmBIT4 +#define bmGPIFA3     bmBIT3 +#define bmGPIFA2     bmBIT2 +#define bmGPIFA1     bmBIT1 +#define bmGPIFA0     bmBIT0 +/* Port E (PORTECFG) */ +#define bmGPIFA8     bmBIT7 +#define bmT2EX       bmBIT6 +#define bmINT6       bmBIT5 +#define bmRXD1OUT    bmBIT4 +#define bmRXD0OUT    bmBIT3 +#define bmT2OUT      bmBIT2 +#define bmT1OUT      bmBIT1 +#define bmT0OUT      bmBIT0 + +/* I2C Control & Status Register (I2CS) */ +#define bmSTART      bmBIT7 +#define bmSTOP       bmBIT6 +#define bmLASTRD     bmBIT5 +#define bmID         (bmBIT4 | bmBIT3) +#define bmBERR       bmBIT2 +#define bmACK        bmBIT1 +#define bmDONE       bmBIT0 +/* I2C Control Register (I2CTL) */ +#define bmSTOPIE     bmBIT1 +#define bm400KHZ     bmBIT0 +/* Interrupt 2 (USB) Autovector Register (INT2IVEC) */ +#define bmIV4        bmBIT6 +#define bmIV3        bmBIT5 +#define bmIV2        bmBIT4 +#define bmIV1        bmBIT3 +#define bmIV0        bmBIT2 +/* USB Interrupt Request & Enable Registers (USBIE/USBIRQ) */ +#define bmEP0ACK     bmBIT6 +#define bmHSGRANT    bmBIT5 +#define bmURES       bmBIT4 +#define bmSUSP       bmBIT3 +#define bmSUTOK      bmBIT2 +#define bmSOF        bmBIT1 +#define bmSUDAV      bmBIT0 +/* Breakpoint register (BREAKPT) */ +#define bmBREAK      bmBIT3 +#define bmBPPULSE    bmBIT2 +#define bmBPEN       bmBIT1 +/* Interrupt 2 & 4 Setup (INTSETUP) */ +#define bmAV2EN      bmBIT3 +#define bmINT4IN     bmBIT1 +#define bmAV4EN      bmBIT0 +/* USB Control & Status Register (USBCS) */ +#define bmHSM        bmBIT7 +#define bmDISCON     bmBIT3 +#define bmNOSYNSOF   bmBIT2 +#define bmRENUM      bmBIT1 +#define bmSIGRESUME  bmBIT0 +/* Wakeup Control and Status Register (WAKEUPCS) */ +#define bmWU2        bmBIT7 +#define bmWU         bmBIT6 +#define bmWU2POL     bmBIT5 +#define bmWUPOL      bmBIT4 +#define bmDPEN       bmBIT2 +#define bmWU2EN      bmBIT1 +#define bmWUEN       bmBIT0 +/* End Point 0 Control & Status Register (EP0CS) */ +#define bmHSNAK      bmBIT7 +/* End Point 0-1 Control & Status Registers (EP0CS/EP1OUTCS/EP1INCS) */ +#define bmEPBUSY     bmBIT1 +#define bmEPSTALL    bmBIT0 +/* End Point 2-8 Control & Status Registers (EP2CS/EP4CS/EP6CS/EP8CS) */ +#define bmNPAK       (bmBIT6 | bmBIT5 | bmBIT4) +#define bmEPFULL     bmBIT3 +#define bmEPEMPTY    bmBIT2 +/* Endpoint Status (EP2468STAT) SFR bits */ +#define bmEP8FULL    bmBIT7 +#define bmEP8EMPTY   bmBIT6 +#define bmEP6FULL    bmBIT5 +#define bmEP6EMPTY   bmBIT4 +#define bmEP4FULL    bmBIT3 +#define bmEP4EMPTY   bmBIT2 +#define bmEP2FULL    bmBIT1 +#define bmEP2EMPTY   bmBIT0 +/* SETUP Data Pointer Auto Mode (SUDPTRCTL) */ +#define bmSDPAUTO    bmBIT0 +/* Endpoint Data Toggle Control (TOGCTL) */ +#define bmQUERYTOGGLE  bmBIT7 +#define bmSETTOGGLE    bmBIT6 +#define bmRESETTOGGLE  bmBIT5 +#define bmTOGCTLEPMASK bmBIT3 | bmBIT2 | bmBIT1 | bmBIT0 +/* IBN (In Bulk Nak) enable and request bits (IBNIE/IBNIRQ) */ +#define bmEP8IBN     bmBIT5 +#define bmEP6IBN     bmBIT4 +#define bmEP4IBN     bmBIT3 +#define bmEP2IBN     bmBIT2 +#define bmEP1IBN     bmBIT1 +#define bmEP0IBN     bmBIT0 + +/* PING-NAK enable and request bits (NAKIE/NAKIRQ) */ +#define bmEP8PING     bmBIT7 +#define bmEP6PING     bmBIT6 +#define bmEP4PING     bmBIT5 +#define bmEP2PING     bmBIT4 +#define bmEP1PING     bmBIT3 +#define bmEP0PING     bmBIT2 +#define bmIBN         bmBIT0 + +/* Interface Configuration bits (IFCONFIG) */ +#define bmIFCLKSRC    bmBIT7		// set == INTERNAL +#define bm3048MHZ     bmBIT6		// set == 48 MHz +#define bmIFCLKOE     bmBIT5 +#define bmIFCLKPOL    bmBIT4 +#define bmASYNC       bmBIT3 +#define bmGSTATE      bmBIT2 +#define bmIFCFG1      bmBIT1 +#define bmIFCFG0      bmBIT0 +#define bmIFCFGMASK   (bmIFCFG0 | bmIFCFG1) +#define bmIFGPIF      bmIFCFG1 + +/* EP 2468 FIFO Configuration bits (EP2FIFOCFG,EP4FIFOCFG,EP6FIFOCFG,EP8FIFOCFG) */ +#define bmINFM       bmBIT6 +#define bmOEP        bmBIT5 +#define bmAUTOOUT    bmBIT4 +#define bmAUTOIN     bmBIT3 +#define bmZEROLENIN  bmBIT2 +//   must be zero    bmBIT1 +#define bmWORDWIDE   bmBIT0 + +/* + * Chip Revision Control Bits (REVCTL) - used to ebable/disable revision specific features + */  +#define bmNOAUTOARM    bmBIT1	// these don't match the docs +#define bmSKIPCOMMIT   bmBIT0	// these don't match the docs + +#define	bmDYN_OUT      bmBIT1	// these do... +#define	bmENH_PKT      bmBIT0 + + +/* Fifo Reset bits (FIFORESET) */ +#define bmNAKALL       bmBIT7 + +/* Endpoint Configuration (EPxCFG) */ +#define	bmVALID		bmBIT7 +#define	bmIN		bmBIT6 +#define	bmTYPE1		bmBIT5 +#define	bmTYPE0		bmBIT4 +#define	  bmISOCHRONOUS		bmTYPE0 +#define	  bmBULK		bmTYPE1 +#define	  bmINTERRUPT	       (bmTYPE1 | bmTYPE0) +#define	bm1KBUF		bmBIT3 +#define	bmBUF1		bmBIT1 +#define	bmBUF0		bmBIT0 +#define	  bmQUADBUF		0 +#define	  bmINVALIDBUF		bmBUF0 +#define	  bmDOUBLEBUF		bmBUF1 +#define	  bmTRIPLEBUF		(bmBUF1 | bmBUF0) + +/* OUTPKTEND */ +#define	bmSKIP		bmBIT7	// low 4 bits specify which end point + +/* GPIFTRIG defs */ +#define	bmGPIF_IDLE		bmBIT7		// status bit + +#define	bmGPIF_EP2_START     	     0 +#define	bmGPIF_EP4_START             1 +#define	bmGPIF_EP6_START             2 +#define	bmGPIF_EP8_START             3 +#define	bmGPIF_READ		bmBIT2 +#define	bmGPIF_WRITE		     0 + +/* EXIF bits */ +#define	bmEXIF_USBINT		bmBIT4 +#define	bmEXIF_I2CINT		bmBIT5 +#define	bmEXIF_IE4		bmBIT6 +#define	bmEXIF_IE5		bmBIT7 + + +#endif   /* FX2REGS_H */ diff --git a/firmware/fx2/common/fx2utils.c b/firmware/fx2/common/fx2utils.c new file mode 100644 index 000000000..64ffcc896 --- /dev/null +++ b/firmware/fx2/common/fx2utils.c @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "fx2utils.h" +#include "fx2regs.h" +#include "delay.h" + +void +fx2_stall_ep0 (void) +{ +  EP0CS |= bmEPSTALL; +} + +void +fx2_reset_data_toggle (unsigned char ep) +{ +  TOGCTL = ((ep & 0x80) >> 3 | (ep & 0x0f)); +  TOGCTL |= bmRESETTOGGLE; +} + +void +fx2_renumerate (void) +{ +  USBCS |= bmDISCON | bmRENUM; + +  // mdelay (1500);		// FIXME why 1.5 seconds? +  mdelay (250);			// FIXME why 1.5 seconds? +   +  USBIRQ = 0xff;		// clear any pending USB irqs... +  EPIRQ =  0xff;		//   they're from before the renumeration + +  EXIF &= ~bmEXIF_USBINT; + +  USBCS &= ~bmDISCON;		// reconnect USB +} diff --git a/firmware/fx2/common/fx2utils.h b/firmware/fx2/common/fx2utils.h new file mode 100644 index 000000000..b184dec27 --- /dev/null +++ b/firmware/fx2/common/fx2utils.h @@ -0,0 +1,31 @@ +/* -*- c -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _FX2UTILS_H_ +#define _FX2UTILS_H_ + +void fx2_stall_ep0 (void); +void fx2_reset_data_toggle (unsigned char ep); +void fx2_renumerate (void); + + + +#endif /* _FX2UTILS_H_ */ diff --git a/firmware/fx2/common/i2c.c b/firmware/fx2/common/i2c.c new file mode 100644 index 000000000..0f238b5cf --- /dev/null +++ b/firmware/fx2/common/i2c.c @@ -0,0 +1,123 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "i2c.h" +#include "fx2regs.h" +#include <string.h> + + +// issue a stop bus cycle and wait for completion + + +// returns non-zero if successful, else 0 +unsigned char +i2c_read (unsigned char addr, xdata unsigned char *buf, unsigned char len) +{ +  volatile unsigned char	junk; +   +  if (len == 0)			// reading zero bytes always works +    return 1; +   +  while (I2CS & bmSTOP)		// wait for stop to clear +    ; + +  I2CS = bmSTART; +  I2DAT = (addr << 1) | 1;	// write address and direction (1's the read bit) + +  while ((I2CS & bmDONE) == 0) +    ; + +  if ((I2CS & bmBERR) || (I2CS & bmACK) == 0)	// no device answered... +    goto fail; + +  if (len == 1) +    I2CS |= bmLASTRD;		 + +  junk = I2DAT;			// trigger the first read cycle + +  while (--len != 0){ +    while ((I2CS & bmDONE) == 0) +      ; + +    if (I2CS & bmBERR) +      goto fail; + +    if (len == 1) +      I2CS |= bmLASTRD; +     +    *buf++ = I2DAT;		// get data, trigger another read +  } + +  // wait for final byte +   +  while ((I2CS & bmDONE) == 0) +    ; +   +  if (I2CS & bmBERR) +    goto fail; + +  I2CS |= bmSTOP; +  *buf = I2DAT; + +  return 1; + + fail: +  I2CS |= bmSTOP; +  return 0; +} + + + +// returns non-zero if successful, else 0 +unsigned char +i2c_write (unsigned char addr, xdata const unsigned char *buf, unsigned char len) +{ +  while (I2CS & bmSTOP)		// wait for stop to clear +    ; + +  I2CS = bmSTART; +  I2DAT = (addr << 1) | 0;	// write address and direction (0's the write bit) + +  while ((I2CS & bmDONE) == 0) +    ; + +  if ((I2CS & bmBERR) || (I2CS & bmACK) == 0)	// no device answered... +    goto fail; + +  while (len > 0){ +    I2DAT = *buf++; +    len--; + +    while ((I2CS & bmDONE) == 0) +      ; + +    if ((I2CS & bmBERR) || (I2CS & bmACK) == 0)	// no device answered... +      goto fail; +  } + +  I2CS |= bmSTOP; +  return 1; + + fail: +  I2CS |= bmSTOP; +  return 0; +} diff --git a/firmware/fx2/common/i2c.h b/firmware/fx2/common/i2c.h new file mode 100644 index 000000000..273526dad --- /dev/null +++ b/firmware/fx2/common/i2c.h @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _I2C_H_ +#define _I2C_H_ + +// returns non-zero if successful, else 0 +unsigned char i2c_read (unsigned char addr, xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char i2c_write (unsigned char addr, xdata const unsigned char *buf, unsigned char len); + +#endif /* _I2C_H_ */ diff --git a/firmware/fx2/common/init_gpif.c b/firmware/fx2/common/init_gpif.c new file mode 100644 index 000000000..edde919be --- /dev/null +++ b/firmware/fx2/common/init_gpif.c @@ -0,0 +1,59 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +#include "usrp_common.h" + +// These are the tables generated by the Cypress GPIF Designer + +extern const char WaveData[128]; +extern const char FlowStates[36]; +extern const char InitData[7]; + +// The tool is kind of screwed up, in that it doesn't configure some +// of the ports correctly.  We just use their tables and handle the +// initialization ourselves.  They also declare that their static +// initialized data is in xdata, which screws us too. + +void +init_gpif (void) +{ +  // we've already setup IFCONFIG before calling this... + +  GPIFABORT = 0xFF;  // abort any waveforms pending +  SYNCDELAY; +  +  GPIFREADYCFG = InitData[ 0 ]; +  GPIFCTLCFG = InitData[ 1 ]; +  GPIFIDLECS = InitData[ 2 ]; +  GPIFIDLECTL = InitData[ 3 ]; +  // Hmmm, what's InitData[ 4 ] ... +  GPIFWFSELECT = InitData[ 5 ]; +  // GPIFREADYSTAT = InitData[ 6 ];	// I think this register is read only... +  +  { +    BYTE i; +     +    for (i = 0; i < 128; i++){ +      GPIF_WAVE_DATA[i] = WaveData[i]; +    } +  } +  +  FLOWSTATE = 0;		/* ensure it's off */ +} diff --git a/firmware/fx2/common/isr.c b/firmware/fx2/common/isr.c new file mode 100644 index 000000000..05412daf5 --- /dev/null +++ b/firmware/fx2/common/isr.c @@ -0,0 +1,167 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "isr.h" +#include "fx2regs.h" +#include "syncdelay.h" + +extern xdata unsigned char _standard_interrupt_vector[]; +extern xdata unsigned char _usb_autovector[]; +extern xdata unsigned char _fifo_gpif_autovector[]; + +#define LJMP_OPCODE	0x02 + +/* + * Hook standard interrupt vector. + * + * vector_number is from the SV_<foo> list. + * addr is the address of the interrupt service routine. + */ +void  +hook_sv (unsigned char vector_number, unsigned short addr) +{ +  bit	t; +   +  // sanity checks + +  if (vector_number < SV_MIN || vector_number > SV_MAX) +    return; + +  if ((vector_number & 0x0f) != 0x03 && (vector_number & 0x0f) != 0x0b) +    return; + +  t = EA; +  EA = 0; +  _standard_interrupt_vector[vector_number] = LJMP_OPCODE; +  _standard_interrupt_vector[vector_number + 1] = addr >> 8; +  _standard_interrupt_vector[vector_number + 2] = addr & 0xff; +  EA = t; +} + +/* + * Hook usb interrupt vector. + * + * vector_number is from the UV_<foo> list. + * addr is the address of the interrupt service routine. + */ +void  +hook_uv (unsigned char vector_number, unsigned short addr) +{ +  bit	t; +   +  // sanity checks + +  if (vector_number < UV_MIN || vector_number > UV_MAX) +    return; + +  if ((vector_number & 0x3) != 0) +    return; + +  t = EA; +  EA = 0; +  _usb_autovector[vector_number] = LJMP_OPCODE; +  _usb_autovector[vector_number + 1] = addr >> 8; +  _usb_autovector[vector_number + 2] = addr & 0xff; +  EA = t; +} + +/* + * Hook fifo/gpif interrupt vector. + * + * vector_number is from the FGV_<foo> list. + * addr is the address of the interrupt service routine. + */ +void  +hook_fgv (unsigned char vector_number, unsigned short addr) +{ +  bit	t; +   +  // sanity checks + +  if (vector_number < FGV_MIN || vector_number > FGV_MAX) +    return; + +  if ((vector_number & 0x3) != 0) +    return; + +  t = EA; +  EA = 0; +  _fifo_gpif_autovector[vector_number] = LJMP_OPCODE; +  _fifo_gpif_autovector[vector_number + 1] = addr >> 8; +  _fifo_gpif_autovector[vector_number + 2] = addr & 0xff; +  EA = t; +} + +/* + * One time call to enable autovectoring for both USB and FIFO/GPIF. + * + * This disables all USB and FIFO/GPIF interrupts and clears + * any pending interrupts too.  It leaves the master USB and FIFO/GPIF + * interrupts enabled. + */ +void +setup_autovectors (void) +{ +  // disable master usb and fifo/gpif interrupt enables +  EIUSB = 0; +  EIEX4 = 0; + +  hook_sv (SV_INT_2, (unsigned short) _usb_autovector); +  hook_sv (SV_INT_4, (unsigned short) _fifo_gpif_autovector); + +  // disable all fifo interrupt enables +  SYNCDELAY; +  EP2FIFOIE = 0;	SYNCDELAY; +  EP4FIFOIE = 0;	SYNCDELAY; +  EP6FIFOIE = 0;	SYNCDELAY; +  EP8FIFOIE = 0;	SYNCDELAY; + +  // clear all pending fifo irqs	 +  EP2FIFOIRQ = 0xff;	SYNCDELAY; +  EP4FIFOIRQ = 0xff;	SYNCDELAY; +  EP6FIFOIRQ = 0xff;	SYNCDELAY; +  EP8FIFOIRQ = 0xff;	SYNCDELAY; + +  IBNIE  = 0; +  IBNIRQ = 0xff; +  NAKIE  = 0; +  NAKIRQ = 0xff; +  USBIE  = 0; +  USBIRQ = 0xff; +  EPIE   = 0; +  EPIRQ  = 0xff; +  SYNCDELAY;	GPIFIE = 0;		 +  SYNCDELAY;	GPIFIRQ = 0xff; +  USBERRIE = 0; +  USBERRIRQ = 0xff; +  CLRERRCNT = 0; +   +  INTSETUP = bmAV2EN | bmAV4EN | bmINT4IN; + +  // clear master irq's for usb and fifo/gpif +  EXIF &= ~bmEXIF_USBINT; +  EXIF &= ~bmEXIF_IE4; +   +  // enable master usb and fifo/gpif interrrupts +  EIUSB = 1; +  EIEX4 = 1; +} diff --git a/firmware/fx2/common/isr.h b/firmware/fx2/common/isr.h new file mode 100644 index 000000000..856532890 --- /dev/null +++ b/firmware/fx2/common/isr.h @@ -0,0 +1,172 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _ISR_H_ +#define _ISR_H_ + +/* + * ---------------------------------------------------------------- + *	routines for managing interrupt services routines + * ---------------------------------------------------------------- + */ + +/* + * The FX2 has three discrete sets of interrupt vectors. + * The first set is the standard 8051 vector (13 8-byte entries). + * The second set is USB interrupt autovector (32 4-byte entries). + * The third set is the FIFO/GPIF autovector (14 4-byte entries). + * + * Since all the code we're running in the FX2 is ram based, we + * forego the typical "initialize the interrupt vectors at link time" + * strategy, in favor of calls at run time that install the correct + * pointers to functions. + */ + +/* + * Standard Vector numbers + */ + +#define	SV_INT_0		0x03 +#define	SV_TIMER_0		0x0b +#define	SV_INT_1		0x13 +#define	SV_TIMER_1		0x1b +#define	SV_SERIAL_0		0x23 +#define	SV_TIMER_2		0x2b +#define	SV_RESUME		0x33 +#define	SV_SERIAL_1		0x3b +#define	SV_INT_2		0x43		// (INT_2) points at USB autovector +#define	SV_I2C			0x4b +#define	SV_INT_4		0x53		// (INT_4) points at FIFO/GPIF autovector +#define	SV_INT_5		0x5b +#define	SV_INT_6		0x63 + +#define	SV_MIN			SV_INT_0 +#define	SV_MAX			SV_INT_6 + +/* + * USB Auto Vector numbers + */ + +#define	UV_SUDAV		0x00 +#define	UV_SOF			0x04 +#define	UV_SUTOK		0x08 +#define	UV_SUSPEND		0x0c +#define	UV_USBRESET		0x10 +#define	UV_HIGHSPEED		0x14 +#define	UV_EP0ACK		0x18 +#define	UV_SPARE_1C		0x1c +#define	UV_EP0IN		0x20 +#define	UV_EP0OUT		0x24 +#define	UV_EP1IN		0x28 +#define	UV_EP1OUT		0x2c +#define	UV_EP2			0x30 +#define	UV_EP4			0x34 +#define	UV_EP6			0x38 +#define	UV_EP8			0x3c +#define	UV_IBN			0x40 +#define	UV_SPARE_44		0x44 +#define	UV_EP0PINGNAK		0x48 +#define	UV_EP1PINGNAK		0x4c +#define	UV_EP2PINGNAK		0x50 +#define	UV_EP4PINGNAK		0x54 +#define	UV_EP6PINGNAK		0x58 +#define	UV_EP8PINGNAK		0x5c +#define	UV_ERRLIMIT		0x60 +#define	UV_SPARE_64		0x64 +#define	UV_SPARE_68		0x68 +#define	UV_SPARE_6C		0x6c +#define	UV_EP2ISOERR		0x70 +#define	UV_EP4ISOERR		0x74 +#define	UV_EP6ISOERR		0x78 +#define	UV_EP8ISOERR		0x7c + +#define	UV_MIN			UV_SUDAV +#define	UV_MAX			UV_EP8ISOERR + +/* + * FIFO/GPIF Auto Vector numbers + */ + +#define	FGV_EP2PF		0x00 +#define	FGV_EP4PF		0x04 +#define	FGV_EP6PF		0x08 +#define	FGV_EP8PF		0x0c +#define	FGV_EP2EF		0x10 +#define	FGV_EP4EF		0x14 +#define	FGV_EP6EF		0x18 +#define	FGV_EP8EF		0x1c +#define	FGV_EP2FF		0x20 +#define	FGV_EP4FF		0x24 +#define	FGV_EP6FF		0x28 +#define	FGV_EP8FF		0x2c +#define	FGV_GPIFDONE		0x30 +#define	FGV_GPIFWF		0x34 + +#define	FGV_MIN			FGV_EP2PF +#define	FGV_MAX			FGV_GPIFWF + + +/* + * Hook standard interrupt vector. + * + * vector_number is from the SV_<foo> list above. + * addr is the address of the interrupt service routine. + */ +void hook_sv (unsigned char vector_number, unsigned short addr); + +/* + * Hook usb interrupt vector. + * + * vector_number is from the UV_<foo> list above. + * addr is the address of the interrupt service routine. + */ +void hook_uv (unsigned char vector_number, unsigned short addr); + +/* + * Hook fifo/gpif interrupt vector. + * + * vector_number is from the FGV_<foo> list above. + * addr is the address of the interrupt service routine. + */ +void hook_fgv (unsigned char vector_number, unsigned short addr); + +/* + * One time call to enable autovectoring for both USB and FIFO/GPIF + */ +void setup_autovectors (void); + + +/* + * Must be called in each usb interrupt handler + */ +#define	clear_usb_irq()			\ +	EXIF &= ~bmEXIF_USBINT;		\ +	INT2CLR = 0 + +/* + * Must be calledin each fifo/gpif interrupt handler + */ +#define	clear_fifo_gpif_irq()		\ +	EXIF &= ~bmEXIF_IE4;		\ +	INT4CLR = 0 + +#endif /* _ISR_H_ */ diff --git a/firmware/fx2/common/spi.c b/firmware/fx2/common/spi.c new file mode 100644 index 000000000..0c4f63d5a --- /dev/null +++ b/firmware/fx2/common/spi.c @@ -0,0 +1,472 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "spi.h" +#include "usrp_regs.h" + +static void +setup_enables (unsigned char enables) +{ +  // Software eanbles are active high. +  // Hardware enables are active low. + +  // Uhh, the CODECs are active low, but the FPGA is active high... +  enables ^= SPI_ENABLE_FPGA; + +  // KLUDGE: This code is fragile, but reasonably fast... +  // low three bits of enables go into port A +  USRP_PA = USRP_PA | (0x7 << 3);	// disable FPGA, CODEC_A, CODEC_B +  USRP_PA ^= (enables & 0x7) << 3;	// enable specified devs + +  // high four bits of enables go into port E +  USRP_PE = USRP_PE | (0xf << 4);	// disable TX_A, RX_A, TX_B, RX_B +  USRP_PE ^= (enables & 0xf0);		// enable specified devs +} + +#define disable_all()	setup_enables (0) + +void +init_spi (void) +{ +  disable_all ();		/* disable all devs	  */ +  bitS_OUT = 0;			/* idle state has CLK = 0 */ +} + +#if 0 +static unsigned char +count_bits8 (unsigned char v) +{ +  static unsigned char count4[16] = { +    0,	// 0 +    1,	// 1 +    1,	// 2 +    2,	// 3 +    1,	// 4 +    2,	// 5 +    2,	// 6 +    3,	// 7 +    1,	// 8 +    2,	// 9 +    2,	// a +    3,	// b +    2,	// c +    3,	// d +    3,	// e +    4	// f +  }; +  return count4[v & 0xf] + count4[(v >> 4) & 0xf]; +} + +#else + +static unsigned char +count_bits8 (unsigned char v) +{ +  unsigned char count = 0; +  if (v & (1 << 0)) count++; +  if (v & (1 << 1)) count++; +  if (v & (1 << 2)) count++; +  if (v & (1 << 3)) count++; +  if (v & (1 << 4)) count++; +  if (v & (1 << 5)) count++; +  if (v & (1 << 6)) count++; +  if (v & (1 << 7)) count++; +  return count; +} +#endif + +static void +write_byte_msb (unsigned char v); + +unsigned char +transact_byte_msb (unsigned char v); + +static void +write_bytes_msb (const xdata unsigned char *buf, unsigned char len); + +static void +read_bytes_msb (xdata unsigned char *buf, unsigned char len); + +static void +transact_bytes_msb (xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char +spi_read (unsigned char header_hi, unsigned char header_lo, +	  unsigned char enables, unsigned char format, +	  xdata unsigned char *buf, unsigned char len) +{ +  if (count_bits8 (enables) > 1) +    return 0;		// error, too many enables set + +  setup_enables (enables); + +  if (format & SPI_FMT_LSB){		// order: LSB +#if 1 +    return 0;		// error, not implemented +#else +    switch (format & SPI_FMR_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_lsb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_lsb (header_lo); +      write_byte_lsb (header_hi); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      read_bytes_lsb (buf, len); +#endif +  } + +  else {		// order: MSB + +    switch (format & SPI_FMT_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_msb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_msb (header_hi); +      write_byte_msb (header_lo); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      read_bytes_msb (buf, len); +  } + +  disable_all (); +  return 1;		// success +} + + +// returns non-zero if successful, else 0 +unsigned char +spi_write (unsigned char header_hi, unsigned char header_lo, +	   unsigned char enables, unsigned char format, +	   const xdata unsigned char *buf, unsigned char len) +{ +  setup_enables (enables); + +  if (format & SPI_FMT_LSB){		// order: LSB +#if 1 +    return 0;		// error, not implemented +#else +    switch (format & SPI_FMR_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_lsb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_lsb (header_lo); +      write_byte_lsb (header_hi); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      write_bytes_lsb (buf, len); +#endif +  } + +  else {		// order: MSB + +    switch (format & SPI_FMT_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_msb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_msb (header_hi); +      write_byte_msb (header_lo); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      write_bytes_msb (buf, len); +  } + +  disable_all (); +  return 1;		// success +} + +unsigned char +spi_transact (unsigned char data0, unsigned char data1, +              unsigned char data2, unsigned char data3, +              unsigned char enables, xdata unsigned char *buf, +              unsigned char len) +{ +  if (count_bits8 (enables) > 1) +    return 0;		// error, too many enables set + +  if (len > 4) +    return 0; + +  setup_enables (enables); + +  buf[0] = data0; +  buf[1] = data1; +  buf[2] = data2;  +  buf[3] = data3;  + +  if (len != 0) +    transact_bytes_msb(buf, len); + +  disable_all (); +  return 1;		// success +} + +static unsigned char  +transact_byte_msb (unsigned char v) +{ +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN;                 // read into bottom bit +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  return v; +} + +static void +transact_bytes_msb (xdata unsigned char *buf, unsigned char len) +{ +  while (len-- != 0){ +    *buf++ = transact_byte_msb (*buf); +  } +} + +static void +write_byte_msb (unsigned char v) +{ +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; +} + +static void +write_bytes_msb (const xdata unsigned char *buf, unsigned char len) +{ +  while (len-- != 0){ +    write_byte_msb (*buf++); +  } +} + +#if 0 +/* + * This is incorrectly compiled by SDCC 2.4.0 + */ +static unsigned char +read_byte_msb (void) +{ +  unsigned char v = 0; + +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  return v; +} +#else +static unsigned char +read_byte_msb (void) _naked +{ +  _asm +	clr	a + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	mov	dpl,a +	ret +  _endasm; +} +#endif + +static void +read_bytes_msb (xdata unsigned char *buf, unsigned char len) +{ +  while (len-- != 0){ +    *buf++ = read_byte_msb (); +  } +} + diff --git a/firmware/fx2/common/spi.h b/firmware/fx2/common/spi.h new file mode 100644 index 000000000..5342b82b8 --- /dev/null +++ b/firmware/fx2/common/spi.h @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_SPI_H +#define INCLUDED_SPI_H + +#include "usrp_spi_defs.h" + +void init_spi (void);		// one time call to init + +// returns non-zero if successful, else 0 +unsigned char +spi_read (unsigned char header_hi, unsigned char header_lo, +	  unsigned char enables, unsigned char format, +	  xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char +spi_write (unsigned char header_hi, unsigned char header_lo, +	   unsigned char enables, unsigned char format, +	   const xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char +spi_transact (unsigned char data0, unsigned char data1, +              unsigned char data2, unsigned char data3, +	      unsigned char enables, xdata unsigned char *buf, +              unsigned char len); + + +#endif /* INCLUDED_SPI_H */ diff --git a/firmware/fx2/common/syncdelay.h b/firmware/fx2/common/syncdelay.h new file mode 100644 index 000000000..0af7d099f --- /dev/null +++ b/firmware/fx2/common/syncdelay.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _SYNCDELAY_H_ +#define _SYNCDELAY_H_ + +/* + * Magic delay required between access to certain xdata registers (TRM page 15-106). + * For our configuration, 48 MHz FX2 / 48 MHz IFCLK, we need three cycles.  Each + * NOP is a single cycle.... + * + * From TRM page 15-105: + * + * Under certain conditions, some read and write access to the FX2 registers must + * be separated by a "synchronization delay".  The delay is necessary only under the + * following conditions: + * + *   - between a write to any register in the 0xE600 - 0xE6FF range and a write to one + *     of the registers listed below. + * + *   - between a write to one of the registers listed below and a read from any register + *     in the 0xE600 - 0xE6FF range. + * + *   Registers which require a synchronization delay: + * + *	FIFORESET			FIFOPINPOLAR + *	INPKTEND			EPxBCH:L + *	EPxFIFOPFH:L			EPxAUTOINLENH:L + *	EPxFIFOCFG			EPxGPIFFLGSEL + *	PINFLAGSAB			PINFLAGSCD + *	EPxFIFOIE			EPxFIFOIRQ + *	GPIFIE				GPIFIRQ + *	UDMACRCH:L			GPIFADRH:L + *	GPIFTRIG			EPxGPIFTRIG + *	OUTPKTEND			REVCTL + *	GPIFTCB3			GPIFTCB2 + *	GPIFTCB1			GPIFTCB0 + */ + +/* + * FIXME ensure that the peep hole optimizer isn't screwing us + */ +#define	SYNCDELAY	_asm nop; nop; nop; _endasm +#define	NOP		_asm nop; _endasm + + +#endif /* _SYNCDELAY_H_ */ diff --git a/firmware/fx2/common/timer.c b/firmware/fx2/common/timer.c new file mode 100644 index 000000000..97e2f7cf9 --- /dev/null +++ b/firmware/fx2/common/timer.c @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "timer.h" +#include "fx2regs.h" +#include "isr.h" + +/* + * Arrange to have isr_tick_handler called at 100 Hz. + * + * The cpu clock is running at 48e6.  The input to the timer + * is 48e6 / 12 = 4e6. + * + * We arrange to have the timer overflow every 40000 clocks == 100 Hz + */ + +#define	RELOAD_VALUE	((unsigned short) -40000) + +void  +hook_timer_tick (unsigned short isr_tick_handler) +{ +  ET2 = 0;			// disable timer 2 interrupts +  hook_sv (SV_TIMER_2, isr_tick_handler); +   +  RCAP2H = RELOAD_VALUE >> 8;	// setup the auto reload value +  RCAP2L = RELOAD_VALUE; + +  T2CON = 0x04;			// interrupt on overflow; reload; run +  ET2 = 1;			// enable timer 2 interrupts +} diff --git a/firmware/fx2/common/timer.h b/firmware/fx2/common/timer.h new file mode 100644 index 000000000..3181874d5 --- /dev/null +++ b/firmware/fx2/common/timer.h @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _TIMER_H_ +#define _TIMER_H_ + +/* + * Arrange to have isr_tick_handler called at 100 Hz + */ +void hook_timer_tick (unsigned short isr_tick_handler); + +#define clear_timer_irq()  				\ +	TF2 = 0 	/* clear overflow flag */ + + +#endif /* _TIMER_H_ */ diff --git a/firmware/fx2/common/usb_common.c b/firmware/fx2/common/usb_common.c new file mode 100644 index 000000000..3b0547b2f --- /dev/null +++ b/firmware/fx2/common/usb_common.c @@ -0,0 +1,386 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usb_common.h" +#include "fx2regs.h" +#include "syncdelay.h" +#include "fx2utils.h" +#include "isr.h" +#include "usb_descriptors.h" +#include "usb_requests.h" + +extern xdata char str0[]; +extern xdata char str1[]; +extern xdata char str2[]; +extern xdata char str3[]; +extern xdata char str4[]; +extern xdata char str5[]; + + +#define	bRequestType	SETUPDAT[0] +#define	bRequest	SETUPDAT[1] +#define	wValueL		SETUPDAT[2] +#define	wValueH		SETUPDAT[3] +#define	wIndexL		SETUPDAT[4] +#define	wIndexH		SETUPDAT[5] +#define	wLengthL	SETUPDAT[6] +#define	wLengthH	SETUPDAT[7] + +#define MSB(x)	(((unsigned short) x) >> 8) +#define LSB(x)	(((unsigned short) x) & 0xff) + +volatile bit _usb_got_SUDAV; + +unsigned char	_usb_config = 0; +unsigned char	_usb_alt_setting = 0;	// FIXME really 1/interface + +xdata unsigned char *current_device_descr; +xdata unsigned char *current_devqual_descr; +xdata unsigned char *current_config_descr; +xdata unsigned char *other_config_descr; + +static void +setup_descriptors (void) +{ +  if (USBCS & bmHSM){		// high speed mode +    current_device_descr  = high_speed_device_descr; +    current_devqual_descr = high_speed_devqual_descr; +    current_config_descr  = high_speed_config_descr; +    other_config_descr    = full_speed_config_descr; +  } +  else { +    current_device_descr  = full_speed_device_descr; +    current_devqual_descr = full_speed_devqual_descr; +    current_config_descr  = full_speed_config_descr; +    other_config_descr    = high_speed_config_descr; +  } + +  // whack the type fields +  // FIXME, may not be required. +  // current_config_descr[1] = DT_CONFIG; +  // other_config_descr[1]   = DT_OTHER_SPEED; +} + +static void +isr_SUDAV (void) interrupt +{ +  clear_usb_irq (); +  _usb_got_SUDAV = 1; +} + +static void +isr_USBRESET (void) interrupt +{ +  clear_usb_irq (); +  setup_descriptors (); +} + +static void +isr_HIGHSPEED (void) interrupt +{ +  clear_usb_irq (); +  setup_descriptors (); +} + +void +usb_install_handlers (void) +{ +  setup_descriptors ();	    // ensure that they're set before use + +  hook_uv (UV_SUDAV,     (unsigned short) isr_SUDAV); +  hook_uv (UV_USBRESET,  (unsigned short) isr_USBRESET); +  hook_uv (UV_HIGHSPEED, (unsigned short) isr_HIGHSPEED); + +  USBIE = bmSUDAV | bmURES | bmHSGRANT; +} + +// On the FX2 the only plausible endpoints are 0, 1, 2, 4, 6, 8 +// This doesn't check to see that they're enabled + +unsigned char +plausible_endpoint (unsigned char ep) +{ +  ep &= ~0x80;	// ignore direction bit + +  if (ep > 8) +    return 0; + +  if (ep == 1) +    return 1; + +  return (ep & 0x1) == 0;	// must be even +} + +// return pointer to control and status register for endpoint. +// only called with plausible_endpoints + +xdata volatile unsigned char * +epcs (unsigned char ep) +{ +  if (ep == 0x01)		// ep1 has different in and out CS regs +    return EP1OUTCS; + +  if (ep == 0x81) +    return EP1INCS; + +  ep &= ~0x80;			// ignore direction bit + +  if (ep == 0x00)		// ep0 +    return EP0CS; + +  return EP2CS + (ep >> 1);	// 2, 4, 6, 8 are consecutive +} + +void +usb_handle_setup_packet (void) +{ +  _usb_got_SUDAV = 0; + +  // handle the standard requests... + +  switch (bRequestType & bmRT_TYPE_MASK){ + +  case bmRT_TYPE_CLASS: +  case bmRT_TYPE_RESERVED: +    fx2_stall_ep0 ();		// we don't handle these.  indicate error +    break; +     +  case bmRT_TYPE_VENDOR: +    // call the application code. +    // If it handles the command it returns non-zero + +    if (!app_vendor_cmd ())	 +      fx2_stall_ep0 (); +    break; + +  case bmRT_TYPE_STD: +    // these are the standard requests... + +    if ((bRequestType & bmRT_DIR_MASK) == bmRT_DIR_IN){ + +      //////////////////////////////////// +      //    handle the IN requests +      //////////////////////////////////// + +      switch (bRequest){ + +      case RQ_GET_CONFIG: +	EP0BUF[0] = _usb_config;	// FIXME app should handle +	EP0BCH = 0; +	EP0BCL = 1; +	break; +	 +      // -------------------------------- + +      case RQ_GET_INTERFACE: +	EP0BUF[0] = _usb_alt_setting;	// FIXME app should handle +	EP0BCH = 0; +	EP0BCL = 1; +	break; + +      // -------------------------------- + +      case RQ_GET_DESCR: +	switch (wValueH){ + +	case DT_DEVICE: +	  SUDPTRH = MSB (current_device_descr); +	  SUDPTRL = LSB (current_device_descr); +	  break; +	   +	case DT_DEVQUAL: +	  SUDPTRH = MSB (current_devqual_descr); +	  SUDPTRL = LSB (current_devqual_descr); +	  break; + +	case DT_CONFIG: +	  if (0 && wValueL != 1)	// FIXME only a single configuration +	    fx2_stall_ep0 (); +	  else { +	    SUDPTRH = MSB (current_config_descr); +	    SUDPTRL = LSB (current_config_descr); +	  } +	  break; + +	case DT_OTHER_SPEED: +	  if (0 && wValueL != 1)	// FIXME only a single configuration +	    fx2_stall_ep0 (); +	  else { +	    SUDPTRH = MSB (other_config_descr); +	    SUDPTRL = LSB (other_config_descr); +	  } +	  break; + +	case DT_STRING: +	  if (wValueL >= nstring_descriptors) +	    fx2_stall_ep0 (); +	  else { +	    xdata char *p = string_descriptors[wValueL]; +	    SUDPTRH = MSB (p); +	    SUDPTRL = LSB (p); +	  } +	  break; + +	default: +	  fx2_stall_ep0 ();	// invalid request +	  break; +	} +	break; +	 +      // -------------------------------- + +      case RQ_GET_STATUS: +	switch (bRequestType & bmRT_RECIP_MASK){ +	case bmRT_RECIP_DEVICE: +	  EP0BUF[0] = bmGSDA_SELF_POWERED;	// FIXME app should handle +	  EP0BUF[1] = 0; +	  EP0BCH = 0; +	  EP0BCL = 2; +	  break; + +	case bmRT_RECIP_INTERFACE: +	  EP0BUF[0] = 0; +	  EP0BUF[1] = 0; +	  EP0BCH = 0; +	  EP0BCL = 2; +	  break; + +	case bmRT_RECIP_ENDPOINT: +	  if (plausible_endpoint (wIndexL)){ +	    EP0BUF[0] = *epcs (wIndexL) & bmEPSTALL; +	    EP0BUF[1] = 0; +	    EP0BCH = 0; +	    EP0BCL = 2; +	  } +	  else +	    fx2_stall_ep0 (); +	  break; + +	default: +	  fx2_stall_ep0 (); +	  break; +	} +	break; + +      // -------------------------------- + +      case RQ_SYNCH_FRAME:	// not implemented +      default: +	fx2_stall_ep0 (); +	break; +      } +    } + +    else { + +      //////////////////////////////////// +      //    handle the OUT requests +      //////////////////////////////////// + +      switch (bRequest){ + +      case RQ_SET_CONFIG: +	_usb_config = wValueL;		// FIXME app should handle +	break; + +      case RQ_SET_INTERFACE: +	_usb_alt_setting = wValueL;	// FIXME app should handle +	break; + +      // -------------------------------- + +      case RQ_CLEAR_FEATURE: +	switch (bRequestType & bmRT_RECIP_MASK){ + +	case bmRT_RECIP_DEVICE: +	  switch (wValueL){ +	  case FS_DEV_REMOTE_WAKEUP: +	  default: +	    fx2_stall_ep0 (); +	  } +	  break; + +	case bmRT_RECIP_ENDPOINT: +	  if (wValueL == FS_ENDPOINT_HALT && plausible_endpoint (wIndexL)){ +	    *epcs (wIndexL) &= ~bmEPSTALL; +	    fx2_reset_data_toggle (wIndexL); +	  } +	  else +	    fx2_stall_ep0 (); +	  break; + +	default: +	  fx2_stall_ep0 (); +	  break; +	} +	break; + +      // -------------------------------- + +      case RQ_SET_FEATURE: +	switch (bRequestType & bmRT_RECIP_MASK){ + +	case bmRT_RECIP_DEVICE: +	  switch (wValueL){ +	  case FS_TEST_MODE: +	    // hardware handles this after we complete SETUP phase handshake +	    break; + +	  case FS_DEV_REMOTE_WAKEUP: +	  default: +	    fx2_stall_ep0 (); +	    break; +	  } +	} +	break; + +      case bmRT_RECIP_ENDPOINT: +	switch (wValueL){ +	case FS_ENDPOINT_HALT: +	  if (plausible_endpoint (wIndexL)) +	    *epcs (wIndexL) |= bmEPSTALL; +	  else +	    fx2_stall_ep0 (); +	  break; + +	default: +	  fx2_stall_ep0 (); +	  break; +	} +	break; + +      // -------------------------------- + +      case RQ_SET_ADDRESS:	// handled by fx2 hardware +      case RQ_SET_DESCR:	// not implemented +      default: +	fx2_stall_ep0 (); +      } + +    } +    break; + +  }	// bmRT_TYPE_MASK + +  // ack handshake phase of device request +  EP0CS |= bmHSNAK; +} diff --git a/firmware/fx2/common/usb_common.h b/firmware/fx2/common/usb_common.h new file mode 100644 index 000000000..ae07b236c --- /dev/null +++ b/firmware/fx2/common/usb_common.h @@ -0,0 +1,37 @@ +/* -*- c -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _USB_COMMON_H_ +#define _USB_COMMON_H_ + +extern volatile bit _usb_got_SUDAV; + +// Provided by user application to handle VENDOR commands. +// returns non-zero if it handled the command. +unsigned char app_vendor_cmd (void); + +void usb_install_handlers (void); +void usb_handle_setup_packet (void); + +#define usb_setup_packet_avail()	_usb_got_SUDAV + +#endif /* _USB_COMMON_H_ */ diff --git a/firmware/fx2/common/usb_descriptors.h b/firmware/fx2/common/usb_descriptors.h new file mode 100644 index 000000000..0b8c6212f --- /dev/null +++ b/firmware/fx2/common/usb_descriptors.h @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +extern xdata const char high_speed_device_descr[]; +extern xdata const char high_speed_devqual_descr[]; +extern xdata const char high_speed_config_descr[]; + +extern xdata const char full_speed_device_descr[]; +extern xdata const char full_speed_devqual_descr[]; +extern xdata const char full_speed_config_descr[]; + +extern xdata unsigned char nstring_descriptors; +extern xdata char * xdata string_descriptors[]; + +/* + * We patch these locations with info read from the usrp config eeprom + */ +extern xdata char usb_desc_hw_rev_binary_patch_location_0[]; +extern xdata char usb_desc_hw_rev_binary_patch_location_1[]; +extern xdata char usb_desc_hw_rev_ascii_patch_location_0[]; +extern xdata char usb_desc_serial_number_ascii[]; diff --git a/firmware/fx2/common/usb_requests.h b/firmware/fx2/common/usb_requests.h new file mode 100644 index 000000000..7a543abb0 --- /dev/null +++ b/firmware/fx2/common/usb_requests.h @@ -0,0 +1,88 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +// Standard USB requests. +// These are contained in end point 0 setup packets + + +#ifndef _USB_REQUESTS_H_ +#define _USB_REQUESTS_H_ + +// format of bmRequestType byte + +#define	bmRT_DIR_MASK		(0x1 << 7) +#define	bmRT_DIR_IN		(1 << 7) +#define	bmRT_DIR_OUT		(0 << 7) + +#define	bmRT_TYPE_MASK		(0x3 << 5) +#define	bmRT_TYPE_STD		(0 << 5) +#define	bmRT_TYPE_CLASS		(1 << 5) +#define	bmRT_TYPE_VENDOR	(2 << 5) +#define	bmRT_TYPE_RESERVED	(3 << 5) + +#define	bmRT_RECIP_MASK		(0x1f << 0) +#define	bmRT_RECIP_DEVICE	(0 << 0) +#define	bmRT_RECIP_INTERFACE	(1 << 0) +#define	bmRT_RECIP_ENDPOINT	(2 << 0) +#define	bmRT_RECIP_OTHER	(3 << 0) + + +// standard request codes (bRequest) + +#define	RQ_GET_STATUS		0 +#define	RQ_CLEAR_FEATURE	1 +#define	RQ_RESERVED_2		2 +#define	RQ_SET_FEATURE		3 +#define	RQ_RESERVED_4		4 +#define	RQ_SET_ADDRESS		5 +#define	RQ_GET_DESCR		6 +#define	RQ_SET_DESCR		7 +#define	RQ_GET_CONFIG		8 +#define	RQ_SET_CONFIG		9 +#define	RQ_GET_INTERFACE       10 +#define	RQ_SET_INTERFACE       11 +#define	RQ_SYNCH_FRAME	       12 + +// standard descriptor types + +#define	DT_DEVICE		1 +#define	DT_CONFIG		2 +#define	DT_STRING		3 +#define	DT_INTERFACE		4 +#define	DT_ENDPOINT		5 +#define	DT_DEVQUAL		6 +#define	DT_OTHER_SPEED		7 +#define	DT_INTERFACE_POWER	8 + +// standard feature selectors + +#define	FS_ENDPOINT_HALT	0	// recip: endpoint +#define	FS_DEV_REMOTE_WAKEUP	1	// recip: device +#define	FS_TEST_MODE		2	// recip: device + +// Get Status device attributes + +#define	bmGSDA_SELF_POWERED	0x01 +#define	bmGSDA_REM_WAKEUP	0x02 + + +#endif /* _USB_REQUESTS_H_ */ diff --git a/firmware/fx2/common/usrp_commands.h b/firmware/fx2/common/usrp_commands.h new file mode 100644 index 000000000..02778c7e3 --- /dev/null +++ b/firmware/fx2/common/usrp_commands.h @@ -0,0 +1,106 @@ +/*  + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2004 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +#ifndef _USRP_COMMANDS_H_ +#define _USRP_COMMANDS_H_ + +#include <usrp_interfaces.h> +#include <usrp_spi_defs.h> + +#define	MAX_EP0_PKTSIZE		       64	// max size of EP0 packet on FX2 + +// ---------------------------------------------------------------- +//			Vendor bmRequestType's +// ---------------------------------------------------------------- + +#define	VRT_VENDOR_IN			0xC0 +#define	VRT_VENDOR_OUT			0x40 + +// ---------------------------------------------------------------- +//			  USRP Vendor Requests +// +// Note that Cypress reserves [0xA0,0xAF]. +// 0xA0 is the firmware load function. +// ---------------------------------------------------------------- + + +// IN commands + +#define	VRQ_GET_STATUS			0x80 +#define		GS_TX_UNDERRUN			0	// wIndexL	// returns 1 byte +#define		GS_RX_OVERRUN			1	// wIndexL	// returns 1 byte + +#define	VRQ_I2C_READ			0x81		// wValueL: i2c address; length: how much to read + +#define	VRQ_SPI_READ			0x82		// wValue: optional header bytes +							// wIndexH:	enables +							// wIndexL:	format +							// len: how much to read + +#define	VRQ_SPI_TRANSACT		0x83		// wValueH:  OUT byte 0 +							// wValueL:  OUT byte 1 +							// wIndexH:  OUT byte 2 +							// wIndexL:  OUT byte 3  +							// wLengthH: enables  +							// wLengthL: transaction length + +// OUT commands + +#define	VRQ_SET_LED			0x01		// wValueL off/on {0,1}; wIndexL: which {0,1} + +#define	VRQ_FPGA_LOAD			0x02 +#  define	FL_BEGIN			0	// wIndexL: begin fpga programming cycle.  stalls if trouble. +#  define	FL_XFER				1	// wIndexL: xfer up to 64 bytes of data +#  define	FL_END				2	// wIndexL: end programming cycle, check for success. +							//          stalls endpoint if trouble. + +#define	VRQ_FPGA_WRITE_REG		0x03		// wIndexL: regno; data: 32-bit regval MSB first +#define	VRQ_FPGA_SET_RESET		0x04		// wValueL: {0,1} +#define	VRQ_FPGA_SET_TX_ENABLE		0x05		// wValueL: {0,1} +#define	VRQ_FPGA_SET_RX_ENABLE		0x06		// wValueL: {0,1} +// see below VRQ_FPGA_SET_{TX,RX}_RESET + +#define	VRQ_SET_SLEEP_BITS		0x07		// wValueH: mask; wValueL: bits.  set bits given by mask to bits + +#  define	SLEEP_ADC0			0x01 +#  define	SLEEP_ADC1			0x02 +#  define	SLEEP_DAC0			0x04 +#  define	SLEEP_DAC1			0x08 + +#define	VRQ_I2C_WRITE			0x08		// wValueL: i2c address; data: data + +#define	VRQ_SPI_WRITE			0x09		// wValue: optional header bytes +							// wIndexH:	enables +							// wIndexL:	format +							// len: how much to write + +#define	VRQ_FPGA_SET_TX_RESET		0x0a		// wValueL: {0, 1} +#define	VRQ_FPGA_SET_RX_RESET		0x0b		// wValueL: {0, 1} + + +// ------------------------------------------------------------------- +// we store the hashes at fixed addresses in the FX2 internal memory + +#define	  USRP_HASH_SLOT_0_ADDR			0xe1e0 +#define	  USRP_HASH_SLOT_1_ADDR			0xe1f0 + + + +#endif /* _USRP_COMMANDS_H_ */ diff --git a/firmware/fx2/common/usrp_common.h b/firmware/fx2/common/usrp_common.h new file mode 100644 index 000000000..fd203927f --- /dev/null +++ b/firmware/fx2/common/usrp_common.h @@ -0,0 +1,77 @@ +/*  + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2006 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +/* + * common defines and prototypes for USRP + * + * In comments below "TRM" refers to the EZ-USB FX2 Technical Reference Manual + */ + +#ifndef _USRPCOMMON_H_ +#define _USRPCOMMON_H_ + +#include "usrp_config.h" +#include "usrp_regs.h" +#include "syncdelay.h" + +/* + * From TRM page 15-105: + * + * Under certain conditions, some read and write access to the FX2 + * registers must be separated by a "synchronization delay".  The + * delay is necessary only under the following conditions: + * + *   - between a write to any register in the 0xE600 - 0xE6FF range  + *     and a write to one of the registers listed below. + * + *   - between a write to one of the registers listed below and a read  + *     from any register in the 0xE600 - 0xE6FF range. + * + *   Registers which require a synchronization delay: + * + *	FIFORESET			FIFOPINPOLAR + *	INPKTEND			EPxBCH:L + *	EPxFIFOPFH:L			EPxAUTOINLENH:L + *	EPxFIFOCFG			EPxGPIFFLGSEL + *	PINFLAGSAB			PINFLAGSCD + *	EPxFIFOIE			EPxFIFOIRQ + *	GPIFIE				GPIFIRQ + *	UDMACRCH:L			GPIFADRH:L + *	GPIFTRIG			EPxGPIFTRIG + *	OUTPKTEND			REVCTL + *	GPIFTCB3			GPIFTCB2 + *	GPIFTCB1			GPIFTCB0 + */ + +#define	TRUE		1 +#define	FALSE		0 + + +void init_usrp (void); +void init_gpif (void); + +void set_led_0 (unsigned char on); +void set_led_1 (unsigned char on); +void toggle_led_0 (void); +void toggle_led_1 (void); + +#define la_trace(v) + +#endif /* _USRPCOMMON_H_ */ diff --git a/firmware/fx2/common/usrp_config.h b/firmware/fx2/common/usrp_config.h new file mode 100644 index 000000000..e77f8e4c5 --- /dev/null +++ b/firmware/fx2/common/usrp_config.h @@ -0,0 +1,44 @@ +/*  + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +/* + * configuration stuff for debugging + */ + +/* + * Define to 0 for normal use of port A, i.e., FPGA control bus. + * Define to 1 to write trace to port A for scoping with logic analyzer. + */ +#define	UC_TRACE_USING_PORT_A			0 + + +/* + * Define to 0 for normal use of low 3 bits of port E, i.e., A/D, D/A SLEEP bits. + * Define to 1 to enable by default driving the GPIF state to the + * low three bits of port E. + */ +#define UC_START_WITH_GSTATE_OUTPUT_ENABLED	0 + + +/* + * Define to 1 for normal use (the board really has an FPGA on it). + * Define to 0 for debug use on board without FPGA. + */ +#define UC_BOARD_HAS_FPGA			1 diff --git a/firmware/fx2/common/usrp_globals.h b/firmware/fx2/common/usrp_globals.h new file mode 100644 index 000000000..445e9e6b4 --- /dev/null +++ b/firmware/fx2/common/usrp_globals.h @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _USRP_GLOBALS_H_ +#define _USRP_GLOBALS_H_ + +extern unsigned char g_tx_enable; +extern unsigned char g_rx_enable; +extern unsigned char g_fpga_reset; +extern unsigned char g_rx_overrun; +extern unsigned char g_tx_underrun; + + +#endif /* _USRP_GLOBALS_H_ */ diff --git a/firmware/fx2/common/usrp_i2c_addr.h b/firmware/fx2/common/usrp_i2c_addr.h new file mode 100644 index 000000000..0a4f3ea59 --- /dev/null +++ b/firmware/fx2/common/usrp_i2c_addr.h @@ -0,0 +1,78 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_USRP_I2C_ADDR_H +#define INCLUDED_USRP_I2C_ADDR_H + +// I2C addresses + +#define I2C_DEV_EEPROM	0x50		// 24LC02[45]:  7-bits 1010xxx + +#define	I2C_ADDR_BOOT	(I2C_DEV_EEPROM	| 0x0) +#define	I2C_ADDR_TX_A	(I2C_DEV_EEPROM | 0x4) +#define	I2C_ADDR_RX_A	(I2C_DEV_EEPROM | 0x5) +#define	I2C_ADDR_TX_B	(I2C_DEV_EEPROM	| 0x6) +#define	I2C_ADDR_RX_B	(I2C_DEV_EEPROM | 0x7) + + +// format of FX2 BOOT EEPROM +//	00: 0xC0	code for ``Read IDs from EEPROM'' +//	01: 0xFE	USB Vendor ID (LSB) +//	02: 0xFF	USB Vendor ID (MSB) +//	03: 0x02	USB Product ID (LSB) +//	04: 0x00	USB Product ID (MSB) +//	05: 0x01	USB Device ID (LSB)	// rev1 +//	06: 0x00	USB Device ID (MSB)	// 0 = unconfig'd (no firmware) +//	07: 0x00	option byte + + +// format of daughterboard EEPROM +//	00: 0xDB	code for ``I'm a daughterboard'' +//	01:   ..	Daughterboard ID (LSB) +//	02:   ..	Daughterboard ID (MSB) +//	03:   ..	io bits  7-0 direction (bit set if it's an output from m'board) +//	04:   ..	io bits 15-8 direction (bit set if it's an output from m'board) +//	05:   ..	ADC0 DC offset correction (LSB) +//	06:   ..	ADC0 DC offset correction (MSB) +//	07:   ..	ADC1 DC offset correction (LSB) +//	08:   ..	ADC1 DC offset correction (MSB) +// 	... +//	1f:   ..	negative of the sum of bytes [0x00, 0x1e] + +#define	DB_EEPROM_MAGIC		0x00 +#define	  DB_EEPROM_MAGIC_VALUE			0xDB +#define	DB_EEPROM_ID_LSB		0x01 +#define	DB_EEPROM_ID_MSB		0x02 +#define	DB_EEPROM_OE_LSB		0x03 +#define	DB_EEPROM_OE_MSB		0x04 +#define	DB_EEPROM_OFFSET_0_LSB		0x05	// offset correction for ADC or DAC 0 +#define	DB_EEPROM_OFFSET_0_MSB		0x06 +#define	DB_EEPROM_OFFSET_1_LSB		0x07	// offset correction for ADC or DAC 1 +#define	DB_EEPROM_OFFSET_1_MSB		0x08 +#define	DB_EEPROM_CHKSUM		0x1f + +#define	DB_EEPROM_CLEN			0x20	// length of common portion of eeprom + +#define	DB_EEPROM_CUSTOM_BASE		DB_EEPROM_CLEN	// first avail offset for +							//   daughterboard specific use + +#endif /* INCLUDED_USRP_I2C_ADDR_H */ + diff --git a/firmware/fx2/common/usrp_ids.h b/firmware/fx2/common/usrp_ids.h new file mode 100644 index 000000000..ffeb47f3c --- /dev/null +++ b/firmware/fx2/common/usrp_ids.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2006,2007 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * USB Vendor and Product IDs that we use + * + * (keep in sync with usb_descriptors.a51) + */ + +#ifndef _USRP_IDS_H_ +#define _USRP_IDS_H_ + +#define	USB_VID_CYPRESS			0x04b4 +#define	USB_PID_CYPRESS_FX2		0x8613 + + +#define	USB_VID_FSF			0xfffe	  // Free Software Folks +#define	USB_PID_FSF_EXP_0		0x0000	  // Experimental 0 +#define	USB_PID_FSF_EXP_1		0x0001	  // Experimental 1 +#define	USB_PID_FSF_USRP		0x0002	  // Universal Software Radio Peripheral +#define	USB_PID_FSF_USRP1P	0x0003	  // USRP1P +#define	USB_PID_FSF_SSRP		0x0004	  // Simple Software Radio Peripheral +#define	USB_PID_FSF_SSRP_reserved	0x0005	  // Simple Software Radio Peripheral +#define USB_PID_FSF_HPSDR               0x0006    // High Performance Software Defined Radio (Internal Boot) +#define USB_PID_FSF_HPSDR_HA    	0x0007    // High Performance Software Defined Radio (Host Assisted Boot) +#define USB_PID_FSF_QS1R	    	0x0008    // QS1R HF receiver +#define USB_PID_FSF_EZDOP	    	0x0009    // ezdop <jcorgan@aeinet.com> +#define USB_PID_FSF_BDALE_0		0x000a	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_1		0x000b	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_2		0x000c	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_3		0x000d	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_4		0x000e	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_5		0x000f	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_6		0x0010	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_7		0x0011	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_8		0x0012	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_BDALE_9		0x0013	  // Bdale Garbee <bdale@gag.com> +#define USB_PID_FSF_HPSDR_HERMES	0x0014	  // HPSDR Hermes +#define USB_PID_FSF_THINKRF		0x0015	  // Catalin Patulea <catalin.patulea@thinkrf.com> +#define USB_PID_FSF_MSA			0x0016	  // Hans de Bok <hdbok@dionaea.demon.nl> Scotty's Modular Spectrum Analyzer + +#define USB_PID_FSF_LBNL_UXO            0x0018    // http://recycle.lbl.gov/~ldoolitt/uxo/ + + +#define	USB_DID_USRP_0			0x0000	  // unconfigured rev 0 USRP +#define	USB_DID_USRP_1			0x0001	  // unconfigured rev 1 USRP +#define	USB_DID_USRP_2			0x0002	  // unconfigured rev 2 USRP + +#endif /* _USRP_IDS_H_ */ diff --git a/firmware/fx2/common/usrp_interfaces.h b/firmware/fx2/common/usrp_interfaces.h new file mode 100644 index 000000000..8666e0490 --- /dev/null +++ b/firmware/fx2/common/usrp_interfaces.h @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _USRP_INTERFACES_H_ +#define _USRP_INTERFACES_H_ + +/* + * We've now split the USRP into 3 separate interfaces. + * + * Interface 0 contains only ep0 and is used for command and status. + * Interface 1 is the Tx path and it uses ep2 OUT BULK. + * Interface 2 is the Rx path and it uses ep6 IN BULK. + */ +  +#define	USRP_CMD_INTERFACE		0 +#define	USRP_CMD_ALTINTERFACE		0 +#define	USRP_CMD_ENDPOINT		0 + +#define	USRP_TX_INTERFACE		1 +#define	USRP_TX_ALTINTERFACE		0 +#define	USRP_TX_ENDPOINT		2	// streaming data from host to FPGA + +#define	USRP_RX_INTERFACE		2 +#define	USRP_RX_ALTINTERFACE		0 +#define	USRP_RX_ENDPOINT		6	// streaming data from FPGA to host + + +#endif /* _USRP_INTERFACES_H_ */ diff --git a/firmware/fx2/common/usrp_spi_defs.h b/firmware/fx2/common/usrp_spi_defs.h new file mode 100644 index 000000000..963463ef2 --- /dev/null +++ b/firmware/fx2/common/usrp_spi_defs.h @@ -0,0 +1,86 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_USRP_SPI_DEFS_H +#define INCLUDED_USRP_SPI_DEFS_H + +/* + * defines for the VRQ_SPI_READ and VRQ_SPI_WRITE commands + * + * SPI == "Serial Port Interface".  SPI is a 3 wire bus plus a + * separate enable for each peripheral.  The common lines are SCLK, + * SDI and SDO.  The FX2 always drives SCLK and SDI, the clock and + * data lines from the FX2 to the peripheral.  When enabled, a + * peripheral may drive SDO, the data line from the peripheral to the + * FX2. + * + * The SPI_READ and SPI_WRITE commands are formatted identically. + * Each specifies which peripherals to enable, whether the bits should + * be transmistted Most Significant Bit first or Least Significant Bit + * first, the number of bytes in the optional header, and the number + * of bytes to read or write in the body. + * + * The body is limited to 64 bytes.  The optional header may contain + * 0, 1 or 2 bytes.  For an SPI_WRITE, the header bytes are + * transmitted to the peripheral followed by the the body bytes.  For + * an SPI_READ, the header bytes are transmitted to the peripheral, + * then len bytes are read back from the peripheral. + */ + +/* + * SPI_FMT_* goes in wIndexL + */ +#define SPI_FMT_xSB_MASK	(1 << 7) +#  define	SPI_FMT_LSB	(1 << 7)	// least signficant bit first +#  define	SPI_FMT_MSB	(0 << 7)	// most significant bit first +#define	SPI_FMT_HDR_MASK	(3 << 5) +#  define	SPI_FMT_HDR_0	(0 << 5)	// 0 header bytes +#  define	SPI_FMT_HDR_1	(1 << 5)	// 1 header byte +#  define	SPI_FMT_HDR_2	(2 << 5)	// 2 header bytes + +/* + * SPI_ENABLE_*  goes in wIndexH + * + * For the software interface, the enables are active high. + * For reads, it's an error to have more than one enable set. + * + * [FWIW, the hardware implements them as active low.  Don't change the + * definitions of these.  They are related to usrp_rev1_regs.h] + */ +#define	SPI_ENABLE_FPGA		0x01	// select FPGA +#define	SPI_ENABLE_CODEC_A	0x02	// select AD9862 A +#define	SPI_ENABLE_CODEC_B	0x04	// select AD9862 B +#define	SPI_ENABLE_reserved	0x08 +#define	SPI_ENABLE_TX_A		0x10	// select d'board TX A +#define	SPI_ENABLE_RX_A		0x20	// select d'board RX A +#define	SPI_ENABLE_TX_B		0x40	// select d'board TX B +#define	SPI_ENABLE_RX_B		0x80	// select d'board RX B + +/* + * If there's one header byte, it goes in wValueL. + * + * If there are two header bytes, they go in wValueH | wValueL. + * The transmit order of the bytes (and bits within them) is  + * determined by SPI_FMT_*SB + */ +  +#endif /* INCLUDED_USRP_SPI_DEFS_H */ diff --git a/firmware/fx2/common/vectors.a51 b/firmware/fx2/common/vectors.a51 new file mode 100644 index 000000000..4eec9fdbf --- /dev/null +++ b/firmware/fx2/common/vectors.a51 @@ -0,0 +1,179 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003 Free Software Foundation, Inc. +;;;  +;;; This file is part of GNU Radio +;;;  +;;; GNU Radio 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 3, or (at your option) +;;; any later version. +;;;  +;;; GNU Radio is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +;;; GNU General Public License for more details. +;;;  +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Radio; see the file COPYING.  If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. +;;;  + +;;; Interrupt vectors. + +;;; N.B. This object module must come first in the list of modules + +	.module vectors + +;;; ---------------------------------------------------------------- +;;;		  standard FX2 interrupt vectors +;;; ---------------------------------------------------------------- +	.area CSEG (CODE) +	.area GSINIT (CODE) +	.area CSEG (CODE) +__standard_interrupt_vector:: +__reset_vector:: +	ljmp	s_GSINIT +	 +	;; 13 8-byte entries.  We point them all at __isr_nop +	ljmp	__isr_nop	; 3 bytes +	.ds	5		; + 5 = 8 bytes for vector slot +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 +	ljmp	__isr_nop +	.ds	5 + +__isr_nop:: +	reti + +;;; ---------------------------------------------------------------- +;;; the FIFO/GPIF autovector.  14 4-byte entries. +;;; must start on a 128 byte boundary. +;;; ---------------------------------------------------------------- +	 +	. = __reset_vector + 0x0080 +		 +__fifo_gpif_autovector:: +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 +	ljmp	__isr_nop +	nop	 + +	 +;;; ---------------------------------------------------------------- +;;; the USB autovector.  32 4-byte entries. +;;; must start on a 256 byte boundary. +;;; ---------------------------------------------------------------- + +	. = __reset_vector + 0x0100 +	 +__usb_autovector:: +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop +	ljmp	__isr_nop +	nop diff --git a/firmware/fx2/config/CMakeASM_SDCCInformation.cmake b/firmware/fx2/config/CMakeASM_SDCCInformation.cmake new file mode 100644 index 000000000..d9f28b8d3 --- /dev/null +++ b/firmware/fx2/config/CMakeASM_SDCCInformation.cmake @@ -0,0 +1,28 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +# support for the SDCC assembler, asx8051 +SET( ASM_DIALECT "_SDCC" ) +SET( CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS a51 ) + +#i don't want to talk about it. i had such high hopes for CMake. +SET( CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <FLAGS> -plosgff <SOURCE>" "${CMAKE_COMMAND} -DFILE=<OBJECT> -DSOURCE=<SOURCE> -P ${CMAKE_SOURCE_DIR}/config/Rename.cmake") + +INCLUDE( CMakeASMInformation ) +SET( CMAKE_ASM${ASM_DIALECT}_OUTPUT_EXTENSION ".rel" ) #must go here because the include appears to overwrite it, although it shouldn't +# for future use +SET( ASM_DIALECT ) diff --git a/firmware/fx2/config/CMakeDetermineASM_SDCCCompiler.cmake b/firmware/fx2/config/CMakeDetermineASM_SDCCCompiler.cmake new file mode 100644 index 000000000..ab301b9f3 --- /dev/null +++ b/firmware/fx2/config/CMakeDetermineASM_SDCCCompiler.cmake @@ -0,0 +1,22 @@ + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +#  License text for the above reference.) + +# Find the MS assembler (masm or masm64) + +SET(ASM_DIALECT "_SDCC") + +SET(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT asx8051) + +INCLUDE(CMakeDetermineASMCompiler) +SET(ASM_DIALECT) diff --git a/firmware/fx2/config/CMakeTestASM_SDCCCompiler.cmake b/firmware/fx2/config/CMakeTestASM_SDCCCompiler.cmake new file mode 100644 index 000000000..1cb71cd9d --- /dev/null +++ b/firmware/fx2/config/CMakeTestASM_SDCCCompiler.cmake @@ -0,0 +1,23 @@ + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +#  License text for the above reference.) + +# This file is used by EnableLanguage in cmGlobalGenerator to +# determine that that selected ASM-ATT compiler can actually compile +# and link the most basic of programs.   If not, a fatal error +# is set and cmake stops processing commands and will not generate +# any makefiles or projects. + +SET(ASM_DIALECT "_SDCC") +INCLUDE(CMakeTestASMCompiler) +SET(ASM_DIALECT) diff --git a/firmware/fx2/config/Rename.cmake b/firmware/fx2/config/Rename.cmake new file mode 100644 index 000000000..36cd33527 --- /dev/null +++ b/firmware/fx2/config/Rename.cmake @@ -0,0 +1,37 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +#go and fetch the real compiler outputs because the compiler does things wrong and CMake is too damn brittle to cope +#just incidentally, why the heck does aslink look for a .lst input? why should it care? + +#first the .rel +get_filename_component(source_noext ${SOURCE} NAME_WE) +get_filename_component(source_path ${SOURCE} PATH) +set(compiled_ext .rel) +list(APPEND compiled_filepath ${source_path}/${source_noext}${compiled_ext}) +#EXECUTE_PROCESS(COMMAND echo Moving ${compiled_filepath} to ${FILE}) +EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E rename ${compiled_filepath} ${FILE}) + +#now do the same for the .lst +set(compiled_lst .lst) +get_filename_component(src_ext ${SOURCE} EXT) +get_filename_component(lst_noext ${FILE} NAME_WE) +get_filename_component(lst_path ${FILE} PATH) +list(APPEND compiled_lstpath ${source_path}/${source_noext}${compiled_lst}) +list(APPEND compiled_outputlstpath ${lst_path}/${lst_noext}${src_ext}${compiled_lst}) +#EXECUTE_PROCESS(COMMAND echo Moving ${compiled_lstpath} to ${compiled_outputlstpath}) +EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E rename ${compiled_lstpath} ${compiled_outputlstpath}) diff --git a/firmware/fx2/config/Toolchain-sdcc.cmake b/firmware/fx2/config/Toolchain-sdcc.cmake new file mode 100644 index 000000000..733d8f563 --- /dev/null +++ b/firmware/fx2/config/Toolchain-sdcc.cmake @@ -0,0 +1,32 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +# the name of the target operating system +SET(CMAKE_SYSTEM_NAME Generic) +# which compilers to use for C and C++ +SET(CMAKE_C_COMPILER sdcc) + +# here is where the target environment is located +SET(CMAKE_FIND_ROOT_PATH  /usr/bin /usr/share/sdcc) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search  +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + diff --git a/firmware/fx2/usrp1/CMakeLists.txt b/firmware/fx2/usrp1/CMakeLists.txt new file mode 100644 index 000000000..6607bc7f2 --- /dev/null +++ b/firmware/fx2/usrp1/CMakeLists.txt @@ -0,0 +1,84 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +include_directories(${CMAKE_SOURCE_DIR}/common) + +#for usrp_common.h and the regs files... +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +#now make a lib to link against +set(libusrp1_sources  +    ${CMAKE_SOURCE_DIR}/common/delay.c +    ${CMAKE_SOURCE_DIR}/common/fx2utils.c +    ${CMAKE_SOURCE_DIR}/common/i2c.c +    ${CMAKE_SOURCE_DIR}/common/init_gpif.c +    ${CMAKE_SOURCE_DIR}/common/isr.c +    ${CMAKE_SOURCE_DIR}/common/timer.c +    ${CMAKE_SOURCE_DIR}/common/usb_common.c +#    ${CMAKE_SOURCE_DIR}/common/spi.c +#    ${CMAKE_SOURCE_DIR}/common/vectors.a51 +) + +#file(GLOB libusrp1_c_sources ${CMAKE_SOURCE_DIR}/common/*.c) +#file(GLOB libusrp1_a51_sources ${CMAKE_SOURCE_DIR}/common/*.a51) +#list(APPEND libusrp1_sources ${libusrp1_c_sources} ${libusrp1_a51_sources}) + +add_library(libusrp1 STATIC ${libusrp1_sources}) + +# edit-gpif hacks up gpif.c for our purposes. no major surgery, just moving stuff around. +set(GPIF_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/gpif.c) +set(GPIF_SOURCE_OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/usrp_gpif.c) +set(GPIF_HEADER_OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/usrp_gpif_inline.h) + +add_custom_command( +        OUTPUT ${GPIF_SOURCE_OUTPUT} +        DEPENDS ${EDIT_GPIF_USRP1} +        COMMAND ${PYTHON_EXECUTABLE} ${EDIT_GPIF_USRP1} ${GPIF_SOURCE} ${GPIF_SOURCE_OUTPUT} ${GPIF_HEADER_OUTPUT} +        COMMENT "Generating ${GPIF_SOURCE_OUTPUT}" +) + +#file(GLOB usrp1_sources *.c) +set(usrp1_sources  +    ${CMAKE_SOURCE_DIR}/common/vectors.a51 +    board_specific.c  +    eeprom_io.c  +    fpga_load.c  +    fpga_rev2.c  +    usrp_common.c  +    usrp_gpif.c  +    usrp_main.c  +    usb_descriptors.a51  +    ${CMAKE_SOURCE_DIR}/common/spi.c +    ${CMAKE_SOURCE_DIR}/common/_startup.a51 +) +add_executable(usrp1_fw ${usrp1_sources}) +target_link_libraries(usrp1_fw libusrp1) + +set(eeprom1_sources +    ${CMAKE_SOURCE_DIR}/common/eeprom_boot.a51 +    ${CMAKE_SOURCE_DIR}/common/eeprom_init.c +    ${CMAKE_SOURCE_DIR}/common/_startup.a51 +) + +add_custom_target(usrp1_eeprom ALL +    DEPENDS usrp1_boot +    COMMAND objcopy -I ihex -O binary usrp1_boot.ihx usrp1_boot.bin +    COMMAND ${PYTHON_EXECUTABLE} ${BUILD_EEPROM} -r1 usrp1_boot.bin usrp1_eeprom.bin +) + +add_executable(usrp1_boot ${eeprom1_sources}) +target_link_libraries(usrp1_boot libusrp1) diff --git a/firmware/fx2/usrp1/board_specific.c b/firmware/fx2/usrp1/board_specific.c new file mode 100644 index 000000000..ef0081d84 --- /dev/null +++ b/firmware/fx2/usrp1/board_specific.c @@ -0,0 +1,113 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usrp_common.h" +#include "spi.h" + +void +set_led_0 (unsigned char on) +{ +  if (!on)			// active low +    USRP_PC |= bmPC_LED0; +  else +    USRP_PC &= ~bmPC_LED0; +} + +void  +set_led_1 (unsigned char on) +{ +  if (!on)			// active low +    USRP_PC |= bmPC_LED1; +  else +    USRP_PC &= ~bmPC_LED1; +} + +void +toggle_led_0 (void) +{ +  USRP_PC ^= bmPC_LED0; +} + +void +toggle_led_1 (void) +{ +  USRP_PC ^= bmPC_LED1; +} + +void +la_trace_init (void) +{ +} + +void +set_sleep_bits (unsigned char bits, unsigned char mask) +{ +  // NOP on usrp1 +} + +static xdata unsigned char xbuf[1]; + +void +write_9862 (unsigned char which, unsigned char regno, unsigned char value) +{ +  xbuf[0] = value; +   +  spi_write (0, regno & 0x3f, +	     which == 0 ? SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B, +	     SPI_FMT_MSB | SPI_FMT_HDR_1, +	     xbuf, 1); +} + +void +write_both_9862s (unsigned char regno, unsigned char value) +{ +  xbuf[0] = value; +   +  spi_write (0, regno & 0x3f, +	     SPI_ENABLE_CODEC_A | SPI_ENABLE_CODEC_B, +	     SPI_FMT_MSB | SPI_FMT_HDR_1, +	     xbuf, 1); +} + +#define REG_RX_PWR_DN		 1 +#define	REG_TX_PWR_DN		 8 +#define	REG_TX_MODULATOR	20 + +static void +power_down_9862s (void) +{ +  write_both_9862s (REG_RX_PWR_DN,    0x01); +  write_both_9862s (REG_TX_PWR_DN,    0x0f);	// pwr dn digital and analog_both +  write_both_9862s (REG_TX_MODULATOR, 0x00);	// coarse & fine modulators disabled +} + +void +init_board (void) +{ +  la_trace_init (); +  init_spi (); + +  USRP_PC &= ~bmPC_nRESET;	// active low reset +  USRP_PC |= bmPC_nRESET; + +  power_down_9862s (); +} diff --git a/firmware/fx2/usrp1/eeprom_io.c b/firmware/fx2/usrp1/eeprom_io.c new file mode 100644 index 000000000..9eeb53636 --- /dev/null +++ b/firmware/fx2/usrp1/eeprom_io.c @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "eeprom_io.h" +#include "i2c.h" +#include "delay.h" + +// returns non-zero if successful, else 0 +unsigned char +eeprom_read (unsigned char i2c_addr, unsigned char eeprom_offset, +	     xdata unsigned char *buf, unsigned char len) +{ +  // We setup a random read by first doing a "zero byte write". +  // Writes carry an address.  Reads use an implicit address. + +  static xdata unsigned char cmd[1]; +  cmd[0] = eeprom_offset; +  if (!i2c_write(i2c_addr, cmd, 1)) +    return 0; + +  return i2c_read(i2c_addr, buf, len); +} + + +#if 0 + +// returns non-zero if successful, else 0 +unsigned char +eeprom_write (unsigned char i2c_addr, unsigned char eeprom_offset, +	      const xdata unsigned char *buf, unsigned char len) +{ +  static xdata unsigned char cmd[2]; +  unsigned char ok; + +  while (len-- > 0){ +    cmd[0] = eeprom_offset++; +    cmd[1] = *buf++; +    ok = i2c_write(i2c_addr, cmd, 2); +    mdelay(10);		// delay 10ms worst case write time +    if (!ok) +      return 0; +  } +  return 1; +} + +#endif diff --git a/firmware/fx2/usrp1/eeprom_io.h b/firmware/fx2/usrp1/eeprom_io.h new file mode 100644 index 000000000..558017b12 --- /dev/null +++ b/firmware/fx2/usrp1/eeprom_io.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_EEPROM_IO_H +#define INCLUDED_EEPROM_IO_H + + +// returns non-zero if successful, else 0 +unsigned char +eeprom_read (unsigned char i2c_addr, unsigned char eeprom_offset, +	     xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char +eeprom_write (unsigned char i2c_addr, unsigned char eeprom_offset, +	      const xdata unsigned char *buf, unsigned char len); + + +#endif /* INCLUDED_EEPROM_IO_H */ diff --git a/firmware/fx2/usrp1/fpga_load.c b/firmware/fx2/usrp1/fpga_load.c new file mode 100644 index 000000000..c3ae9e707 --- /dev/null +++ b/firmware/fx2/usrp1/fpga_load.c @@ -0,0 +1,193 @@ +/*  + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +#include "usrp_common.h" +#include "fpga_load.h" +#include "delay.h" + +/* + * setup altera FPGA serial load (PS). + * + * On entry: + *	don't care + * + * On exit: + *	ALTERA_DCLK    = 0 + *	ALTERA_NCONFIG = 1 + *	ALTERA_NSTATUS = 1 (input) + */ +unsigned char +fpga_load_begin (void) +{ +  USRP_ALTERA_CONFIG &= ~bmALTERA_BITS;		// clear all bits (NCONFIG low) +  udelay (40);					// wait 40 us +  USRP_ALTERA_CONFIG |= bmALTERA_NCONFIG;	// set NCONFIG high + +  if (UC_BOARD_HAS_FPGA){ +    // FIXME should really cap this loop with a counter so we +    //   don't hang forever on a hardware failure. +    while ((USRP_ALTERA_CONFIG & bmALTERA_NSTATUS) == 0) // wait for NSTATUS to go high +      ; +  } + +  // ready to xfer now + +  return 1; +} + +/* + * clock out the low bit of bits. + * + * On entry: + *	ALTERA_DCLK    = 0 + *	ALTERA_NCONFIG = 1 + *	ALTERA_NSTATUS = 1 (input) + * + * On exit: + *	ALTERA_DCLK    = 0 + *	ALTERA_NCONFIG = 1 + *	ALTERA_NSTATUS = 1 (input) + */ + + +#if 0 + +static void +clock_out_config_byte (unsigned char bits) +{ +  unsigned char i; + +  // clock out configuration byte, least significant bit first + +  for (i = 0; i < 8; i++){ + +    USRP_ALTERA_CONFIG = ((USRP_ALTERA_CONFIG & ~bmALTERA_DATA0) | ((bits & 1) ? bmALTERA_DATA0 : 0)); +    USRP_ALTERA_CONFIG |= bmALTERA_DCLK;		/* set DCLK to 1 */ +    USRP_ALTERA_CONFIG &= ~bmALTERA_DCLK;		/* set DCLK to 0 */ + +    bits = bits >> 1; +  } +} +	 +#else + +static void  +clock_out_config_byte (unsigned char bits) _naked +{ +    _asm +	mov	a, dpl +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	rrc	a +	mov	_bitALTERA_DATA0,c +	setb	_bitALTERA_DCLK +	clr	_bitALTERA_DCLK +	 +	ret	 + +    _endasm; +} + +#endif + +static void +clock_out_bytes (unsigned char bytecount, +		 unsigned char xdata *p) +{ +  while (bytecount-- > 0) +    clock_out_config_byte (*p++); +} + +/* + * Transfer block of bytes from packet to FPGA serial configuration port + * + * On entry: + *	ALTERA_DCLK    = 0 + *	ALTERA_NCONFIG = 1 + *	ALTERA_NSTATUS = 1 (input) + * + * On exit: + *	ALTERA_DCLK    = 0 + *	ALTERA_NCONFIG = 1 + *	ALTERA_NSTATUS = 1 (input) + */ +unsigned char +fpga_load_xfer (xdata unsigned char *p, unsigned char bytecount) +{ +  clock_out_bytes (bytecount, p); +  return 1; +} + +/* + * check for successful load... + */ +unsigned char +fpga_load_end (void) +{ +  unsigned char status = USRP_ALTERA_CONFIG; + +  if (!UC_BOARD_HAS_FPGA)			// always true if we don't have FPGA +    return 1; + +  if ((status & bmALTERA_NSTATUS) == 0)		// failed to program +    return 0; + +  if ((status & bmALTERA_CONF_DONE) == bmALTERA_CONF_DONE) +    return 1;					// everything's cool + +  // I don't think this should happen.  It indicates that +  // programming is still in progress. + +  return 0; +} diff --git a/firmware/fx2/usrp1/fpga_rev2.c b/firmware/fx2/usrp1/fpga_rev2.c new file mode 100644 index 000000000..cca961dc4 --- /dev/null +++ b/firmware/fx2/usrp1/fpga_rev2.c @@ -0,0 +1,122 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "fpga.h" +#include "fpga_regs_common.h" +#include "usrp_common.h" +#include "usrp_globals.h" +#include "spi.h" + +unsigned char g_tx_reset = 0; +unsigned char g_rx_reset = 0; + +void +fpga_write_reg (unsigned char regno, const xdata unsigned char *regval) +{ +  spi_write (0, 0x00 | (regno & 0x7f), +	     SPI_ENABLE_FPGA, +	     SPI_FMT_MSB | SPI_FMT_HDR_1, +	     regval, 4); +} + + +static xdata unsigned char regval[4] = {0, 0, 0, 0}; + +static void +write_fpga_master_ctrl (void) +{ +  unsigned char v = 0; +  if (g_tx_enable) +    v |= bmFR_MC_ENABLE_TX; +  if (g_rx_enable) +    v |= bmFR_MC_ENABLE_RX; +  if (g_tx_reset) +    v |= bmFR_MC_RESET_TX; +  if (g_rx_reset) +    v |= bmFR_MC_RESET_RX; +  regval[3] = v; + +  fpga_write_reg (FR_MASTER_CTRL, regval); +} + +// Resets both AD9862's and the FPGA serial bus interface. + +void +fpga_set_reset (unsigned char on) +{ +  on &= 0x1; + +  if (on){ +    USRP_PC &= ~bmPC_nRESET;		// active low +    g_tx_enable = 0; +    g_rx_enable = 0; +    g_tx_reset = 0; +    g_rx_reset = 0; +  } +  else +    USRP_PC |= bmPC_nRESET; +} + +void +fpga_set_tx_enable (unsigned char on) +{ +  on &= 0x1; +  g_tx_enable = on; + +  write_fpga_master_ctrl (); + +  if (on){ +    g_tx_underrun = 0; +    fpga_clear_flags (); +  } +} + +void +fpga_set_rx_enable (unsigned char on) +{ +  on &= 0x1; +  g_rx_enable = on; +   +  write_fpga_master_ctrl (); +  if (on){ +    g_rx_overrun = 0; +    fpga_clear_flags (); +  } +} + +void +fpga_set_tx_reset (unsigned char on) +{ +  on &= 0x1; +  g_tx_reset = on; + +  write_fpga_master_ctrl (); +} + +void +fpga_set_rx_reset (unsigned char on) +{ +  on &= 0x1; +  g_rx_reset = on; +   +  write_fpga_master_ctrl (); +} diff --git a/firmware/fx2/usrp1/fpga_rev2.h b/firmware/fx2/usrp1/fpga_rev2.h new file mode 100644 index 000000000..54ec3f9fa --- /dev/null +++ b/firmware/fx2/usrp1/fpga_rev2.h @@ -0,0 +1,58 @@ +/*  + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2004 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +#ifndef INCLUDED_FPGA_REV1_H +#define INCLUDED_FPGA_REV1_H + +void fpga_set_reset (unsigned char v); +void fpga_set_tx_enable (unsigned char v); +void fpga_set_rx_enable (unsigned char v); +void fpga_set_tx_reset (unsigned char v); +void fpga_set_rx_reset (unsigned char v); + +unsigned char fpga_has_room_for_packet (void); +unsigned char fpga_has_packet_avail (void); + +#if (UC_BOARD_HAS_FPGA) +/* + * return TRUE iff FPGA internal fifo has room for 512 bytes. + */ +#define fpga_has_room_for_packet()	(GPIFREADYSTAT & bmFPGA_HAS_SPACE) + +/* + * return TRUE iff FPGA internal fifo has at least 512 bytes available. + */ +#define fpga_has_packet_avail()		(GPIFREADYSTAT & bmFPGA_PKT_AVAIL) + +#else	/* no FPGA on board.  fake it. */ + +#define fpga_has_room_for_packet()	TRUE +#define	fpga_has_packet_avail()		TRUE + +#endif + +#define	fpga_clear_flags()				\ +	do {						\ +	  USRP_PE |= bmPE_FPGA_CLR_STATUS;		\ +	  USRP_PE &= ~bmPE_FPGA_CLR_STATUS;		\ +        } while (0) + + +#endif /* INCLUDED_FPGA_REV1_H */ diff --git a/firmware/fx2/usrp1/gpif.c b/firmware/fx2/usrp1/gpif.c new file mode 100644 index 000000000..f6745a43b --- /dev/null +++ b/firmware/fx2/usrp1/gpif.c @@ -0,0 +1,292 @@ +// This program configures the General Programmable Interface (GPIF) for FX2.      +// Please do not modify sections of text which are marked as "DO NOT EDIT ...".  +//                                                                                 +// DO NOT EDIT ...                   +// GPIF Initialization               +// Interface Timing      Async         +// Internal Ready Init   IntRdy=1      +// CTL Out Tristate-able Binary        +// SingleWrite WF Select     1      +// SingleRead WF Select      0      +// FifoWrite WF Select       3      +// FifoRead WF Select        2      +// Data Bus Idle Drive   Tristate      +// END DO NOT EDIT                   +                                     +// DO NOT EDIT ...        +// GPIF Wave Names        +// Wave 0   = singlerd      +// Wave 1   = singlewr      +// Wave 2   = FIFORd        +// Wave 3   = FIFOWr        +                          +// GPIF Ctrl Outputs   Level    +// CTL 0    = WEN#     CMOS         +// CTL 1    = REN#     CMOS         +// CTL 2    = OE#      CMOS         +// CTL 3    = CLRST    CMOS         +// CTL 4    = unused   CMOS         +// CTL 5    = BOGUS    CMOS         +                                +// GPIF Rdy Inputs          +// RDY0     = EF#             +// RDY1     = FF#             +// RDY2     = unused          +// RDY3     = unused          +// RDY4     = unused          +// RDY5     = TCXpire         +// FIFOFlag = FIFOFlag        +// IntReady = IntReady        +// END DO NOT EDIT          +// DO NOT EDIT ...                                                                          +//                                                                                          +// GPIF Waveform 0: singlerd                                                                 +//                                                                                          +// Interval     0         1         2         3         4         5         6     Idle (7)  +//          _________ _________ _________ _________ _________ _________ _________ _________ +//                                                                                          +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val            +// DataMode NO Data   NO Data   NO Data   NO Data   NO Data   NO Data   NO Data             +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData            +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int              +// IF/Wait  Wait 1    Wait 1    Wait 1    Wait 1    Wait 1    Wait 1    Wait 1              +//   Term A                                                                                 +//   LFunc                                                                                  +//   Term B                                                                                 +// Branch1                                                                                  +// Branch0                                                                                  +// Re-Exec                                                                                  +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default             +// WEN#         0         0         0         0         0         0         0         0     +// REN#         0         0         0         0         0         0         0         0     +// OE#          0         0         0         0         0         0         0         0     +// CLRST        0         0         0         0         0         0         0         0     +// unused       0         0         0         0         0         0         0         0     +// BOGUS        0         0         0         0         0         0         0         0     +//                      +// END DO NOT EDIT      +// DO NOT EDIT ...                                                                          +//                                                                                          +// GPIF Waveform 1: singlewr                                                                 +//                                                                                          +// Interval     0         1         2         3         4         5         6     Idle (7)  +//          _________ _________ _________ _________ _________ _________ _________ _________ +//                                                                                          +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val            +// DataMode Activate  Activate  Activate  Activate  Activate  Activate  Activate            +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData            +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int              +// IF/Wait  Wait 1    IF        Wait 1    Wait 1    Wait 1    Wait 1    Wait 1              +//   Term A           EF#                                                                   +//   LFunc            AND                                                                   +//   Term B           EF#                                                                   +// Branch1            ThenIdle                                                              +// Branch0            ElseIdle                                                              +// Re-Exec            No                                                                    +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default             +// WEN#         0         1         1         1         1         1         1         0     +// REN#         0         0         0         0         0         0         0         0     +// OE#          0         0         0         0         0         0         0         0     +// CLRST        0         0         0         0         0         0         0         0     +// unused       0         0         0         0         0         0         0         0     +// BOGUS        0         0         0         0         0         0         0         0     +//                      +// END DO NOT EDIT      +// DO NOT EDIT ...                                                                          +//                                                                                          +// GPIF Waveform 2: FIFORd                                                                   +//                                                                                          +// Interval     0         1         2         3         4         5         6     Idle (7)  +//          _________ _________ _________ _________ _________ _________ _________ _________ +//                                                                                          +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val            +// DataMode NO Data   Activate  NO Data   NO Data   NO Data   NO Data   NO Data             +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData            +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int              +// IF/Wait  Wait 1    IF        Wait 1    IF        Wait 1    Wait 1    Wait 1              +//   Term A           TCXpire             TCXpire                                           +//   LFunc            AND                 AND                                               +//   Term B           TCXpire             TCXpire                                           +// Branch1            Then 2              ThenIdle                                          +// Branch0            Else 1              ElseIdle                                          +// Re-Exec            No                  No                                                +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default             +// WEN#         0         0         0         0         0         0         0         0     +// REN#         1         0         0         0         0         0         0         0     +// OE#          1         1         1         0         0         0         0         0     +// CLRST        0         0         0         0         0         0         0         0     +// unused       0         0         0         0         0         0         0         0     +// BOGUS        0         0         0         0         0         0         0         0     +//                      +// END DO NOT EDIT      +// DO NOT EDIT ...                                                                          +//                                                                                          +// GPIF Waveform 3: FIFOWr                                                                   +//                                                                                          +// Interval     0         1         2         3         4         5         6     Idle (7)  +//          _________ _________ _________ _________ _________ _________ _________ _________ +//                                                                                          +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val            +// DataMode NO Data   Activate  Activate  Activate  Activate  Activate  Activate            +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData            +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int              +// IF/Wait  Wait 1    IF        Wait 1    Wait 1    Wait 1    Wait 1    Wait 1              +//   Term A           TCXpire                                                               +//   LFunc            AND                                                                   +//   Term B           TCXpire                                                               +// Branch1            ThenIdle                                                              +// Branch0            Else 1                                                                +// Re-Exec            No                                                                    +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default             +// WEN#         0         0         0         0         0         0         0         0     +// REN#         0         0         0         0         0         0         0         0     +// OE#          0         0         0         0         0         0         0         0     +// CLRST        0         0         0         0         0         0         0         0     +// unused       0         0         0         0         0         0         0         0     +// BOGUS        0         0         0         0         0         0         0         0     +//                      +// END DO NOT EDIT      +                                               +// GPIF Program Code                           +                                               +// DO NOT EDIT ...                             +#include "fx2.h"                             +#include "fx2regs.h"                         +#include "fx2sdly.h"     // SYNCDELAY macro  +// END DO NOT EDIT                             +                                               +// DO NOT EDIT ...                      +const char xdata WaveData[128] =      +{                                       +// Wave 0  +/* LenBr */ 0x01,     0x01,     0x01,     0x01,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00, +/* Output*/ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00, +/* LFun  */ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x3F, +// Wave 1  +/* LenBr */ 0x01,     0x3F,     0x01,     0x01,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x22,     0x03,     0x02,     0x02,     0x02,     0x02,     0x02,     0x00, +/* Output*/ 0x00,     0x01,     0x01,     0x01,     0x01,     0x01,     0x01,     0x00, +/* LFun  */ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x3F, +// Wave 2  +/* LenBr */ 0x01,     0x11,     0x01,     0x3F,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x00,     0x03,     0x00,     0x01,     0x00,     0x00,     0x00,     0x00, +/* Output*/ 0x06,     0x04,     0x04,     0x00,     0x00,     0x00,     0x00,     0x00, +/* LFun  */ 0x00,     0x2D,     0x00,     0x2D,     0x00,     0x00,     0x00,     0x3F, +// Wave 3  +/* LenBr */ 0x01,     0x39,     0x01,     0x01,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x00,     0x03,     0x02,     0x02,     0x02,     0x02,     0x02,     0x00, +/* Output*/ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00, +/* LFun  */ 0x00,     0x2D,     0x00,     0x00,     0x00,     0x00,     0x00,     0x3F, +};                      +// END DO NOT EDIT      +                        +// DO NOT EDIT ...                      +const char xdata FlowStates[36] =    +{                                       +/* Wave 0 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 1 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 2 FlowStates */ 0x81,0x2D,0x26,0x00,0x04,0x04,0x03,0x02,0x00, +/* Wave 3 FlowStates */ 0x81,0x2D,0x21,0x00,0x04,0x04,0x03,0x02,0x00, +};                      +// END DO NOT EDIT      +                        +// DO NOT EDIT ...                                                +const char xdata InitData[7] =                                    +{                                                                 +/* Regs  */ 0xA0,0x00,0x00,0x00,0xEE,0x4E,0x00      +};                                                                +// END DO NOT EDIT                                                +                                                                  +// TO DO: You may add additional code below. + +void GpifInit( void ) +{ +  BYTE i; +  +  // Registers which require a synchronization delay, see section 15.14 +  // FIFORESET        FIFOPINPOLAR +  // INPKTEND         OUTPKTEND +  // EPxBCH:L         REVCTL +  // GPIFTCB3         GPIFTCB2 +  // GPIFTCB1         GPIFTCB0 +  // EPxFIFOPFH:L     EPxAUTOINLENH:L +  // EPxFIFOCFG       EPxGPIFFLGSEL +  // PINFLAGSxx       EPxFIFOIRQ +  // EPxFIFOIE        GPIFIRQ +  // GPIFIE           GPIFADRH:L +  // UDMACRCH:L       EPxGPIFTRIG +  // GPIFTRIG +   +  // Note: The pre-REVE EPxGPIFTCH/L register are affected, as well... +  //      ...these have been replaced by GPIFTC[B3:B0] registers +  +  // 8051 doesn't have access to waveform memories 'til +  // the part is in GPIF mode. +  +  IFCONFIG = 0xEE; +  // IFCLKSRC=1   , FIFOs executes on internal clk source +  // xMHz=1       , 48MHz internal clk rate +  // IFCLKOE=0    , Don't drive IFCLK pin signal at 48MHz +  // IFCLKPOL=0   , Don't invert IFCLK pin signal from internal clk +  // ASYNC=1      , master samples asynchronous +  // GSTATE=1     , Drive GPIF states out on PORTE[2:0], debug WF +  // IFCFG[1:0]=10, FX2 in GPIF master mode +  +  GPIFABORT = 0xFF;  // abort any waveforms pending +  +  GPIFREADYCFG = InitData[ 0 ]; +  GPIFCTLCFG = InitData[ 1 ]; +  GPIFIDLECS = InitData[ 2 ]; +  GPIFIDLECTL = InitData[ 3 ]; +  GPIFWFSELECT = InitData[ 5 ]; +  GPIFREADYSTAT = InitData[ 6 ]; +  +  // use dual autopointer feature...  +  AUTOPTRSETUP = 0x07;          // inc both pointers,  +                                // ...warning: this introduces pdata hole(s) +                                // ...at E67B (XAUTODAT1) and E67C (XAUTODAT2) +   +  // source +  AUTOPTRH1 = MSB( &WaveData ); +  AUTOPTRL1 = LSB( &WaveData ); +   +  // destination +  AUTOPTRH2 = 0xE4; +  AUTOPTRL2 = 0x00; +  +  // transfer +  for ( i = 0x00; i < 128; i++ ) +  { +    EXTAUTODAT2 = EXTAUTODAT1; +  } +  +// Configure GPIF Address pins, output initial value, +  PORTCCFG = 0xFF;    // [7:0] as alt. func. GPIFADR[7:0] +  OEC = 0xFF;         // and as outputs +  PORTECFG |= 0x80;   // [8] as alt. func. GPIFADR[8] +  OEE |= 0x80;        // and as output +  +// ...OR... tri-state GPIFADR[8:0] pins +//  PORTCCFG = 0x00;  // [7:0] as port I/O +//  OEC = 0x00;       // and as inputs +//  PORTECFG &= 0x7F; // [8] as port I/O +//  OEE &= 0x7F;      // and as input +  +// GPIF address pins update when GPIFADRH/L written +  SYNCDELAY;                    //  +  GPIFADRH = 0x00;    // bits[7:1] always 0 +  SYNCDELAY;                    //  +  GPIFADRL = 0x00;    // point to PERIPHERAL address 0x0000 +  +// Configure GPIF FlowStates registers for Wave 0 of WaveData +  FLOWSTATE = FlowStates[ 0 ]; +  FLOWLOGIC = FlowStates[ 1 ]; +  FLOWEQ0CTL = FlowStates[ 2 ]; +  FLOWEQ1CTL = FlowStates[ 3 ]; +  FLOWHOLDOFF = FlowStates[ 4 ]; +  FLOWSTB = FlowStates[ 5 ]; +  FLOWSTBEDGE = FlowStates[ 6 ]; +  FLOWSTBHPERIOD = FlowStates[ 7 ]; +} +  diff --git a/firmware/fx2/usrp1/gpif.gpf b/firmware/fx2/usrp1/gpif.gpf Binary files differnew file mode 100755 index 000000000..854e25399 --- /dev/null +++ b/firmware/fx2/usrp1/gpif.gpf diff --git a/firmware/fx2/usrp1/usb_descriptors.a51 b/firmware/fx2/usrp1/usb_descriptors.a51 new file mode 100644 index 000000000..a60adbef8 --- /dev/null +++ b/firmware/fx2/usrp1/usb_descriptors.a51 @@ -0,0 +1,404 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003 Free Software Foundation, Inc. +;;;  +;;; This file is part of GNU Radio +;;;  +;;; GNU Radio 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 3, or (at your option) +;;; any later version. +;;;  +;;; GNU Radio is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +;;; GNU General Public License for more details. +;;;  +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Radio; see the file COPYING.  If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. +;;; +	 +;;; USB Descriptor table for the USRP +;;;  +;;; We're a high-speed only device (480 Mb/sec) with 1 configuration +;;; and 3 interfaces.   +;;;  +;;;	interface 0:	command and status (ep0 COMMAND) +;;;	interface 1:	Transmit path (ep2 OUT BULK) +;;;	interface 2:	Receive path (ep6 IN BULK) + +	.module usb_descriptors +	 +	VID_FREE	 = 0xfffe	; Free Software Folks +	PID_USRP	 = 0x0002	; USRP + +	;; We distinguish configured from unconfigured USRPs using the Device ID. +	;; If the MSB of the DID is 0, the device is unconfigured. +	;; The LSB of the DID is reserved for hardware revs. +	 +	DID_USRP	 = 0x0100	; Device ID (bcd) + +	 +	DSCR_DEVICE	 =   1	; Descriptor type: Device +	DSCR_CONFIG	 =   2	; Descriptor type: Configuration +	DSCR_STRING	 =   3	; Descriptor type: String +	DSCR_INTRFC	 =   4	; Descriptor type: Interface +	DSCR_ENDPNT	 =   5	; Descriptor type: Endpoint +	DSCR_DEVQUAL	 =   6	; Descriptor type: Device Qualifier +	 +	DSCR_DEVICE_LEN	 =  18 +	DSCR_CONFIG_LEN  =   9 +	DSCR_INTRFC_LEN  =   9 +	DSCR_ENDPNT_LEN  =   7 +	DSCR_DEVQUAL_LEN =  10 +	 +	ET_CONTROL	 =   0	; Endpoint type: Control +	ET_ISO		 =   1	; Endpoint type: Isochronous +	ET_BULK		 =   2	; Endpoint type: Bulk +	ET_INT		 =   3	; Endpoint type: Interrupt +	 +	 +	;; configuration attributes +	bmSELF_POWERED	=	1 << 6 + +;;; -------------------------------------------------------- +;;;	external ram data +;;;-------------------------------------------------------- +	 +	.area USBDESCSEG    (XDATA) +	 +;;; ---------------------------------------------------------------- +;;; descriptors used when operating at high speed (480Mb/sec) +;;; ---------------------------------------------------------------- +	 +	.even	; descriptors must be 2-byte aligned for SUDPTR{H,L} to work + +	;; The .even directive isn't really honored by the linker.  Bummer! +	;; (There's no way to specify an alignment requirement for a given area, +	;; hence when they're concatenated together, even doesn't work.) +	;;  +	;; We work around this by telling the linker to put USBDESCSEG +	;; at 0xE000 absolute.  This means that the maximimum length of this +	;; segment is 480 bytes, leaving room for the two hash slots  +	;; at 0xE1EO to 0xE1FF.   +	;;  +	;; As of July 7, 2004, this segment is 326 bytes long +	 +_high_speed_device_descr:: +	.db	DSCR_DEVICE_LEN +	.db	DSCR_DEVICE +	.db	<0x0200		; Specification version (LSB) +	.db	>0x0200		; Specification version (MSB) +	.db	0xff		; device class (vendor specific) +	.db	0xff		; device subclass (vendor specific) +	.db	0xff		; device protocol (vendor specific) +	.db	64		; bMaxPacketSize0 for endpoint 0 +	.db	<VID_FREE	; idVendor +	.db	>VID_FREE	; idVendor +	.db	<PID_USRP	; idProduct +	.db	>PID_USRP	; idProduct +_usb_desc_hw_rev_binary_patch_location_0:: +	.db	<DID_USRP	; bcdDevice +	.db	>DID_USRP	; bcdDevice +	.db	SI_VENDOR	; iManufacturer (string index) +	.db	SI_PRODUCT	; iProduct (string index) +	.db	SI_SERIAL	; iSerial number (string index) +	.db	1		; bNumConfigurations +	 +;;; describes the other speed (12Mb/sec) +	.even +_high_speed_devqual_descr:: +	.db	DSCR_DEVQUAL_LEN +	.db	DSCR_DEVQUAL +	.db	<0x0200		; bcdUSB (LSB) +	.db	>0x0200		; bcdUSB (MSB) +	.db	0xff		; bDeviceClass +	.db	0xff		; bDeviceSubClass +	.db	0xff		; bDeviceProtocol +	.db	64		; bMaxPacketSize0 +	.db	1		; bNumConfigurations (one config at 12Mb/sec) +	.db	0		; bReserved +	 +	.even +_high_speed_config_descr::	 +	.db	DSCR_CONFIG_LEN +	.db	DSCR_CONFIG +	.db	<(_high_speed_config_descr_end - _high_speed_config_descr) ; LSB +	.db	>(_high_speed_config_descr_end - _high_speed_config_descr) ; MSB +	.db	3		; bNumInterfaces +	.db	1		; bConfigurationValue +	.db	0		; iConfiguration +	.db	0x80 | bmSELF_POWERED ; bmAttributes +	.db	0		; bMaxPower + +	;; interface descriptor 0 (command & status, ep0 COMMAND) +	 +	.db	DSCR_INTRFC_LEN +	.db	DSCR_INTRFC +	.db	0		; bInterfaceNumber (zero based) +	.db	0		; bAlternateSetting +	.db	0		; bNumEndpoints +	.db	0xff		; bInterfaceClass (vendor specific) +	.db	0xff		; bInterfaceSubClass (vendor specific) +	.db	0xff		; bInterfaceProtocol (vendor specific) +	.db	SI_COMMAND_AND_STATUS	; iInterface (description) + +	;; interface descriptor 1 (transmit path, ep2 OUT BULK) +	 +	.db	DSCR_INTRFC_LEN +	.db	DSCR_INTRFC +	.db	1		; bInterfaceNumber (zero based) +	.db	0		; bAlternateSetting +	.db	1		; bNumEndpoints +	.db	0xff		; bInterfaceClass (vendor specific) +	.db	0xff		; bInterfaceSubClass (vendor specific) +	.db	0xff		; bInterfaceProtocol (vendor specific) +	.db	SI_TX_PATH	; iInterface (description) + +	;; interface 1's end point + +	.db	DSCR_ENDPNT_LEN +	.db	DSCR_ENDPNT +	.db	0x02		; bEndpointAddress (ep 2 OUT) +	.db	ET_BULK		; bmAttributes +	.db	<512		; wMaxPacketSize (LSB) +	.db	>512		; wMaxPacketSize (MSB) +	.db	0		; bInterval (iso only) + +	;; interface descriptor 2 (receive path, ep6 IN BULK) +	 +	.db	DSCR_INTRFC_LEN +	.db	DSCR_INTRFC +	.db	2		; bInterfaceNumber (zero based) +	.db	0		; bAlternateSetting +	.db	1		; bNumEndpoints +	.db	0xff		; bInterfaceClass (vendor specific) +	.db	0xff		; bInterfaceSubClass (vendor specific) +	.db	0xff		; bInterfaceProtocol (vendor specific) +	.db	SI_RX_PATH	; iInterface (description) + +	;; interface 2's end point + +	.db	DSCR_ENDPNT_LEN +	.db	DSCR_ENDPNT +	.db	0x86		; bEndpointAddress (ep 6 IN) +	.db	ET_BULK		; bmAttributes +	.db	<512		; wMaxPacketSize (LSB) +	.db	>512		; wMaxPacketSize (MSB) +	.db	0		; bInterval (iso only) + +_high_speed_config_descr_end:		 + +;;; ---------------------------------------------------------------- +;;; descriptors used when operating at full speed (12Mb/sec) +;;; ---------------------------------------------------------------- + +	.even +_full_speed_device_descr::	 +	.db	DSCR_DEVICE_LEN +	.db	DSCR_DEVICE +	.db	<0x0200		; Specification version (LSB) +	.db	>0x0200		; Specification version (MSB) +	.db	0xff		; device class (vendor specific) +	.db	0xff		; device subclass (vendor specific) +	.db	0xff		; device protocol (vendor specific) +	.db	64		; bMaxPacketSize0 for endpoint 0 +	.db	<VID_FREE	; idVendor +	.db	>VID_FREE	; idVendor +	.db	<PID_USRP	; idProduct +	.db	>PID_USRP	; idProduct +_usb_desc_hw_rev_binary_patch_location_1:: +	.db	<DID_USRP	; bcdDevice +	.db	>DID_USRP	; bcdDevice +	.db	SI_VENDOR	; iManufacturer (string index) +	.db	SI_PRODUCT	; iProduct (string index) +	.db	SI_NONE		; iSerial number (None) +	.db	1		; bNumConfigurations +	 +	 +;;; describes the other speed (480Mb/sec) +	.even +_full_speed_devqual_descr:: +	.db	DSCR_DEVQUAL_LEN +	.db	DSCR_DEVQUAL +	.db	<0x0200		; bcdUSB +	.db	>0x0200		; bcdUSB +	.db	0xff		; bDeviceClass +	.db	0xff		; bDeviceSubClass +	.db	0xff		; bDeviceProtocol +	.db	64		; bMaxPacketSize0 +	.db	1		; bNumConfigurations (one config at 480Mb/sec) +	.db	0		; bReserved +	 +	.even +_full_speed_config_descr::	 +	.db	DSCR_CONFIG_LEN +	.db	DSCR_CONFIG +	.db	<(_full_speed_config_descr_end - _full_speed_config_descr) ; LSB +	.db	>(_full_speed_config_descr_end - _full_speed_config_descr) ; MSB +	.db	1		; bNumInterfaces +	.db	1		; bConfigurationValue +	.db	0		; iConfiguration +	.db	0x80 | bmSELF_POWERED ; bmAttributes +	.db	0		; bMaxPower + +	;; interface descriptor 0 (command & status, ep0 COMMAND) +	 +	.db	DSCR_INTRFC_LEN +	.db	DSCR_INTRFC +	.db	0		; bInterfaceNumber (zero based) +	.db	0		; bAlternateSetting +	.db	0		; bNumEndpoints +	.db	0xff		; bInterfaceClass (vendor specific) +	.db	0xff		; bInterfaceSubClass (vendor specific) +	.db	0xff		; bInterfaceProtocol (vendor specific) +	.db	SI_COMMAND_AND_STATUS	; iInterface (description) +	 +_full_speed_config_descr_end:	 +	 +;;; ---------------------------------------------------------------- +;;;			string descriptors +;;; ---------------------------------------------------------------- + +_nstring_descriptors:: +	.db	(_string_descriptors_end - _string_descriptors) / 2 + +_string_descriptors:: +	.db	<str0, >str0 +	.db	<str1, >str1 +	.db	<str2, >str2 +	.db	<str3, >str3 +	.db	<str4, >str4 +	.db	<str5, >str5 +	.db	<str6, >str6 +_string_descriptors_end: + +	SI_NONE = 0 +	;; str0 contains the language ID's. +	.even +str0:	.db	str0_end - str0 +	.db	DSCR_STRING +	.db	0 +	.db	0 +	.db	<0x0409		; magic code for US English (LSB) +	.db	>0x0409		; magic code for US English (MSB) +str0_end: + +	SI_VENDOR = 1 +	.even +str1:	.db	str1_end - str1 +	.db	DSCR_STRING +	.db	'F, 0		; 16-bit unicode +	.db	'r, 0 +	.db	'e, 0 +	.db	'e, 0 +	.db	' , 0 +	.db	'S, 0 +	.db	'o, 0 +	.db	'f, 0 +	.db	't, 0 +	.db	'w, 0 +	.db	'a, 0 +	.db	'r, 0 +	.db	'e, 0 +	.db	' , 0 +	.db	'F, 0 +	.db	'o, 0 +	.db	'l, 0 +	.db	'k, 0 +	.db	's, 0 +str1_end: + +	SI_PRODUCT = 2 +	.even +str2:	.db	str2_end - str2 +	.db	DSCR_STRING +	.db	'U, 0 +	.db	'S, 0 +	.db	'R, 0 +	.db	'P, 0 +	.db	' , 0 +	.db	'R, 0 +	.db	'e, 0 +	.db	'v, 0 +	.db	' , 0 +_usb_desc_hw_rev_ascii_patch_location_0:: +	.db	'?, 0 +str2_end: + +	SI_COMMAND_AND_STATUS = 3 +	.even +str3:	.db	str3_end - str3 +	.db	DSCR_STRING +	.db	'C, 0 +	.db	'o, 0 +	.db	'm, 0 +	.db	'm, 0 +	.db	'a, 0 +	.db	'n, 0 +	.db	'd, 0 +	.db	' , 0 +	.db	'&, 0 +	.db	' , 0 +	.db	'S, 0 +	.db	't, 0 +	.db	'a, 0 +	.db	't, 0 +	.db	'u, 0 +	.db	's, 0 +str3_end: + +	SI_TX_PATH = 4 +	.even +str4:	.db	str4_end - str4 +	.db	DSCR_STRING +	.db	'T, 0 +	.db	'r, 0 +	.db	'a, 0 +	.db	'n, 0 +	.db	's, 0 +	.db	'm, 0 +	.db	'i, 0 +	.db	't, 0 +	.db	' , 0 +	.db	'P, 0 +	.db	'a, 0 +	.db	't, 0 +	.db	'h, 0 +str4_end: + +	SI_RX_PATH = 5 +	.even +str5:	.db	str5_end - str5 +	.db	DSCR_STRING +	.db	'R, 0 +	.db	'e, 0 +	.db	'c, 0 +	.db	'e, 0 +	.db	'i, 0 +	.db	'v, 0 +	.db	'e, 0 +	.db	' , 0 +	.db	'P, 0 +	.db	'a, 0 +	.db	't, 0 +	.db	'h, 0 +str5_end: + +	SI_SERIAL = 6 +	.even +str6:	.db	str6_end - str6 +	.db	DSCR_STRING +_usb_desc_serial_number_ascii:: +	.db	'3, 0 +	.db	'., 0 +	.db	'1, 0 +	.db	'4, 0 +	.db	'1, 0 +	.db	'5, 0 +	.db	'9, 0 +	.db	'3, 0 +str6_end: + diff --git a/firmware/fx2/usrp1/usrp_common.c b/firmware/fx2/usrp1/usrp_common.c new file mode 100644 index 000000000..0998653c2 --- /dev/null +++ b/firmware/fx2/usrp1/usrp_common.c @@ -0,0 +1,109 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +/*  + * common code for USRP + */ + +#include "usrp_common.h" + +void init_board (void); + +void +init_usrp (void) +{ +  CPUCS = bmCLKSPD1;	// CPU runs @ 48 MHz +  CKCON = 0;		// MOVX takes 2 cycles + +  // IFCLK is generated internally and runs at 48 MHz; GPIF "master mode" + +  IFCONFIG = bmIFCLKSRC | bm3048MHZ | bmIFCLKOE | bmIFCLKPOL | bmIFGPIF; +  SYNCDELAY; + +  // configure IO ports (B and D are used by GPIF) + +  IOA = bmPORT_A_INITIAL;	// Port A initial state +  OEA = bmPORT_A_OUTPUTS;	// Port A direction register + +  IOC = bmPORT_C_INITIAL;	// Port C initial state +  OEC = bmPORT_C_OUTPUTS;	// Port C direction register + +  IOE = bmPORT_E_INITIAL;	// Port E initial state +  OEE = bmPORT_E_OUTPUTS;	// Port E direction register + + +  // REVCTL = bmDYN_OUT | bmENH_PKT;			// highly recommended by docs +  // SYNCDELAY; +   +  // configure end points + +  EP1OUTCFG = bmVALID | bmBULK;				SYNCDELAY; +  EP1INCFG  = bmVALID | bmBULK | bmIN;			SYNCDELAY; + +  EP2CFG    = bmVALID | bmBULK | bmQUADBUF;		SYNCDELAY;	// 512 quad bulk OUT +  EP4CFG    = 0;					SYNCDELAY;	// disabled +  EP6CFG    = bmVALID | bmBULK | bmQUADBUF | bmIN;	SYNCDELAY;	// 512 quad bulk IN +  EP8CFG    = 0;					SYNCDELAY;	// disabled + +  // reset FIFOs + +  FIFORESET = bmNAKALL;					SYNCDELAY; +  FIFORESET = 2;					SYNCDELAY; +  // FIFORESET = 4;					SYNCDELAY; +  FIFORESET = 6;					SYNCDELAY; +  // FIFORESET = 8;					SYNCDELAY; +  FIFORESET = 0;					SYNCDELAY; +   +  // configure end point FIFOs + +  // let core see 0 to 1 transistion of autoout bit + +  EP2FIFOCFG =             bmWORDWIDE;			SYNCDELAY; +  EP2FIFOCFG = bmAUTOOUT | bmWORDWIDE;			SYNCDELAY; +  EP6FIFOCFG = bmAUTOIN  | bmWORDWIDE;			SYNCDELAY; + + +  // prime the pump  + +#if 0 +  EP2BCL  = 0x80;		SYNCDELAY; +  EP2BCL  = 0x80;		SYNCDELAY; +  EP2BCL  = 0x80;		SYNCDELAY; +  EP2BCL  = 0x80;		SYNCDELAY; +#endif + +  EP0BCH = 0;			SYNCDELAY; + +  // arm EP1OUT so we can receive "out" packets (TRM pg 8-8) + +  EP1OUTBC = 0;			SYNCDELAY; + +  EP2GPIFFLGSEL = 0x01;		SYNCDELAY; // For EP2OUT, GPIF uses EF flag +  EP6GPIFFLGSEL = 0x02;		SYNCDELAY; // For EP6IN,  GPIF uses FF flag + +  // set autoin length for EP6 +  // FIXME should be f(enumeration) + +  EP6AUTOINLENH = (512) >> 8;	SYNCDELAY;  // this is the length for high speed +  EP6AUTOINLENL = (512) & 0xff; SYNCDELAY; + +  init_board (); +} + diff --git a/firmware/fx2/usrp1/usrp_gpif.c b/firmware/fx2/usrp1/usrp_gpif.c new file mode 100644 index 000000000..1191c8b28 --- /dev/null +++ b/firmware/fx2/usrp1/usrp_gpif.c @@ -0,0 +1,206 @@ +/* + * Machine generated by "edit-gpif".  Do not edit by hand. + */ + +// This program configures the General Programmable Interface (GPIF) for FX2. +// Please do not modify sections of text which are marked as "DO NOT EDIT ...". +// +// DO NOT EDIT ... +// GPIF Initialization +// Interface Timing      Async +// Internal Ready Init   IntRdy=1 +// CTL Out Tristate-able Binary +// SingleWrite WF Select     1 +// SingleRead WF Select      0 +// FifoWrite WF Select       3 +// FifoRead WF Select        2 +// Data Bus Idle Drive   Tristate +// END DO NOT EDIT + +// DO NOT EDIT ... +// GPIF Wave Names +// Wave 0   = singlerd +// Wave 1   = singlewr +// Wave 2   = FIFORd +// Wave 3   = FIFOWr + +// GPIF Ctrl Outputs   Level +// CTL 0    = WEN#     CMOS +// CTL 1    = REN#     CMOS +// CTL 2    = OE#      CMOS +// CTL 3    = CLRST    CMOS +// CTL 4    = unused   CMOS +// CTL 5    = BOGUS    CMOS + +// GPIF Rdy Inputs +// RDY0     = EF# +// RDY1     = FF# +// RDY2     = unused +// RDY3     = unused +// RDY4     = unused +// RDY5     = TCXpire +// FIFOFlag = FIFOFlag +// IntReady = IntReady +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 0: singlerd +// +// Interval     0         1         2         3         4         5         6     Idle (7) +//          _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val +// DataMode NO Data   NO Data   NO Data   NO Data   NO Data   NO Data   NO Data +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int +// IF/Wait  Wait 1    Wait 1    Wait 1    Wait 1    Wait 1    Wait 1    Wait 1 +//   Term A +//   LFunc +//   Term B +// Branch1 +// Branch0 +// Re-Exec +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default +// WEN#         0         0         0         0         0         0         0         0 +// REN#         0         0         0         0         0         0         0         0 +// OE#          0         0         0         0         0         0         0         0 +// CLRST        0         0         0         0         0         0         0         0 +// unused       0         0         0         0         0         0         0         0 +// BOGUS        0         0         0         0         0         0         0         0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 1: singlewr +// +// Interval     0         1         2         3         4         5         6     Idle (7) +//          _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val +// DataMode Activate  Activate  Activate  Activate  Activate  Activate  Activate +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int +// IF/Wait  Wait 1    IF        Wait 1    Wait 1    Wait 1    Wait 1    Wait 1 +//   Term A           EF# +//   LFunc            AND +//   Term B           EF# +// Branch1            ThenIdle +// Branch0            ElseIdle +// Re-Exec            No +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default +// WEN#         0         1         1         1         1         1         1         0 +// REN#         0         0         0         0         0         0         0         0 +// OE#          0         0         0         0         0         0         0         0 +// CLRST        0         0         0         0         0         0         0         0 +// unused       0         0         0         0         0         0         0         0 +// BOGUS        0         0         0         0         0         0         0         0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 2: FIFORd +// +// Interval     0         1         2         3         4         5         6     Idle (7) +//          _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val +// DataMode NO Data   Activate  NO Data   NO Data   NO Data   NO Data   NO Data +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int +// IF/Wait  Wait 1    IF        Wait 1    IF        Wait 1    Wait 1    Wait 1 +//   Term A           TCXpire             TCXpire +//   LFunc            AND                 AND +//   Term B           TCXpire             TCXpire +// Branch1            Then 2              ThenIdle +// Branch0            Else 1              ElseIdle +// Re-Exec            No                  No +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default +// WEN#         0         0         0         0         0         0         0         0 +// REN#         1         0         0         0         0         0         0         0 +// OE#          1         1         1         0         0         0         0         0 +// CLRST        0         0         0         0         0         0         0         0 +// unused       0         0         0         0         0         0         0         0 +// BOGUS        0         0         0         0         0         0         0         0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 3: FIFOWr +// +// Interval     0         1         2         3         4         5         6     Idle (7) +//          _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val  Same Val  Same Val  Same Val  Same Val  Same Val  Same Val +// DataMode NO Data   Activate  Activate  Activate  Activate  Activate  Activate +// NextData SameData  SameData  SameData  SameData  SameData  SameData  SameData +// Int Trig No Int    No Int    No Int    No Int    No Int    No Int    No Int +// IF/Wait  Wait 1    IF        Wait 1    Wait 1    Wait 1    Wait 1    Wait 1 +//   Term A           TCXpire +//   LFunc            AND +//   Term B           TCXpire +// Branch1            ThenIdle +// Branch0            Else 1 +// Re-Exec            No +// Sngl/CRC Default   Default   Default   Default   Default   Default   Default +// WEN#         0         0         0         0         0         0         0         0 +// REN#         0         0         0         0         0         0         0         0 +// OE#          0         0         0         0         0         0         0         0 +// CLRST        0         0         0         0         0         0         0         0 +// unused       0         0         0         0         0         0         0         0 +// BOGUS        0         0         0         0         0         0         0         0 +// +// END DO NOT EDIT + +// GPIF Program Code + +// DO NOT EDIT ... +// #include "fx2.h" +// #include "fx2regs.h" +// #include "fx2sdly.h"     // SYNCDELAY macro +// END DO NOT EDIT + +// DO NOT EDIT ... +const char WaveData[128] = +{ +// Wave 0 +/* LenBr */ 0x01,     0x01,     0x01,     0x01,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00, +/* Output*/ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00, +/* LFun  */ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x3F, +// Wave 1 +/* LenBr */ 0x01,     0x3F,     0x01,     0x01,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x22,     0x03,     0x02,     0x02,     0x02,     0x02,     0x02,     0x00, +/* Output*/ 0x00,     0x01,     0x01,     0x01,     0x01,     0x01,     0x01,     0x00, +/* LFun  */ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x3F, +// Wave 2 +/* LenBr */ 0x01,     0x11,     0x01,     0x3F,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x00,     0x03,     0x00,     0x01,     0x00,     0x00,     0x00,     0x00, +/* Output*/ 0x06,     0x04,     0x04,     0x00,     0x00,     0x00,     0x00,     0x00, +/* LFun  */ 0x00,     0x2D,     0x00,     0x2D,     0x00,     0x00,     0x00,     0x3F, +// Wave 3 +/* LenBr */ 0x01,     0x39,     0x01,     0x01,     0x01,     0x01,     0x01,     0x07, +/* Opcode*/ 0x00,     0x03,     0x02,     0x02,     0x02,     0x02,     0x02,     0x00, +/* Output*/ 0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00,     0x00, +/* LFun  */ 0x00,     0x2D,     0x00,     0x00,     0x00,     0x00,     0x00,     0x3F, +}; +// END DO NOT EDIT + +// DO NOT EDIT ... +const char FlowStates[36] = +{ +/* Wave 0 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 1 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 2 FlowStates */ 0x81,0x2D,0x26,0x00,0x04,0x04,0x03,0x02,0x00, +/* Wave 3 FlowStates */ 0x81,0x2D,0x21,0x00,0x04,0x04,0x03,0x02,0x00, +}; +// END DO NOT EDIT + +// DO NOT EDIT ... +const char InitData[7] = +{ +/* Regs  */ 0xA0,0x00,0x00,0x00,0xEE,0x4E,0x00 +}; +// END DO NOT EDIT + +// TO DO: You may add additional code below. + diff --git a/firmware/fx2/usrp1/usrp_gpif_inline.h b/firmware/fx2/usrp1/usrp_gpif_inline.h new file mode 100644 index 000000000..77a741a8b --- /dev/null +++ b/firmware/fx2/usrp1/usrp_gpif_inline.h @@ -0,0 +1,27 @@ +/* + * Machine generated by "edit-gpif".  Do not edit by hand. + */ + +#define setup_flowstate_common()	\ +do {					\ +     FLOWSTATE = 0x81;			\ +     FLOWLOGIC = 0x2d;			\ +    FLOWEQ0CTL = 0x26;			\ +    FLOWEQ1CTL = 0x00;			\ +   FLOWHOLDOFF = 0x04;			\ +       FLOWSTB = 0x04;			\ +   FLOWSTBEDGE = 0x03;			\ +FLOWSTBHPERIOD = 0x02;			\ +GPIFHOLDAMOUNT = 0x00;			\ +} while (0) + +#define setup_flowstate_read()	\ +do {					\ +    FLOWEQ0CTL = 0x26;			\ +} while (0) + +#define setup_flowstate_write()	\ +do {					\ +    FLOWEQ0CTL = 0x21;			\ +} while (0) + diff --git a/firmware/fx2/usrp1/usrp_main.c b/firmware/fx2/usrp1/usrp_main.c new file mode 100644 index 000000000..3eb8c001f --- /dev/null +++ b/firmware/fx2/usrp1/usrp_main.c @@ -0,0 +1,389 @@ +/*  + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2004 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +#include "usrp_common.h" +#include "usrp_regs.h" +#include "usrp_commands.h" +#include "fpga.h" +#include "usrp_gpif_inline.h" +#include "timer.h" +#include "i2c.h" +#include "isr.h" +#include "usb_common.h" +#include "fx2utils.h" +#include "usrp_globals.h" +#include "usrp_i2c_addr.h" +#include <string.h> +#include "spi.h" +#include "eeprom_io.h" +#include "usb_descriptors.h" + +/* + * offsets into boot eeprom for configuration values + */ +#define	HW_REV_OFFSET		  5 +#define SERIAL_NO_OFFSET	248 +#define SERIAL_NO_LEN		  8 + + +#define	bRequestType	SETUPDAT[0] +#define	bRequest	SETUPDAT[1] +#define	wValueL		SETUPDAT[2] +#define	wValueH		SETUPDAT[3] +#define	wIndexL		SETUPDAT[4] +#define	wIndexH		SETUPDAT[5] +#define	wLengthL	SETUPDAT[6] +#define	wLengthH	SETUPDAT[7] + + +unsigned char g_tx_enable = 0; +unsigned char g_rx_enable = 0; +unsigned char g_rx_overrun = 0; +unsigned char g_tx_underrun = 0; + +/* + * the host side fpga loader code pushes an MD5 hash of the bitstream + * into hash1. + */ +#define	  USRP_HASH_SIZE      16 +xdata at USRP_HASH_SLOT_1_ADDR unsigned char hash1[USRP_HASH_SIZE]; + +static void +get_ep0_data (void) +{ +  EP0BCL = 0;			// arm EP0 for OUT xfer.  This sets the busy bit + +  while (EP0CS & bmEPBUSY)	// wait for busy to clear +    ; +} + +/* + * Handle our "Vendor Extension" commands on endpoint 0. + * If we handle this one, return non-zero. + */ +unsigned char +app_vendor_cmd (void) +{ +  if (bRequestType == VRT_VENDOR_IN){ + +    ///////////////////////////////// +    //    handle the IN requests +    ///////////////////////////////// + +    switch (bRequest){ + +    case VRQ_GET_STATUS: +      switch (wIndexL){ + +      case GS_TX_UNDERRUN: +	EP0BUF[0] = g_tx_underrun; +	g_tx_underrun = 0; +	EP0BCH = 0; +	EP0BCL = 1; +	break; + +      case GS_RX_OVERRUN: +	EP0BUF[0] = g_rx_overrun; +	g_rx_overrun = 0; +	EP0BCH = 0; +	EP0BCL = 1; +	break; + +      default: +	return 0; +      } +      break; + +    case VRQ_I2C_READ: +      if (!i2c_read (wValueL, EP0BUF, wLengthL)) +	return 0; + +      EP0BCH = 0; +      EP0BCL = wLengthL; +      break; + +    case VRQ_SPI_READ: +      if (!spi_read (wValueH, wValueL, wIndexH, wIndexL, EP0BUF, wLengthL)) +	return 0; + +      EP0BCH = 0; +      EP0BCL = wLengthL; +      break; + +    case VRQ_SPI_TRANSACT: +      if (!spi_transact (wValueH, wValueL, wIndexH, wIndexL, wLengthH, EP0BUF, wLengthL)) +	return 0; + +      EP0BCH = 0; +      EP0BCL = wLengthL; +      break; + +    default: +      return 0; +    } +  } + +  else if (bRequestType == VRT_VENDOR_OUT){ + +    ///////////////////////////////// +    //    handle the OUT requests +    ///////////////////////////////// + +    switch (bRequest){ + +    case VRQ_SET_LED: +      switch (wIndexL){ +      case 0: +	set_led_0 (wValueL); +	break; +	 +      case 1: +	set_led_1 (wValueL); +	break; +	 +      default: +	return 0; +      } +      break; +       +    case VRQ_FPGA_LOAD: +      switch (wIndexL){			// sub-command +      case FL_BEGIN: +	return fpga_load_begin (); +	 +      case FL_XFER: +	get_ep0_data (); +	return fpga_load_xfer (EP0BUF, EP0BCL); +	 +      case FL_END: +	return fpga_load_end (); +	 +      default: +	return 0; +      } +      break; +       + +    case VRQ_FPGA_SET_RESET: +      fpga_set_reset (wValueL); +      break; +       +    case VRQ_FPGA_SET_TX_ENABLE: +      fpga_set_tx_enable (wValueL); +      break; +       +    case VRQ_FPGA_SET_RX_ENABLE: +      fpga_set_rx_enable (wValueL); +      break; + +    case VRQ_FPGA_SET_TX_RESET: +      fpga_set_tx_reset (wValueL); +      break; +       +    case VRQ_FPGA_SET_RX_RESET: +      fpga_set_rx_reset (wValueL); +      break; + +    case VRQ_I2C_WRITE: +      get_ep0_data (); +      if (!i2c_write (wValueL, EP0BUF, EP0BCL)) +	return 0; +      break; + +    case VRQ_SPI_WRITE: +      get_ep0_data (); +      if (!spi_write (wValueH, wValueL, wIndexH, wIndexL, EP0BUF, EP0BCL)) +	return 0; +      break; + +    default: +      return 0; +    } + +  } +  else +    return 0;    // invalid bRequestType + +  return 1; +} + + + +static void +main_loop (void) +{ +  setup_flowstate_common (); + +  while (1){ + +    if (usb_setup_packet_avail ()) +      usb_handle_setup_packet (); +     +   +    if (GPIFTRIG & bmGPIF_IDLE){ + +      // OK, GPIF is idle.  Let's try to give it some work. + +      // First check for underruns and overruns + +      if (UC_BOARD_HAS_FPGA && (USRP_PA & (bmPA_TX_UNDERRUN | bmPA_RX_OVERRUN))){ +       +	// record the under/over run +	if (USRP_PA & bmPA_TX_UNDERRUN) +	  g_tx_underrun = 1; + +	if (USRP_PA & bmPA_RX_OVERRUN) +	  g_rx_overrun = 1; + +	// tell the FPGA to clear the flags +	fpga_clear_flags (); +      } + +      // Next see if there are any "OUT" packets waiting for our attention, +      // and if so, if there's room in the FPGA's FIFO for them. + +      if (g_tx_enable && !(EP24FIFOFLGS & 0x02)){  // USB end point fifo is not empty... + +	if (fpga_has_room_for_packet ()){	   // ... and FPGA has room for packet + +	  GPIFTCB1 = 0x01;	SYNCDELAY; +	  GPIFTCB0 = 0x00;	SYNCDELAY; + +	  setup_flowstate_write (); + +	  SYNCDELAY; +	  GPIFTRIG = bmGPIF_EP2_START | bmGPIF_WRITE; 	// start the xfer +	  SYNCDELAY; + +	  while (!(GPIFTRIG & bmGPIF_IDLE)){ +	    // wait for the transaction to complete +	  } +	} +      } + +      // See if there are any requests for "IN" packets, and if so +      // whether the FPGA's got any packets for us. + +      if (g_rx_enable && !(EP6CS & bmEPFULL)){	// USB end point fifo is not full... + +	if (fpga_has_packet_avail ()){		// ... and FPGA has packet available + +	  GPIFTCB1 = 0x01;	SYNCDELAY; +	  GPIFTCB0 = 0x00;	SYNCDELAY; + +	  setup_flowstate_read (); + +	  SYNCDELAY; +	  GPIFTRIG = bmGPIF_EP6_START | bmGPIF_READ; 	// start the xfer +	  SYNCDELAY; + +	  while (!(GPIFTRIG & bmGPIF_IDLE)){ +	    // wait for the transaction to complete +	  } + +	  SYNCDELAY; +	  INPKTEND = 6;	// tell USB we filled buffer (6 is our endpoint num) +	} +      } +    } +  } +} + + +/* + * called at 100 Hz from timer2 interrupt + * + * Toggle led 0 + */ +void +isr_tick (void) interrupt +{ +  static unsigned char	count = 1; +   +  if (--count == 0){ +    count = 50; +    USRP_LED_REG ^= bmLED0; +  } + +  clear_timer_irq (); +} + +/* + * Read h/w rev code and serial number out of boot eeprom and + * patch the usb descriptors with the values. + */ +void +patch_usb_descriptors(void) +{ +  static xdata unsigned char hw_rev; +  static xdata unsigned char serial_no[8]; +  unsigned char i; + +  eeprom_read(I2C_ADDR_BOOT, HW_REV_OFFSET, &hw_rev, 1);	// LSB of device id +  usb_desc_hw_rev_binary_patch_location_0[0] = hw_rev; +  usb_desc_hw_rev_binary_patch_location_1[0] = hw_rev; +  usb_desc_hw_rev_ascii_patch_location_0[0] = hw_rev + '0';     // FIXME if we get > 9 + +  eeprom_read(I2C_ADDR_BOOT, SERIAL_NO_OFFSET, serial_no, SERIAL_NO_LEN); + +  for (i = 0; i < SERIAL_NO_LEN; i++){ +    unsigned char ch = serial_no[i]; +    if (ch == 0xff)	// make unprogrammed EEPROM default to '0' +      ch = '0'; +    usb_desc_serial_number_ascii[i << 1] = ch; +  } +} + +void +main (void) +{ +#if 0 +  g_rx_enable = 0;	// FIXME (work around initialization bug) +  g_tx_enable = 0; +  g_rx_overrun = 0; +  g_tx_underrun = 0; +#endif + +  memset (hash1, 0, USRP_HASH_SIZE);	// zero fpga bitstream hash.  This forces reload +   +  init_usrp (); +  init_gpif (); +   +  // if (UC_START_WITH_GSTATE_OUTPUT_ENABLED) +  IFCONFIG |= bmGSTATE;			// no conflict, start with it on + +  set_led_0 (0); +  set_led_1 (0); +   +  EA = 0;		// disable all interrupts + +  patch_usb_descriptors(); + +  setup_autovectors (); +  usb_install_handlers (); +  hook_timer_tick ((unsigned short) isr_tick); + +  EIEX4 = 1;		// disable INT4 FIXME +  EA = 1;		// global interrupt enable + +  fx2_renumerate ();	// simulates disconnect / reconnect + +  main_loop (); +} diff --git a/firmware/fx2/usrp1/usrp_regs.h b/firmware/fx2/usrp1/usrp_regs.h new file mode 100644 index 000000000..a4f1d9896 --- /dev/null +++ b/firmware/fx2/usrp1/usrp_regs.h @@ -0,0 +1,163 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA + */ + +/* + * These are the register definitions for the Rev 1 USRP prototype + * The Rev 1 is the version with the AD9862's and daughterboards + */ + +#ifndef _USRP_REV1_REGS_H_ +#define _USRP_REV1_REGS_H_ + +#include "fx2regs.h" + +/* + * Port A (bit addressable): + */ + +#define USRP_PA			IOA		// Port A +#define	USRP_PA_OE		OEA		// Port A direction register + +#define bmPA_S_CLK		bmBIT0		// SPI serial clock +#define	bmPA_S_DATA_TO_PERIPH	bmBIT1		// SPI SDI (peripheral rel name) +#define bmPA_S_DATA_FROM_PERIPH	bmBIT2		// SPI SDO (peripheral rel name) +#define bmPA_SEN_FPGA		bmBIT3		// serial enable for FPGA (active low) +#define	bmPA_SEN_CODEC_A	bmBIT4		// serial enable AD9862 A (active low) +#define	bmPA_SEN_CODEC_B	bmBIT5		// serial enable AD9862 B (active low) +//#define bmPA_FX2_2		bmBIT6		// misc pin to FPGA (overflow) +//#define bmPA_FX2_3		bmBIT7		// misc pin to FPGA (underflow) +#define	bmPA_RX_OVERRUN		bmBIT6		// misc pin to FPGA (overflow) +#define	bmPA_TX_UNDERRUN	bmBIT7		// misc pin to FPGA (underflow) + + +sbit at 0x80+0 bitS_CLK;		// 0x80 is the bit address of PORT A +sbit at 0x80+1 bitS_OUT;		// out from FX2 point of view +sbit at 0x80+2 bitS_IN;			// in from FX2 point of view + + +/* all outputs except S_DATA_FROM_PERIPH, FX2_2, FX2_3 */ + +#define	bmPORT_A_OUTPUTS  (bmPA_S_CLK			\ +			   | bmPA_S_DATA_TO_PERIPH	\ +			   | bmPA_SEN_FPGA		\ +			   | bmPA_SEN_CODEC_A		\ +			   | bmPA_SEN_CODEC_B		\ +			   ) + +#define	bmPORT_A_INITIAL   (bmPA_SEN_FPGA | bmPA_SEN_CODEC_A | bmPA_SEN_CODEC_B) + + +/* Port B: GPIF	FD[7:0]			*/ + +/* + * Port C (bit addressable): + *    5:1 FPGA configuration + */ + +#define	USRP_PC			IOC		// Port C +#define	USRP_PC_OE		OEC		// Port C direction register + +#define	USRP_ALTERA_CONFIG	USRP_PC + +#define	bmPC_nRESET		bmBIT0		// reset line to codecs (active low) +#define bmALTERA_DATA0		bmBIT1 +#define bmALTERA_NCONFIG	bmBIT2 +#define bmALTERA_DCLK		bmBIT3 +#define bmALTERA_CONF_DONE	bmBIT4 +#define bmALTERA_NSTATUS	bmBIT5 +#define	bmPC_LED0		bmBIT6		// active low +#define	bmPC_LED1		bmBIT7		// active low + +sbit at 0xA0+1 bitALTERA_DATA0;		// 0xA0 is the bit address of PORT C +sbit at 0xA0+3 bitALTERA_DCLK; + + +#define	bmALTERA_BITS		(bmALTERA_DATA0			\ +				 | bmALTERA_NCONFIG		\ +				 | bmALTERA_DCLK		\ +				 | bmALTERA_CONF_DONE		\ +				 | bmALTERA_NSTATUS) + +#define	bmPORT_C_OUTPUTS	(bmPC_nRESET			\ +				 | bmALTERA_DATA0 		\ +				 | bmALTERA_NCONFIG		\ +				 | bmALTERA_DCLK		\ +				 | bmPC_LED0			\ +				 | bmPC_LED1			\ +				 ) + +#define	bmPORT_C_INITIAL	(bmPC_LED0 | bmPC_LED1) + + +#define	USRP_LED_REG		USRP_PC +#define	bmLED0			bmPC_LED0 +#define	bmLED1			bmPC_LED1 + + +/* Port D: GPIF	FD[15:8]		*/ + +/* Port E: not bit addressible		*/ + +#define	USRP_PE			IOE		// Port E +#define	USRP_PE_OE		OEE		// Port E direction register + +#define bmPE_PE0		bmBIT0		// GPIF debug output +#define	bmPE_PE1		bmBIT1		// GPIF debug output +#define	bmPE_PE2		bmBIT2		// GPIF debug output +#define	bmPE_FPGA_CLR_STATUS	bmBIT3		// misc pin to FPGA (clear status) +#define	bmPE_SEN_TX_A		bmBIT4		// serial enable d'board TX A (active low) +#define	bmPE_SEN_RX_A		bmBIT5		// serial enable d'board RX A (active low) +#define	bmPE_SEN_TX_B		bmBIT6		// serial enable d'board TX B (active low) +#define bmPE_SEN_RX_B		bmBIT7		// serial enable d'board RX B (active low) + + +#define	bmPORT_E_OUTPUTS	(bmPE_FPGA_CLR_STATUS	\ +				 | bmPE_SEN_TX_A 	\ +				 | bmPE_SEN_RX_A	\ +				 | bmPE_SEN_TX_B	\ +				 | bmPE_SEN_RX_B	\ +				 ) + + +#define	bmPORT_E_INITIAL	(bmPE_SEN_TX_A 		\ +				 | bmPE_SEN_RX_A	\ +				 | bmPE_SEN_TX_B	\ +				 | bmPE_SEN_RX_B	\ +				 ) + +/* + * FPGA output lines that are tied to FX2 RDYx inputs. + * These are readable using GPIFREADYSTAT. + */ +#define	bmFPGA_HAS_SPACE		bmBIT0	// usbrdy[0] has room for 512 byte packet +#define	bmFPGA_PKT_AVAIL		bmBIT1	// usbrdy[1] has >= 512 bytes available +// #define	bmTX_UNDERRUN			bmBIT2  // usbrdy[2] D/A ran out of data +// #define	bmRX_OVERRUN			bmBIT3	// usbrdy[3] A/D ran out of buffer + +/* + * FPGA input lines that are tied to the FX2 CTLx outputs. + * + * These are controlled by the GPIF microprogram... + */ +// WR					bmBIT0	// usbctl[0] +// RD					bmBIT1	// usbctl[1] +// OE					bmBIT2	// usbctl[2] + +#endif /* _USRP_REV1_REGS_H_ */ diff --git a/firmware/fx2/utils/build_eeprom.py b/firmware/fx2/utils/build_eeprom.py new file mode 100755 index 000000000..298ccc00c --- /dev/null +++ b/firmware/fx2/utils/build_eeprom.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# +# Copyright 2004,2006 Free Software Foundation, Inc. +#  +# This file is part of GNU Radio +#  +# GNU Radio 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 3, or (at your option) +# any later version. +#  +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +#  +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING.  If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +#  + +import re +import sys +import os, os.path +from optparse import OptionParser + +# USB Vendor and Product ID's + +VID = 0xfffe                            # Free Software Folks + +     +def msb (x): +    return (x >> 8) & 0xff + +def lsb (x): +    return x & 0xff + +def build_eeprom_image (filename, rev): +    """Build a ``C2 Load'' EEPROM image. + +    For details on this format, see section 3.4.3 of +    the EZ-USB FX2 Technical Reference Manual +    """ +    # get the code we want to run +    f = open(filename, 'rb') +    bytes = f.read() + +    devid = 4 #for compatibility +    start_addr = 0 #prove me wrong + +    if(rev == 1): +      PID = 0x0002 #USRP1 +    else: +      PID = 0x0003 #USRP1P + +    rom_header = [ +        0xC2,                           # boot from EEPROM +        lsb (VID), +        msb (VID), +        lsb (PID), +        msb (PID), +        lsb (devid), +        msb (devid), +        0                               # configuration byte +        ] +     +    # 4 byte header that indicates where to load +    # the immediately follow code bytes. +    code_header = [ +        msb (len (bytes)), +        lsb (len (bytes)), +        msb (start_addr), +        lsb (start_addr) +        ] + +    # writes 0 to CPUCS reg (brings FX2 out of reset) +    trailer = [ +        0x80, +        0x01, +        0xe6, +        0x00, +        0x00 +        ] + +    image = rom_header + code_header + [ord(c) for c in bytes] + trailer + +    assert (len (image) <= 256) +    return image  + +if __name__ == '__main__': +    usage = "usage: %prog -r REV [options] bootfile.bin outfile.bin" +    parser = OptionParser (usage=usage) +    parser.add_option ("-r", "--rev", type="int", default=-1, +                       help="Specify USRP revision, 1 for USRP1, 2 for USRP1P") +    (options, args) = parser.parse_args () +    if len (args) != 2: +        parser.print_help () +        sys.exit (1) +    if options.rev < 0: +        sys.stderr.write ( +            "You must specify the USRP revision number (2 or 4) with -r REV\n") +        sys.exit (1) + +    infile = args[0] +    outfile = args[1] + +    image = "".join(chr(c) for c in build_eeprom_image(infile, options.rev)) + +    f = open(outfile, 'wb') +    f.write(str(image)) +    f.close()   diff --git a/firmware/fx2/utils/edit-gpif.py b/firmware/fx2/utils/edit-gpif.py new file mode 100755 index 000000000..5367b75a5 --- /dev/null +++ b/firmware/fx2/utils/edit-gpif.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- Python -*- +# +# Copyright 2003 Free Software Foundation, Inc. +#  +# This file is part of GNU Radio +#  +# GNU Radio 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 3, or (at your option) +# any later version. +#  +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +#  +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING.  If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +#  + + +# Edit the gpif.c file generated by the Cypress GPIF Designer Tool and +# produce usrp_gpif.c, and usrp_gpif_inline.h, files suitable for our +# uses. + +import re +import string +import sys + +def check_flow_state (line, flow_state_dict): +    mo = re.match (r'/\* Wave (\d) FlowStates \*/ (.*),', line) +    if mo: +        wave = int (mo.group (1)) +        data = mo.group (2) +        split = data.split (',', 8) +        v = map (lambda x : int (x, 16), split) +        # print "%s, %s" % (wave, data) +        # print "split: ", split +        # print "v    : ", v +        flow_state_dict[wave] = v + + +def delta (xseq, yseq): +    # set subtraction +    z = [] +    for x in xseq: +        if x not in yseq: +            z.append (x) +    return z +     + +def write_define (output, name, pairs): +    output.write ('#define %s()\t\\\n' % name) +    output.write ('do {\t\t\t\t\t\\\n') +    for reg, val in pairs: +        output.write ('%14s = 0x%02x;\t\t\t\\\n' % (reg, val)) +    output.write ('} while (0)\n\n') +     +def write_inlines (output, dict): +    regs = ['FLOWSTATE', 'FLOWLOGIC', 'FLOWEQ0CTL', 'FLOWEQ1CTL', 'FLOWHOLDOFF', +            'FLOWSTB', 'FLOWSTBEDGE', 'FLOWSTBHPERIOD', 'GPIFHOLDAMOUNT'] + +    READ_FLOW_STATE = 2 +    WRITE_FLOW_STATE = 3 + +    read_info = zip (regs, dict[READ_FLOW_STATE]) +    write_info = zip (regs, dict[WRITE_FLOW_STATE]) +     +    output.write ('''/* + * Machine generated by "edit-gpif".  Do not edit by hand. + */ + +''') +    write_define (output, 'setup_flowstate_common', read_info) +    write_define (output, 'setup_flowstate_read', delta (read_info, write_info)) +    write_define (output, 'setup_flowstate_write', delta (write_info, read_info)) +     + +def edit_gpif (input_name, output_name, inline_name): +    input = open (input_name, 'r') +    output = open (output_name, 'w') +    inline = open (inline_name, 'w') +    flow_state_dict = {} + +    output.write ('''/* + * Machine generated by "edit-gpif".  Do not edit by hand. + */ + +''') +     +    while 1: +        line = input.readline () +        line = string.replace (line, '\r','') +        line = re.sub (r' *$', r'', line) + +        check_flow_state (line, flow_state_dict) + +        line = re.sub (r'#include', r'// #include', line) +        line = re.sub (r'xdata ', r'', line) +        if re.search (r'GpifInit', line): +            break +         +        output.write (line) + +    output.close () +    write_inlines (inline, flow_state_dict) +    inline.close () + + +# gpif.c usrp_gpif.c usrp_gpif_inline.h +edit_gpif (sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/firmware/fx2/utils/generate_regs.py b/firmware/fx2/utils/generate_regs.py new file mode 100755 index 000000000..656cd5e81 --- /dev/null +++ b/firmware/fx2/utils/generate_regs.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +import os, os.path +import re +import sys + + +# set srcdir to the directory that contains Makefile.am +try: +    srcdir = os.environ['srcdir'] +except KeyError, e: +    srcdir = "." +srcdir = srcdir + '/' + +def open_src (name, mode): +    global srcdir +    return open (os.path.join (srcdir, name), mode) + + +def generate_fpga_regs (h_filename, v_filename): +    const_width = 7                  # bit width of constants +     +    h_file = open_src (h_filename, 'r') +    v_file = open (v_filename, 'w') +    v_file.write ( +    '''// +// This file is machine generated from %s +// Do not edit by hand; your edits will be overwritten. +// +''' % (h_filename,)) + +    pat = re.compile (r'^#define\s*(FR_\w*)\s*(\w*)(.*)$') +    pat_bitno = re.compile (r'^#define\s*(bitno\w*)\s*(\w*)(.*)$') +    pat_bm = re.compile (r'^#define\s*(bm\w*)\s*(\w*)(.*)$') +    for line in h_file: +        if re.match ('//|\s*$', line):  # comment or blank line +            v_file.write (line) +        mo = pat.search (line) +        mo_bitno =pat_bitno.search (line) +        mo_bm =pat_bm.search (line) +        if mo: +            v_file.write ('`define %-25s %d\'d%s%s\n' % ( +                mo.group (1), const_width, mo.group (2), mo.group (3))) +        elif mo_bitno: +            v_file.write ('`define %-25s %s%s\n' % ( +                mo_bitno.group (1), mo_bitno.group (2), mo_bitno.group (3))) +        elif mo_bm: +            v_file.write ('`define %-25s %s%s\n' % ( +                mo_bm.group (1), mo_bm.group (2), mo_bm.group (3))) +     + +if __name__ == '__main__': +    if len (sys.argv) != 3: +        sys.stderr.write ('usage: %s file.h file.v\n' % (sys.argv[0])) +        sys.exit (1) +    generate_fpga_regs (sys.argv[1], sys.argv[2]) +     diff --git a/firmware/microblaze/.gitignore b/firmware/microblaze/.gitignore new file mode 100644 index 000000000..e867fe87c --- /dev/null +++ b/firmware/microblaze/.gitignore @@ -0,0 +1,46 @@ +/*-stamp +/*.a +/*.bin +/*.dump +/*.log +/*.rom +/.deps +/*.guess +/*.sub +/Makefile +/Makefile.in +/aclocal.m4 +/autom4te.cache +/blink_leds +/blink_leds2 +/build +/compile +/config.h +/config.h.in +/config.log +/config.status +/configure +/depcomp +/eth_test +/gen_eth_packets +/ibs_rx_test +/ibs_tx_test +/install-sh +/libtool +/ltmain.sh +/missing +/py-compile +/rcv_eth_packets +/run_tests.sh +/stamp-h1 +/test1 +/test_phy_comm +/timer_test +/buf_ram_test +/buf_ram_zero +/hello +/configure.lineno +/configure.guess +/configure.sub +*.deps +*.o diff --git a/firmware/microblaze/AUTHORS b/firmware/microblaze/AUTHORS new file mode 100644 index 000000000..c365261f8 --- /dev/null +++ b/firmware/microblaze/AUTHORS @@ -0,0 +1,3 @@ +Eric Blossom <eb@comsec.com> +Matt Ettus <matt@ettus.com> +Josh Blum <josh@ettus.com> diff --git a/firmware/microblaze/COPYING b/firmware/microblaze/COPYING new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/firmware/microblaze/COPYING @@ -0,0 +1,674 @@ +                    GNU GENERAL PUBLIC LICENSE +                       Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +                            Preamble + +  The GNU General Public License is a free, copyleft license for +software and other kinds of works. + +  The licenses for most software and other practical works are designed +to take away your freedom to share and change the works.  By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users.  We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors.  You can apply it to +your programs, too. + +  When we speak of free software, we are referring to freedom, not +price.  Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +  To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights.  Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + +  For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received.  You must make sure that they, too, receive +or can get the source code.  And you must show them these terms so they +know their rights. + +  Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + +  For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software.  For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + +  Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so.  This is fundamentally incompatible with the aim of +protecting users' freedom to change the software.  The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable.  Therefore, we +have designed this version of the GPL to prohibit the practice for those +products.  If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + +  Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary.  To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + +  The precise terms and conditions for copying, distribution and +modification follow. + +                       TERMS AND CONDITIONS + +  0. Definitions. + +  "This License" refers to version 3 of the GNU General Public License. + +  "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +  "The Program" refers to any copyrightable work licensed under this +License.  Each licensee is addressed as "you".  "Licensees" and +"recipients" may be individuals or organizations. + +  To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy.  The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + +  A "covered work" means either the unmodified Program or a work based +on the Program. + +  To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy.  Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +  To "convey" a work means any kind of propagation that enables other +parties to make or receive copies.  Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + +  An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License.  If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +  1. Source Code. + +  The "source code" for a work means the preferred form of the work +for making modifications to it.  "Object code" means any non-source +form of a work. + +  A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +  The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form.  A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +  The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities.  However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work.  For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +  The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + +  The Corresponding Source for a work in source code form is that +same work. + +  2. Basic Permissions. + +  All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met.  This License explicitly affirms your unlimited +permission to run the unmodified Program.  The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work.  This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +  You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force.  You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright.  Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + +  Conveying under any other circumstances is permitted solely under +the conditions stated below.  Sublicensing is not allowed; section 10 +makes it unnecessary. + +  3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +  No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +  When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + +  4. Conveying Verbatim Copies. + +  You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +  You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +  5. Conveying Modified Source Versions. + +  You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + +    a) The work must carry prominent notices stating that you modified +    it, and giving a relevant date. + +    b) The work must carry prominent notices stating that it is +    released under this License and any conditions added under section +    7.  This requirement modifies the requirement in section 4 to +    "keep intact all notices". + +    c) You must license the entire work, as a whole, under this +    License to anyone who comes into possession of a copy.  This +    License will therefore apply, along with any applicable section 7 +    additional terms, to the whole of the work, and all its parts, +    regardless of how they are packaged.  This License gives no +    permission to license the work in any other way, but it does not +    invalidate such permission if you have separately received it. + +    d) If the work has interactive user interfaces, each must display +    Appropriate Legal Notices; however, if the Program has interactive +    interfaces that do not display Appropriate Legal Notices, your +    work need not make them do so. + +  A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit.  Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +  6. Conveying Non-Source Forms. + +  You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + +    a) Convey the object code in, or embodied in, a physical product +    (including a physical distribution medium), accompanied by the +    Corresponding Source fixed on a durable physical medium +    customarily used for software interchange. + +    b) Convey the object code in, or embodied in, a physical product +    (including a physical distribution medium), accompanied by a +    written offer, valid for at least three years and valid for as +    long as you offer spare parts or customer support for that product +    model, to give anyone who possesses the object code either (1) a +    copy of the Corresponding Source for all the software in the +    product that is covered by this License, on a durable physical +    medium customarily used for software interchange, for a price no +    more than your reasonable cost of physically performing this +    conveying of source, or (2) access to copy the +    Corresponding Source from a network server at no charge. + +    c) Convey individual copies of the object code with a copy of the +    written offer to provide the Corresponding Source.  This +    alternative is allowed only occasionally and noncommercially, and +    only if you received the object code with such an offer, in accord +    with subsection 6b. + +    d) Convey the object code by offering access from a designated +    place (gratis or for a charge), and offer equivalent access to the +    Corresponding Source in the same way through the same place at no +    further charge.  You need not require recipients to copy the +    Corresponding Source along with the object code.  If the place to +    copy the object code is a network server, the Corresponding Source +    may be on a different server (operated by you or a third party) +    that supports equivalent copying facilities, provided you maintain +    clear directions next to the object code saying where to find the +    Corresponding Source.  Regardless of what server hosts the +    Corresponding Source, you remain obligated to ensure that it is +    available for as long as needed to satisfy these requirements. + +    e) Convey the object code using peer-to-peer transmission, provided +    you inform other peers where the object code and Corresponding +    Source of the work are being offered to the general public at no +    charge under subsection 6d. + +  A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +  A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling.  In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage.  For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product.  A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +  "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source.  The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + +  If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information.  But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +  The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed.  Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + +  Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +  7. Additional Terms. + +  "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law.  If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +  When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it.  (Additional permissions may be written to require their own +removal in certain cases when you modify the work.)  You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +  Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + +    a) Disclaiming warranty or limiting liability differently from the +    terms of sections 15 and 16 of this License; or + +    b) Requiring preservation of specified reasonable legal notices or +    author attributions in that material or in the Appropriate Legal +    Notices displayed by works containing it; or + +    c) Prohibiting misrepresentation of the origin of that material, or +    requiring that modified versions of such material be marked in +    reasonable ways as different from the original version; or + +    d) Limiting the use for publicity purposes of names of licensors or +    authors of the material; or + +    e) Declining to grant rights under trademark law for use of some +    trade names, trademarks, or service marks; or + +    f) Requiring indemnification of licensors and authors of that +    material by anyone who conveys the material (or modified versions of +    it) with contractual assumptions of liability to the recipient, for +    any liability that these contractual assumptions directly impose on +    those licensors and authors. + +  All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10.  If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term.  If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +  If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +  Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + +  8. Termination. + +  You may not propagate or modify a covered work except as expressly +provided under this License.  Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +  However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +  Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +  Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License.  If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +  9. Acceptance Not Required for Having Copies. + +  You are not required to accept this License in order to receive or +run a copy of the Program.  Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance.  However, +nothing other than this License grants you permission to propagate or +modify any covered work.  These actions infringe copyright if you do +not accept this License.  Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +  10. Automatic Licensing of Downstream Recipients. + +  Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License.  You are not responsible +for enforcing compliance by third parties with this License. + +  An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations.  If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +  You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License.  For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +  11. Patents. + +  A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based.  The +work thus licensed is called the contributor's "contributor version". + +  A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version.  For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +  Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +  In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement).  To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +  If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients.  "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +  If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +  A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License.  You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + +  Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +  12. No Surrender of Others' Freedom. + +  If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all.  For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + +  13. Use with the GNU Affero General Public License. + +  Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work.  The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + +  14. Revised Versions of this License. + +  The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time.  Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +  Each version is given a distinguishing version number.  If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation.  If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + +  If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +  Later license versions may give you additional or different +permissions.  However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +  15. Disclaimer of Warranty. + +  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +  16. Limitation of Liability. + +  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + +  17. Interpretation of Sections 15 and 16. + +  If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +                     END OF TERMS AND CONDITIONS + +            How to Apply These Terms to Your New Programs + +  If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +  To do so, attach the following notices to the program.  It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + +    <one line to give the program's name and a brief idea of what it does.> +    Copyright (C) <year>  <name of author> + +    This program 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 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + +  If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + +    <program>  Copyright (C) <year>  <name of author> +    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. +    This is free software, and you are welcome to redistribute it +    under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License.  Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + +  You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + +  The GNU General Public License does not permit incorporating your program +into proprietary programs.  If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library.  If this is what you want to do, use the GNU Lesser General +Public License instead of this License.  But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/firmware/microblaze/ChangeLog b/firmware/microblaze/ChangeLog new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/firmware/microblaze/ChangeLog @@ -0,0 +1 @@ + diff --git a/firmware/microblaze/INSTALL b/firmware/microblaze/INSTALL new file mode 100644 index 000000000..5458714e1 --- /dev/null +++ b/firmware/microblaze/INSTALL @@ -0,0 +1,234 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package.  The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + +   The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation.  It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions.  Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + +   It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring.  Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + +   If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release.  If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + +   The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'.  You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + +  1. `cd' to the directory containing the package's source code and type +     `./configure' to configure the package for your system. + +     Running `configure' might take a while.  While running, it prints +     some messages telling which features it is checking for. + +  2. Type `make' to compile the package. + +  3. Optionally, type `make check' to run any self-tests that come with +     the package. + +  4. Type `make install' to install the programs and any data files and +     documentation. + +  5. You can remove the program binaries and object files from the +     source code directory by typing `make clean'.  To also remove the +     files that `configure' created (so you can compile the package for +     a different kind of computer), type `make distclean'.  There is +     also a `make maintainer-clean' target, but that is intended mainly +     for the package's developers.  If you use it, you may have to get +     all sorts of other programs in order to regenerate files that came +     with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about.  Run `./configure --help' for +details on some of the pertinent environment variables. + +   You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment.  Here +is an example: + +     ./configure CC=c99 CFLAGS=-g LIBS=-lposix + +   *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory.  To do this, you can use GNU `make'.  `cd' to the +directory where you want the object files and executables to go and run +the `configure' script.  `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + +   With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory.  After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc.  You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + +   You can specify separate installation prefixes for +architecture-specific files and architecture-independent files.  If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + +   In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files.  Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + +   If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System).  The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + +   For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option.  TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + +     CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + +     OS KERNEL-OS + +   See the file `config.sub' for the possible values of each field.  If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + +   If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + +   If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists.  Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'.  However, some packages may run +configure again during the build, and the customized values of these +variables may be lost.  In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'.  For example: + +     ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug.  Until the bug is fixed you can use this workaround: + +     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' +     Print a summary of the options to `configure', and exit. + +`--version' +`-V' +     Print the version of Autoconf used to generate the `configure' +     script, and exit. + +`--cache-file=FILE' +     Enable the cache: use and save the results of the tests in FILE, +     traditionally `config.cache'.  FILE defaults to `/dev/null' to +     disable caching. + +`--config-cache' +`-C' +     Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' +     Do not print messages saying which checks are being made.  To +     suppress all normal output, redirect it to `/dev/null' (any error +     messages will still be shown). + +`--srcdir=DIR' +     Look for the package's source code in directory DIR.  Usually +     `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options.  Run +`configure --help' for more details. + diff --git a/firmware/microblaze/Makefile.am b/firmware/microblaze/Makefile.am new file mode 100644 index 000000000..52fa649c2 --- /dev/null +++ b/firmware/microblaze/Makefile.am @@ -0,0 +1,29 @@ +# +# Copyright 2010 Ettus Research LLC +# +# Copyright 2007,2008 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +EXTRA_DIST = \ +	u2_flash_tool + +SUBDIRS = \ +	usrp2 \ +	usrp2p \ +	usrp2p/bootloader + diff --git a/firmware/microblaze/Makefile.common b/firmware/microblaze/Makefile.common new file mode 100644 index 000000000..4e726edab --- /dev/null +++ b/firmware/microblaze/Makefile.common @@ -0,0 +1,88 @@ +# +# Copyright 2010 Ettus Research LLC +# +# Copyright 2007 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/lib/Makefile.inc + +######################################################################## +# lwIP header include dirs +######################################################################## +LWIPDIR = $(top_srcdir)/lwip/lwip-1.3.1 + +LWIP_INCLUDES = \ +	-I$(top_srcdir)/lwip \ +	-I$(top_srcdir)/lwip_port \ +	-I$(LWIPDIR)/src/include \ +	-I$(LWIPDIR)/src/include/ipv4 + +######################################################################## +# misc flags for the mb-gcc compiler +######################################################################## +MBGCC_CFLAGS = \ +	--std=gnu99 -Wall -Werror-implicit-function-declaration \ +	-mxl-soft-div -msoft-float -mxl-soft-mul -mxl-barrel-shift + +######################################################################## +# define for the hal io (FIXME move?) +######################################################################## +#HAL_IO = -DHAL_IO_USES_DBOARD_PINS  +HAL_IO = -DHAL_IO_USES_UART  + +######################################################################## +# common cflags and ldflags +######################################################################## +COMMON_CFLAGS = \ +	-I$(top_srcdir)/../../host/lib/usrp \ +	-I$(top_srcdir)/lib \ +	$(MBGCC_CFLAGS) \ +	$(LWIP_INCLUDES) \ +	$(HAL_IO) + +COMMON_LFLAGS = \ +	-Wl,-Map -Wl,$(@:.elf=.map) + +######################################################################## +# Common stuff for building top level microblaze images +######################################################################## +#we use COMMON_IHX_ARGS to relocate the reset and interrupt vectors to +#just below the start of code. upon creating the BIN, any leading padding +#is thrown out, so the .bin file is valid for uploading to USRP2P. this  +#does not affect USRP2 because the USRP2 already starts at 0x0000, and +#because the relocate_args are not defined for USRP2's Makefile.am. +.elf.bin: +	$(MB_OBJCOPY) -O binary $(RELOCATE_ARGS) $< $@ + +.elf.dump: +	$(MB_OBJDUMP) -DSC $< > $@ + +.bin.rom: +	$(HEXDUMP) -v -e'1/1 "%.2X\n"' $< > $@ + +.elf.ihx: +	$(MB_OBJCOPY) -O ihex $(RELOCATE_ARGS) $< $@ + +_generated_from_elf = \ +	$(noinst_PROGRAMS:.elf=.map) \ +	$(noinst_PROGRAMS:.elf=.bin) \ +	$(noinst_PROGRAMS:.elf=.dump) \ +	$(noinst_PROGRAMS:.elf=.rom) \ +	$(noinst_PROGRAMS:.elf=.ihx) + +noinst_DATA = $(_generated_from_elf) + +MOSTLYCLEANFILES = $(_generated_from_elf) diff --git a/firmware/microblaze/NEWS b/firmware/microblaze/NEWS new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/firmware/microblaze/NEWS diff --git a/firmware/microblaze/README b/firmware/microblaze/README new file mode 100644 index 000000000..1479ffe1f --- /dev/null +++ b/firmware/microblaze/README @@ -0,0 +1,3 @@ +./bootstrap +./configure --host=mb +make diff --git a/firmware/microblaze/apps/bitrot/tx_drop.c b/firmware/microblaze/apps/bitrot/tx_drop.c new file mode 100644 index 000000000..3a336e938 --- /dev/null +++ b/firmware/microblaze/apps/bitrot/tx_drop.c @@ -0,0 +1,261 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include "print_rmon_regs.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * Like tx_only.c, but we discard data packets instead of sending them to the + * DSP TX pipeline. + */ + +int total_rx_pkts = 0; +int total_rx_bytes = 0; + + +static int timer_delta = MASTER_CLK_RATE/1000;	// tick at 1kHz + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu +//#define CPU_TX_BUF 	1	// cpu -> eth + +#define	DSP_RX_BUF_0	2	// dsp rx -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> eth +#define	DSP_TX_BUF_0	4	// eth -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> dsp tx + + +/* + * ================================================================ + *      configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE		  4 +#define DSP_TX_SAMPLES_PER_FRAME	250	// not used except w/ debugging +#define	DSP_TX_EXTRA_LINES		  2	// reads word0 + timestamp + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_ETH, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past ethernet header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +} + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ +  putchar('U'); + +  dbsm_stop(&dsp_tx_sm); +  dsp_tx_regs->clear_state = 1; +  dbsm_start(&dsp_tx_sm);  // restart sm so we're listening to ethernet again + +  // putstr("\nirq: underrun\n"); +} + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +  int tx_scale = 256; +  int interp = 32; + +  op_config_tx_t def_config; +  memset(&def_config, 0, sizeof(def_config)); +  def_config.phase_inc  = 408021893;			// 9.5 MHz [2**32 * fc/fsample] +  def_config.scale_iq = (tx_scale << 16) | tx_scale; +  def_config.interp = interp; + +  // setup Tx DSP regs +  config_tx_cmd(&def_config); +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  if (status & BPS_ERROR_ALL){ +    // FIXME rare path, handle error conditions +    putstr("Errors! status = "); +    puthex32_nl(status); + +    printf("total_rx_pkts  = %d\n", total_rx_pkts); +    printf("total_rx_bytes = %d\n", total_rx_bytes); + +    print_rmon_regs(); + +    if (status & (BPS_ERROR(DSP_TX_BUF_0) | BPS_ERROR(DSP_TX_BUF_1))){ +      dbsm_stop(&dsp_tx_sm);		 +      dsp_tx_regs->clear_state = 1; // try to restart +      dbsm_start(&dsp_tx_sm); +      return; +    } +  } + +  dbsm_process_status(&dsp_tx_sm, status); + +  if (status & BPS_DONE(CPU_TX_BUF)){ +    bp_clear_buf(CPU_TX_BUF); +  } +} + + +/* + * Called when an ethernet packet is received. + * + * Claim that we handled all the packets, + * dropping those destined for the TX DSP chain + * on the ground. + */ +bool +nop_eth_pkt_inspector(dbsm_t *sm, int bufno) +{ +  hal_toggle_leds(0x1); + +  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); +  size_t byte_len = (buffer_pool_status->last_line[bufno] - 1) * 4; + +  total_rx_pkts++; +  total_rx_bytes += byte_len; + +  // inspect rcvd frame and figure out what do do. + +  if (pkt->ehdr.ethertype != U2_ETHERTYPE) +    return true;	// ignore, probably bogus PAUSE frame from MAC + +  int chan = u2p_chan(&pkt->fixed); + +  switch (chan){ +  case CONTROL_CHAN: +    handle_control_chan_frame(pkt, byte_len); +    return true;	// we handled the packet +    break; + +  case 0: +  default: +    return true;	// We handled the data by dropping it :) +    break; +  } +} + + +int +main(void) +{ +  u2_init(); + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  hal_gpio_set_tx_mode(15, 0, GPIOM_FPGA_1); +  hal_gpio_set_rx_mode(15, 0, GPIOM_FPGA_1); + +  putstr("\ntx_drop\n"); +   +  // Control LEDs +  hal_set_leds(0x0, 0x3); + +  pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    nop_eth_pkt_inspector); + +  // program tx registers +  setup_tx(); + +  // kick off the state machine +  dbsm_start(&dsp_tx_sm); + +  while(1){ +    buffer_irq_handler(0); +  } +} + diff --git a/firmware/microblaze/apps/bitrot/tx_drop2.c b/firmware/microblaze/apps/bitrot/tx_drop2.c new file mode 100644 index 000000000..3afd722e6 --- /dev/null +++ b/firmware/microblaze/apps/bitrot/tx_drop2.c @@ -0,0 +1,292 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include "print_rmon_regs.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * Like tx_only.c, but we discard data packets instead of sending them to the + * DSP TX pipeline. + */ + +int total_rx_pkts = 0; +int total_rx_bytes = 0; + + +static int timer_delta = MASTER_CLK_RATE/1000;	// tick at 1kHz + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu +//#define CPU_TX_BUF 	1	// cpu -> eth + +#define	DSP_RX_BUF_0	2	// dsp rx -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> eth +#define	DSP_TX_BUF_0	4	// eth -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> dsp tx + + +/* + * ================================================================ + *      configure DSP RX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE		  5 +#define DSP_RX_SAMPLES_PER_FRAME	128 +#define	DSP_RX_EXTRA_LINES		  1	// writes timestamp + +// Receive from DSP Rx +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_DSP, +  DSP_RX_FIRST_LINE, +  BP_LAST_LINE +}; + +// send to ethernet +buf_cmd_args_t dsp_rx_send_args = { +  PORT_ETH, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from last_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine + +/* + * ================================================================ + *      configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE		  4 +#define DSP_TX_SAMPLES_PER_FRAME	250	// not used except w/ debugging +#define	DSP_TX_EXTRA_LINES		  2	// reads word0 + timestamp + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_ETH, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past ethernet header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +} + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ +  putchar('U'); + +  dbsm_stop(&dsp_tx_sm); +  dsp_tx_regs->clear_state = 1; +  dbsm_start(&dsp_tx_sm);  // restart sm so we're listening to ethernet again + +  // putstr("\nirq: underrun\n"); +} + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +#if 1 +  int tx_scale = 256; +  int interp = 32; + +  op_config_tx_t def_config; +  memset(&def_config, 0, sizeof(def_config)); +  def_config.phase_inc  = 408021893;			// 9.5 MHz [2**32 * fc/fsample] +  def_config.scale_iq = (tx_scale << 16) | tx_scale; +  def_config.interp = interp; + +  // setup Tx DSP regs +  config_tx_cmd(&def_config); +#endif +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  if (status & BPS_ERROR_ALL){ +    // FIXME rare path, handle error conditions +    putstr("Errors! status = "); +    puthex32_nl(status); + +    printf("total_rx_pkts  = %d\n", total_rx_pkts); +    printf("total_rx_bytes = %d\n", total_rx_bytes); + +    print_rmon_regs(); + +    if (status & (BPS_ERROR(DSP_TX_BUF_0) | BPS_ERROR(DSP_TX_BUF_1))){ +      dbsm_stop(&dsp_tx_sm);		 +      dsp_tx_regs->clear_state = 1; // try to restart +      dbsm_start(&dsp_tx_sm); +      return; +    } +  } + +  dbsm_process_status(&dsp_tx_sm, status); + +  if (status & BPS_DONE(CPU_TX_BUF)){ +    bp_clear_buf(CPU_TX_BUF); +  } +} + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here (always!) + */ +bool +nop_eth_pkt_inspector(dbsm_t *sm, int bufno) +{ +  hal_toggle_leds(0x1); + +  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); +  size_t byte_len = (buffer_pool_status->last_line[bufno] - 1) * 4; + +  total_rx_pkts++; +  total_rx_bytes += byte_len; + +  // inspect rcvd frame and figure out what do do. + +  if (pkt->ehdr.ethertype != U2_ETHERTYPE) +    return true;	// ignore, probably bogus PAUSE frame from MAC + +  int chan = u2p_chan(&pkt->fixed); + +  switch (chan){ +  case CONTROL_CHAN: +    handle_control_chan_frame(pkt, byte_len); +    return true;	// we handled the packet +    break; + +  case 0: +  default: +    return true;	// say we handled it +    break; +  } +} + + +int +main(void) +{ +  u2_init(); + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  hal_gpio_set_tx_mode(15, 0, GPIOM_FPGA_1); +  hal_gpio_set_rx_mode(15, 0, GPIOM_FPGA_1);	// no printing... + +  putstr("\ntx_drop2\n"); +   +  // Control LEDs +  hal_set_leds(0x0, 0x3); + +  // pic_register_handler(IRQ_OVERRUN,  overrun_irq_handler); +  pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + +  //pic_register_handler(IRQ_TIMER, timer_irq_handler); +  //hal_set_timeout(timer_delta); + +  ethernet_register_link_changed_callback(link_changed_callback); + +  ethernet_init(); + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    nop_eth_pkt_inspector); + +  // program tx registers +  setup_tx(); + +  // kick off the state machine +  dbsm_start(&dsp_tx_sm); + +  while(1){ +    buffer_irq_handler(0); +  } +} + diff --git a/firmware/microblaze/apps/bitrot/tx_drop_rate_limited.c b/firmware/microblaze/apps/bitrot/tx_drop_rate_limited.c new file mode 100644 index 000000000..2b8db7f7d --- /dev/null +++ b/firmware/microblaze/apps/bitrot/tx_drop_rate_limited.c @@ -0,0 +1,233 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include "print_rmon_regs.h" +#include "eth_mac.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * receive packets from ethernet at a fixed rate and discard them + */ + +int total_rx_pkts = 0; +int total_rx_bytes = 0; + + +static int timer_delta = (int)(MASTER_CLK_RATE * 10e-6); // 10us / tick + + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu +//#define CPU_TX_BUF 	1	// cpu -> eth + +#define	DSP_RX_BUF_0	2	// dsp rx -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> eth +#define	DSP_TX_BUF_0	4	// eth -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> dsp tx + + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +static volatile bool receive_packet_now = false; + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +  receive_packet_now = true; +} + + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ +  putchar('U'); +} + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +  int tx_scale = 256; +  int interp = 32; + +  op_config_tx_t def_config; +  memset(&def_config, 0, sizeof(def_config)); +  def_config.phase_inc  = 408021893;			// 9.5 MHz [2**32 * fc/fsample] +  def_config.scale_iq = (tx_scale << 16) | tx_scale; +  def_config.interp = interp; + +  // setup Tx DSP regs +  config_tx_cmd(&def_config); +} + + +/* + * Called when an ethernet packet is received. + * + * Claim that we handled all the packets, + * dropping those destined for the TX DSP chain + * on the ground. + */ +bool +nop_eth_pkt_inspector(dbsm_t *sm, int bufno) +{ +  hal_toggle_leds(0x1); + +  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); +  size_t byte_len = (buffer_pool_status->last_line[bufno] - 1) * 4; + +  total_rx_pkts++; +  total_rx_bytes += byte_len; + +  // inspect rcvd frame and figure out what do do. + +  if (pkt->ehdr.ethertype != U2_ETHERTYPE) +    return true;	// ignore, probably bogus PAUSE frame from MAC + +  int chan = u2p_chan(&pkt->fixed); + +  switch (chan){ +  case CONTROL_CHAN: +    handle_control_chan_frame(pkt, byte_len); +    return true;	// we handled the packet +    break; + +  case 0: +  default: +    return true;	// We handled the data by dropping it :) +    break; +  } +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  if (status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) +    bp_clear_buf(CPU_TX_BUF); + +  if (status & (BPS_DONE(DSP_TX_BUF_0) | BPS_ERROR(DSP_TX_BUF_0))){ +    bp_clear_buf(DSP_TX_BUF_0); + +    if (status & BPS_ERROR(DSP_TX_BUF_0)){ +      int crc = eth_mac_read_rmon(0x05); +      int fifo_full = eth_mac_read_rmon(0x06); +      int too_short_too_long = eth_mac_read_rmon(0x07); +      putstr("Errors! status = "); +      puthex32_nl(status); + +      printf("crc_err\t\t= %d\n", crc); +      printf("fifo_full\t\t= %d\n", fifo_full); +      printf("too_short_too_long\t= %d\n", too_short_too_long); + +      printf("total_rx_pkts  = %d\n", total_rx_pkts); +      printf("total_rx_bytes = %d\n", total_rx_bytes); +    } +    else +      nop_eth_pkt_inspector(0, DSP_TX_BUF_0); +  } + +  if (receive_packet_now && (status & BPS_IDLE(DSP_TX_BUF_0))){ +    receive_packet_now = false; +    bp_receive_to_buf(DSP_TX_BUF_0, PORT_ETH, 1, 0, BP_LAST_LINE); +  } +} + + +int +main(void) +{ +  u2_init(); + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  hal_gpio_set_tx_mode(15, 0, GPIOM_FPGA_1); +  hal_gpio_set_rx_mode(15, 0, GPIOM_FPGA_1); + +  putstr("\ntx_drop_rate_limited\n"); +   +  // Control LEDs +  hal_set_leds(0x0, 0x3); + +  pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + +  pic_register_handler(IRQ_TIMER, timer_irq_handler); +  hal_set_timeout(timer_delta); + +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + +  // program tx registers +  setup_tx(); + +  // start a receive from ethernet +  bp_receive_to_buf(DSP_TX_BUF_0, PORT_ETH, 1, 0, BP_LAST_LINE); + +  while(1){ +    buffer_irq_handler(0); +  } +} + diff --git a/firmware/microblaze/apps/blinkenlights.c b/firmware/microblaze/apps/blinkenlights.c new file mode 100644 index 000000000..4cebe5c9d --- /dev/null +++ b/firmware/microblaze/apps/blinkenlights.c @@ -0,0 +1,26 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include "memory_map.h" +#include <nonstdio.h> + +int main(int argc, char *argv[]) { + +	uint32_t c = 0; +	uint8_t i = 0; + +	while(1) { +		//delay(5000000); +		for(c=0;c<5000000;c++) asm("NOP"); +		output_regs->leds = (i++ % 2) ? 0xFF : 0x00; //blink everything on that register +	} + +	return 0; +} + +//void delay(uint32_t t) { +//	while(t-- != 0) asm("NOP"); +//} diff --git a/firmware/microblaze/apps/cruft/Makefile.am b/firmware/microblaze/apps/cruft/Makefile.am new file mode 100644 index 000000000..a4f79935b --- /dev/null +++ b/firmware/microblaze/apps/cruft/Makefile.am @@ -0,0 +1,82 @@ +# +# Copyright 2010 Ettus Research LLC +# +# Copyright 2007,2008 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +LDADD = $(top_srcdir)/lib/libu2fw.a + +AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp + +noinst_PROGRAMS = txrx_uhd.elf + +#	blink_leds \ +#	blink_leds2 \ +#	buf_ram_test \ +#	burn_dbsrx_eeprom \ +#	can_i_sub \ +#	echo \ +#	hello \ +#	read_dbids \ +#	set_hw_rev \ +#	test1 \ +#	test_db_spi \ +#	test_i2c \ +#	test_sd \ +#	test_ram \ +#	test_phy_comm \ +#	test_lsadc \ +#	test_lsdac \ +#	timer_test \ +#	txrx \ +#	burnrev30 \ +#	burnrev31 \ +#	burnrev40 \ +#	sd_gentest \ +#	sd_bounce +# + +#nononono =  \ +#	eth_serdes \ +#	gen_eth_packets \ +#	rcv_eth_packets \ +#	tx_standalone \ +#	factory_test \ +#	serdes_txrx \ +#	mimo_tx \ +#	mimo_tx_slave \ +#	ibs_rx_test \ +#	ibs_tx_test + +# tx_drop_SOURCES = tx_drop.c app_common.c +# tx_drop_rate_limited_SOURCES = tx_drop_rate_limited.c app_common.c +# tx_drop2_SOURCES = tx_drop2.c app_common.c +txrx_uhd_elf_SOURCES = txrx_uhd.c +# app_common_v2.c +#factory_test_SOURCES = factory_test.c app_common_v2.c +#eth_serdes_SOURCES = eth_serdes.c app_passthru_v2.c +#serdes_txrx_SOURCES = serdes_txrx.c app_common_v2.c +#mimo_tx_SOURCES = mimo_tx.c mimo_app_common_v2.c +#mimo_tx_slave_SOURCES = mimo_tx_slave.c app_common_v2.c + +#noinst_HEADERS = \ +#        app_common_v2.h \ +#        app_passthru_v2.h \ +#        mimo_app_common_v2.h +# + diff --git a/firmware/microblaze/apps/cruft/app_passthru_v2.c b/firmware/microblaze/apps/cruft/app_passthru_v2.c new file mode 100644 index 000000000..406c56b3b --- /dev/null +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.c @@ -0,0 +1,251 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "app_passthru_v2.h" +#include "buffer_pool.h" +#include "memcpy_wa.h" +#include "ethernet.h" +#include "nonstdio.h" +#include "print_rmon_regs.h" +#include "db.h" +#include "clocks.h" +#include <string.h> + +volatile bool link_is_up = false;	// eth handler sets this + + +// If this is non-zero, this dbsm could be writing to the ethernet +dbsm_t *ac_could_be_sending_to_eth; + +//static unsigned char exp_seqno = 0; + +void +set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt) +{ +  reply_pkt->ehdr.dst = cmd_pkt->ehdr.src; +  reply_pkt->ehdr.src = *ethernet_mac_addr(); +  reply_pkt->ehdr.ethertype = U2_ETHERTYPE; +  reply_pkt->thdr.flags = 0; +  reply_pkt->thdr.fifo_status = 0;	// written by protocol engine +  reply_pkt->thdr.seqno = 0;		// written by protocol engine +  reply_pkt->thdr.ack = 0;		// written by protocol engine +  u2p_set_word0(&reply_pkt->fixed, 0, CONTROL_CHAN); +  reply_pkt->fixed.timestamp = timer_regs->time; +} + +static void +send_reply(unsigned char *reply, size_t reply_len) +{ +  if (reply_len < 64) +    reply_len = 64; + +  // wait for buffer to become idle +  hal_set_leds(0x4, 0x4); +  while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0) +    ; +  hal_set_leds(0x0, 0x4); + +  // copy reply into CPU_TX_BUF +  memcpy_wa(buffer_ram(CPU_TX_BUF), reply, reply_len); + +  // wait until nobody else is sending to the ethernet +  if (ac_could_be_sending_to_eth){ +    hal_set_leds(0x8, 0x8); +    dbsm_wait_for_opening(ac_could_be_sending_to_eth); +    hal_set_leds(0x0, 0x8); +  } + +  // fire it off +  bp_send_from_buf(CPU_TX_BUF, PORT_ETH, 1, 0, reply_len/4); + +  // wait for it to complete (not long, it's a small pkt) +  while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0) +    ; + +  bp_clear_buf(CPU_TX_BUF); +} + + +static size_t +op_id_cmd(const op_generic_t *p, +	  void *reply_payload, size_t reply_payload_space) +{ +  op_id_reply_t *r = (op_id_reply_t *) reply_payload; +  if (reply_payload_space < sizeof(*r))	// no room +    return 0; + +  // Build reply subpacket + +  r->opcode = OP_ID_REPLY; +  r->len = sizeof(op_id_reply_t); +  r->rid = p->rid; +  r->addr = *ethernet_mac_addr(); +  r->hw_rev = 0x0000;	// FIXME +  // r->fpga_md5sum = ;	// FIXME +  // r->sw_md5sum = ;	// FIXME + +  // FIXME Add d'board info, including dbid, min/max gain, min/max freq + +  return r->len; +} + +static size_t +add_eop(void *reply_payload, size_t reply_payload_space) +{ +  op_generic_t *r = (op_generic_t *) reply_payload; +  if (reply_payload_space < sizeof(*r))		 +    return 0;					// no room + +  r->opcode = OP_EOP; +  r->len = sizeof(*r); +  r->rid = 0; +  r->ok =  0; + +  return r->len; +} + +bool +handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) +{ +  unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4; +  unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)]; +  int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t); + +  bool handled_it = false; + +  // initialize reply +  memset(reply, 0, sizeof(reply)); +  set_reply_hdr((u2_eth_packet_t *) reply, pkt); + +  // point to beginning of payload (subpackets) +  unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t); +  int payload_len = len - sizeof(u2_eth_packet_t); + +  size_t subpktlen = 0; + +  while (payload_len >= sizeof(op_generic_t)){ +    const op_generic_t *gp = (const op_generic_t *) payload; +    subpktlen = 0; + +    switch(gp->opcode){ +    case OP_EOP:		// end of subpackets +      goto end_of_subpackets; + +    case OP_ID: +      subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space); +      handled_it = true; +      break; + +    default: +      if (0){ +	printf("\npassing on %d\n", gp->opcode); +      } +      break; +    } + +    int t = (gp->len + 3) & ~3;		// bump to a multiple of 4 +    payload += t; +    payload_len -= t; + +    subpktlen = (subpktlen + 3) & ~3;	// bump to a multiple of 4 +    reply_payload += subpktlen; +    reply_payload_space -= subpktlen; +  } + + end_of_subpackets: + +  if (handled_it){ +    // add the EOP marker +    subpktlen = add_eop(reply_payload, reply_payload_space); +    subpktlen = (subpktlen + 3) & ~3;	// bump to a multiple of 4 +    reply_payload += subpktlen; +    reply_payload_space -= subpktlen; + +    send_reply(reply, reply_payload - reply); +  } + +  return handled_it; +} + + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +bool +eth_pkt_inspector(dbsm_t *sm, int bufno) +{ +  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); +  size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4; + +  //static size_t last_len = 0; + +  // hal_toggle_leds(0x1); + +  // inspect rcvd frame and figure out what do do. + +  if (pkt->ehdr.ethertype != U2_ETHERTYPE) +    return true;	// ignore, probably bogus PAUSE frame from MAC + +  int chan = u2p_chan(&pkt->fixed); + +  switch (chan){ +  case CONTROL_CHAN: +    return handle_control_chan_frame(pkt, byte_len); +    break; + +  case 0: +  default: +#if 0 +    if (last_len != 0){ +      if (byte_len != last_len){ +	printf("Len: %d last: %d\n", byte_len, last_len); +      } +    } +    last_len = byte_len; + +    if((pkt->thdr.seqno) == exp_seqno){ +      exp_seqno++; +      //putchar('.'); +    } +    else { +      // putchar('S'); +      //printf("S%d %d ",exp_seqno,pkt->thdr.seqno); +      exp_seqno = pkt->thdr.seqno + 1; +    } +#endif +    return false;	// pass it on to Tx DSP +    break; +  } +} + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ +  link_is_up = speed != 0; +  hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); +  printf("\neth link changed: speed = %d\n", speed); +} diff --git a/firmware/microblaze/apps/cruft/app_passthru_v2.h b/firmware/microblaze/apps/cruft/app_passthru_v2.h new file mode 100644 index 000000000..3904c670f --- /dev/null +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_APP_COMMON_H +#define INCLUDED_APP_COMMON_H + +#include <stdbool.h> +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "memory_map.h" +#include "hal_io.h" +#include <stddef.h> +#include <db.h> + +#define CPU_TX_BUF 	7	// cpu -> eth + +#define	_AL4 __attribute__((aligned (4))) + +extern volatile bool link_is_up;	// eth handler sets this + + +// If there's a dbsm that sends to the ethernet, put it's address here +extern dbsm_t *ac_could_be_sending_to_eth; + + +void set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt); + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +bool eth_pkt_inspector(dbsm_t *sm, int bufno); + +void link_changed_callback(int speed); + +bool handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len); + +#endif /* INCLUDED_APP_COMMON_H */ diff --git a/firmware/microblaze/apps/cruft/blink_leds.c b/firmware/microblaze/apps/cruft/blink_leds.c new file mode 100644 index 000000000..682ca8db2 --- /dev/null +++ b/firmware/microblaze/apps/cruft/blink_leds.c @@ -0,0 +1,40 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "nonstdio.h" + +int +main(void) +{ +  int	counter = 0; + +  u2_init(); +   +  putstr("blink_leds\n"); +  while(1){ +    output_regs->leds = (counter++ & 0x3); +  } +   +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/blink_leds2.c b/firmware/microblaze/apps/cruft/blink_leds2.c new file mode 100644 index 000000000..13e78afb3 --- /dev/null +++ b/firmware/microblaze/apps/cruft/blink_leds2.c @@ -0,0 +1,53 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "pic.h" +#include "nonstdio.h" + +//#define DELTA_T  (MASTER_CLK_RATE/2)	// 0.5s (10ns per tick) +#define DELTA_T  5000  		// 5 us (10ns per tick) + + +void +timer_handler(unsigned irq) +{ +  hal_set_timeout(DELTA_T);	// schedule next timeout +  hal_toggle_leds(0x2); +} + +int +main(void) +{ +  u2_init(); + +  putstr("blink_leds2\n"); +  pic_register_handler(IRQ_ONETIME, timer_handler); +  hal_set_timeout(DELTA_T);	// schedule next timeout + +  while(1){ +    hal_toggle_leds(0x1); +  } + +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/buf_ram_test.c b/firmware/microblaze/apps/cruft/buf_ram_test.c new file mode 100644 index 000000000..1aca2aec5 --- /dev/null +++ b/firmware/microblaze/apps/cruft/buf_ram_test.c @@ -0,0 +1,89 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include <stdbool.h> +#include "nonstdio.h" +#include "hal_io.h" +#include "mdelay.h" + + +static void +write_bufs(void) +{ +  int	i, n; +  int	counter = 0; + +  for (n = 0; n < NBUFFERS; n++){ +    volatile int *p = buffer_ram(n); +    for (i = 0; i < BP_NLINES; i++) +      p[i] = counter++; +  } +} + +// return number of errors detected +static int +check_bufs(void) +{ +  int	i, n; +  int	counter = 0; +  int	nerrors = 0; + +  for (n = 0; n < NBUFFERS; n++){ +    volatile int *p = buffer_ram(n); +    for (i = 0; i < BP_NLINES; i++, counter++){ +      int rd = p[i]; +      if (rd != counter){ +	putchar('b'); +	putchar(n + '0'); +	putchar('['); +	puthex16(i); +	putstr("] exp: "); +	puthex32(counter); +	putstr(" got: "); +	puthex32_nl(rd); +	nerrors++; +      } +    } +  } +  return nerrors; +} + + +int +main(void) +{ +  u2_init(); + +  output_regs->leds = 0; + +  write_bufs(); +  int nerrors = check_bufs(); + +  if (nerrors == 0){ +    output_regs->leds = 0x3;		// leds on  -> PASS +    putstr("PASS\n"); +  } +  else { +    output_regs->leds = 0x0;		// leds off -> FAIL +    putstr("FAIL\n"); +  } + +  hal_finish(); +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c new file mode 100644 index 000000000..116d4d8d0 --- /dev/null +++ b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c @@ -0,0 +1,106 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "i2c.h" +#include "usrp2_i2c_addr.h" +#include "mdelay.h" +#include "hal_io.h" +#include "nonstdio.h" +#include <stdbool.h> + + + +int read_dboard_eeprom(int i2c_addr); + + +#define USRP_DBID_DBS_RX          	 0x0002 +#define USRP_DBID_DBS_RX_WITH_CLOCK_MOD  0x000d + +const char dbs_rx_rev2_eeprom[] = { +  0xdb, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18 +}; + +#define	LED_VALS   (LED_A | LED_B | LED_C | LED_D) +#define	LED_MASK   (LED_A | LED_B | LED_C | LED_D) + +int +main(void) +{ +  u2_init(); + +  puts("\nburn_dbsrx_eeprom\n"); + +  hal_set_leds(0, ~0);	// all off + +  int i2c_addr = I2C_ADDR_RX_A; +  int dbid = read_dboard_eeprom(i2c_addr); +  bool ok; +  const char *msg = 0; + +  switch (dbid){ +  case -1: +    msg = "No RX daughterboard found"; +    goto bad; + +  case -2: +    msg = "Invalid RX EEPROM contents"; +    goto bad; + +  case USRP_DBID_DBS_RX_WITH_CLOCK_MOD: +    msg = "RX Daughterboard already reports being a DBS RX w/ CLOCK_MOD"; +    goto good; + +  case USRP_DBID_DBS_RX: +    // Says it's a DBS_RX, attempt to burn the EEPROM +    ok = eeprom_write(i2c_addr, 0, +		      dbs_rx_rev2_eeprom, sizeof(dbs_rx_rev2_eeprom)); +    if (ok){ +      msg = "Successfully programmed db as DBS RX Rev 2.1"; +      goto good; +    } +    else { +      msg = "Failed to write daugherboard eeprom"; +      goto bad; +    } + +  default: +    msg = "Daughterboard is not a DBS RX; ignored"; +    goto bad; +  } +   + good: +  puts(msg); +  hal_set_leds(LED_VALS, LED_MASK); +  while (1) +    ; + + bad: +  puts(msg); +  while(1){ +    hal_toggle_leds(LED_VALS); +    mdelay(50); +  } +} diff --git a/firmware/microblaze/apps/cruft/burnrev30.c b/firmware/microblaze/apps/cruft/burnrev30.c new file mode 100644 index 000000000..40fa53e34 --- /dev/null +++ b/firmware/microblaze/apps/cruft/burnrev30.c @@ -0,0 +1,162 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <clocks.h> +#include "sd.h" +#include "mdelay.h" + +#define HW_REV_MAJOR 3 +#define HW_REV_MINOR 0 + +int test_ram() +{ +  int i,j,k; +  output_regs->ram_page = 1<<10; +   +  extram[0] = 0xDEADBEEF; +  extram[1] = 0xF00D1234; +  extram[7] = 0x76543210; +   +  output_regs->ram_page = 2<<10; +  extram[7] = 0x55555555; +  extram[1] = 0xaaaaaaaa; +  extram[0] = 0xeeeeeeee; +   +  output_regs->ram_page = 1<<10; +   +  i = extram[0]; +  k = extram[1]; +  j = extram[7]; +   +  if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { +    puts("RAM FAIL1!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +   +  output_regs->ram_page = 2<<10; + +  j = extram[7]; +  k = extram[1]; +  i = extram[0]; + +  if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { +    puts("RAM FAIL2!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +  return 1; +} + +int test_sd() +{ +  int i = sd_init(); +  if(i==0) { +    puts("FAILED INIT of Card\n"); +    return 0; +  } +   +  unsigned char buf[512]; +  i = sd_read_block(2048,buf); +  if(i == 0) { +    puts("READ Command Rejected\n"); +    return 0; +  } +  if((buf[0]==0xb8)&&(buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x50)) +    ; +  else { +    puts("Read bad data from SD Card\n"); +    return 0; +  } +  return 1; +} + +int +main(void) +{ +  u2_init(); + +  putstr("\nFactory Test, Board Rev 3.0\n"); + +  bool ok = true; +  unsigned char maj = HW_REV_MAJOR; +  unsigned char min = HW_REV_MINOR; +  ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &maj, 1); +  ok &= eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &min, 1); + +  putstr("\nset_hw_rev\n"); +  if (ok) +    printf("OK: set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); +  else { +    printf("FAILED to set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); +    hal_finish(); +    return 0; +  } + +  if(test_sd()) +    puts("SD OK\n"); +  else { +    puts("SD FAIL\n"); +    //hal_finish(); +    //return 0; +  } +  if(test_ram()) +    puts("RAM OK\n"); +  else { +    puts("RAM FAIL\n"); +    hal_finish(); +    return 0; +  } + +  print_mac_addr(ethernet_mac_addr()->addr); +  newline(); + +  clocks_mimo_config(MC_WE_LOCK_TO_SMA); + +  while (!clocks_lock_detect()) { +    puts("No Lock"); +    mdelay(1000); +  } +  puts("Clock Locked\n"); + +} diff --git a/firmware/microblaze/apps/cruft/burnrev31.c b/firmware/microblaze/apps/cruft/burnrev31.c new file mode 100644 index 000000000..f6b08d187 --- /dev/null +++ b/firmware/microblaze/apps/cruft/burnrev31.c @@ -0,0 +1,162 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <clocks.h> +#include "sd.h" +#include "mdelay.h" + +#define HW_REV_MAJOR 3 +#define HW_REV_MINOR 1 + +int test_ram() +{ +  int i,j,k; +  output_regs->ram_page = 1<<10; +   +  extram[0] = 0xDEADBEEF; +  extram[1] = 0xF00D1234; +  extram[7] = 0x76543210; +   +  output_regs->ram_page = 2<<10; +  extram[7] = 0x55555555; +  extram[1] = 0xaaaaaaaa; +  extram[0] = 0xeeeeeeee; +   +  output_regs->ram_page = 1<<10; +   +  i = extram[0]; +  k = extram[1]; +  j = extram[7]; +   +  if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { +    puts("RAM FAIL1!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +   +  output_regs->ram_page = 2<<10; + +  j = extram[7]; +  k = extram[1]; +  i = extram[0]; + +  if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { +    puts("RAM FAIL2!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +  return 1; +} + +int test_sd() +{ +  int i = sd_init(); +  if(i==0) { +    puts("FAILED INIT of Card\n"); +    return 0; +  } +   +  unsigned char buf[512]; +  i = sd_read_block(2048,buf); +  if(i == 0) { +    puts("READ Command Rejected\n"); +    return 0; +  } +  if((buf[0]==0xb8)&&(buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x50)) +    ; +  else { +    puts("Read bad data from SD Card\n"); +    return 0; +  } +  return 1; +} + +int +main(void) +{ +  u2_init(); + +  putstr("\nFactory Test, Board Rev 3.1\n"); + +  bool ok = true; +  unsigned char maj = HW_REV_MAJOR; +  unsigned char min = HW_REV_MINOR; +  ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &maj, 1); +  ok &= eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &min, 1); + +  putstr("\nset_hw_rev\n"); +  if (ok) +    printf("OK: set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); +  else { +    printf("FAILED to set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); +    hal_finish(); +    return 0; +  } + +  if(test_sd()) +    puts("SD OK\n"); +  else { +    puts("SD FAIL\n"); +    //hal_finish(); +    //return 0; +  } +  if(test_ram()) +    puts("RAM OK\n"); +  else { +    puts("RAM FAIL\n"); +    hal_finish(); +    return 0; +  } + +  print_mac_addr(ethernet_mac_addr()->addr); +  newline(); + +  clocks_mimo_config(MC_WE_LOCK_TO_SMA); + +  while (!clocks_lock_detect()) { +    puts("No Lock"); +    mdelay(1000); +  } +  puts("Clock Locked\n"); + +} diff --git a/firmware/microblaze/apps/cruft/can_i_sub.c b/firmware/microblaze/apps/cruft/can_i_sub.c new file mode 100644 index 000000000..ed49791f0 --- /dev/null +++ b/firmware/microblaze/apps/cruft/can_i_sub.c @@ -0,0 +1,25 @@ +#include <u2_init.h> +#include <nonstdio.h> + +//typedef long long int64_t; + + +int64_t sub(int64_t a, int64_t b); +void print(int64_t d); + +int main(void) +{ +  u2_init(); + +  int64_t d = sub(462550990848000LL, 462028800000000LL); +  print_uint64(d); +  newline(); +  return 0; +} + +int64_t sub(int64_t a, int64_t b) +{ +  return a - b; +} + + diff --git a/firmware/microblaze/apps/cruft/double_buffer_fragment.c b/firmware/microblaze/apps/cruft/double_buffer_fragment.c new file mode 100644 index 000000000..cfc061247 --- /dev/null +++ b/firmware/microblaze/apps/cruft/double_buffer_fragment.c @@ -0,0 +1,138 @@ +#if 0 +void  +double_buffering(int port) { +  unsigned int localstatus = buffer_pool_status->status; + +  if(localstatus & BPS_DONE_0) { +    bp_clear_buf(0); +    if(buffer_state[0] == FILLING) { +      buffer_state[0] = FULL; +      if(buffer_state[1] == EMPTY) { +	bp_receive_to_buf(1, 1, 1, 10, 509);  // DSP_RX to buffer 1, use 500 lines +	buffer_state[1] = FILLING; +      } +      else +	dsp_rx_idle = 1; +      if(serdes_tx_idle) { +	serdes_tx_idle = 0; +	bp_send_from_buf(0, port, 1, 10, 509);  // SERDES_TX from buffer 0 +	buffer_state[0] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[0] = EMPTY; +      if(dsp_rx_idle) { +	dsp_rx_idle = 0; +	bp_receive_to_buf(0, 1, 1, 10, 509);  // DSP_RX to buffer 0, use 500 lines +	buffer_state[0] = FILLING; +      } +      if(buffer_state[1] == FULL) { +	bp_send_from_buf(1, port, 1, 10, 509);  // SERDES_TX from buffer 1 +	buffer_state[1] = EMPTYING; +      } +      else +	serdes_tx_idle = 1; +    } +    putstr("Int Proc'ed 0\n"); +  } + +  if(localstatus & BPS_DONE_1) { +    bp_clear_buf(1); +    if(buffer_state[1] == FILLING) { +      buffer_state[1] = FULL; +      if(buffer_state[0] == EMPTY) { +	bp_receive_to_buf(0, 1, 1, 10, 509);  // DSP_RX to buffer 1, use 500 lines +	buffer_state[0] = FILLING; +      } +      else +	dsp_rx_idle = 1; +      if(serdes_tx_idle) { +	serdes_tx_idle = 0; +	bp_send_from_buf(1, port, 1, 10, 509);  // SERDES_TX from buffer 1 +	buffer_state[1] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[1] = EMPTY; +      if(dsp_rx_idle) { +	dsp_rx_idle = 0; +	bp_receive_to_buf(1, 1, 1, 10, 509);  // DSP_RX to buffer 1, use 500 lines +	buffer_state[1] = FILLING; +      } +      if(buffer_state[0] == FULL) { +	bp_send_from_buf(0, port, 1, 10, 509);  // SERDES_TX from buffer 0 +	buffer_state[0] = EMPTYING; +      } +      else +	serdes_tx_idle = 1; +    } +  putstr("Int Proc'ed 1\n"); +  } + +  if(localstatus & BPS_DONE_2) { +    bp_clear_buf(2); +    if(buffer_state[2] == FILLING) { +      buffer_state[2] = FULL; +      if(buffer_state[3] == EMPTY) { +	bp_receive_to_buf(3, port, 1, 5, 504);  // SERDES_RX to buffer 3, use 500 lines +	buffer_state[3] = FILLING; +      } +      else +	serdes_rx_idle = 1; +      if(dsp_tx_idle) { +	dsp_tx_idle = 0; +	bp_send_from_buf(2, 1, 1, 5, 504);  // DSP_TX from buffer 2 +	buffer_state[2] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[2] = EMPTY; +      if(serdes_rx_idle) { +	serdes_rx_idle = 0; +	bp_receive_to_buf(2, port, 1, 5, 504);  // SERDES_RX to buffer 2 +	buffer_state[2] = FILLING; +      } +      if(buffer_state[3] == FULL) { +	bp_send_from_buf(3, 1, 1, 5, 504);  // DSP_TX from buffer 3 +	buffer_state[3] = EMPTYING; +      } +      else +	dsp_tx_idle = 1; +    } +  putstr("Int Proc'ed 2\n"); +  } + +  if(localstatus & BPS_DONE_3) { +    bp_clear_buf(3); +    if(buffer_state[3] == FILLING) { +      buffer_state[3] = FULL; +      if(buffer_state[2] == EMPTY) { +	bp_receive_to_buf(2, port, 1, 5, 504);  // SERDES_RX to buffer 2, use 500 lines +	buffer_state[2] = FILLING; +      } +      else +	serdes_rx_idle = 1; +      if(dsp_tx_idle) { +	dsp_tx_idle = 0; +	bp_send_from_buf(3, 1, 1, 5, 504);  // DSP_TX from buffer 3 +	buffer_state[3] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[3] = EMPTY; +      if(serdes_rx_idle) { +	serdes_rx_idle = 0; +	bp_receive_to_buf(3, port, 1, 5, 504);  // SERDES_RX to buffer 3 +	buffer_state[3] = FILLING; +      } +      if(buffer_state[2] == FULL) { +	bp_send_from_buf(2, 1, 1, 5, 504);  // DSP_TX from buffer 2 +	buffer_state[2] = EMPTYING; +      } +      else +	dsp_tx_idle = 1; +    } +  putstr("Int Proc'ed 3\n"); +  } +} +#endif diff --git a/firmware/microblaze/apps/cruft/echo.c b/firmware/microblaze/apps/cruft/echo.c new file mode 100644 index 000000000..89108ee80 --- /dev/null +++ b/firmware/microblaze/apps/cruft/echo.c @@ -0,0 +1,34 @@ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "stdio.h" + +int +main(void) +{ +  u2_init(); + +  puts("\n>>> echo <<<"); + +  while (1){ +    int ch = getchar(); +    putchar(ch); +  } + +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/eth_serdes.c b/firmware/microblaze/apps/cruft/eth_serdes.c new file mode 100644 index 000000000..2d2ddc1ca --- /dev/null +++ b/firmware/microblaze/apps/cruft/eth_serdes.c @@ -0,0 +1,233 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_passthru_v2.h" +#include "memcpy_wa.h" +#include "clocks.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +#define FW_SETS_SEQNO	1	// define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno __attribute__((unused));	// used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between ethernet and serdes + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu + +#define	DSP_RX_BUF_0	2	// serdes -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// serdes -> eth +#define	DSP_TX_BUF_0	4	// eth -> serdes (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> serdes + +/* + * ================================================================ + *   configure serdes double buffering state machine (eth -> serdes) + * ================================================================ + */ + + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_ETH, +  0, +  BP_LAST_LINE +}; + +// send to serdes +buf_cmd_args_t dsp_tx_send_args = { +  PORT_SERDES, +  0, +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + +/* + * ==================================================================== + *   configure serdes RX double buffering state machine (serdes -> eth) + * ==================================================================== + */ + +// receive from serdes +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_SERDES, +  0, +  BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { +  PORT_ETH, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from list_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// ---------------------------------------------------------------- + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY.  This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet.  A bit of a kludge + * but it should work. + */ + +bool  +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this)	// returns false +{ +#if 0 +  uint32_t *p = buffer_ram(buf_this); +  uint32_t last_line = buffer_pool_status->last_line[buf_this] - sm->last_line_adj; +  printf("fw_sets_seqno_inspector: buf_this = %d, last_line = %d\n", +	 buf_this, last_line); + +  print_buffer(p, (last_line + 1)); +#endif + +#if 0 +  uint32_t *p = buffer_ram(buf_this); +  uint32_t seqno = fw_seqno++; + +  // KLUDGE all kinds of nasty magic numbers and embedded knowledge +  uint32_t t = p[4]; +  t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); +  p[4] = t; +#endif + +  return false;		// we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  if (0 && (status & ~BPS_IDLE_ALL)){ +    putstr("status = "); +    puthex32_nl(status); +  } +     +  dbsm_process_status(&dsp_tx_sm, status); +  dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ +  u2_init(); + +  output_regs->led_src = 0x3;		// h/w controls bottom two bits +  clocks_enable_test_clk(true, 1); + +  putstr("\neth <-> serdes\n"); + +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + +  // clocks_mimo_config(MC_WE_LOCK_TO_SMA | MC_PROVIDE_CLK_TO_MIMO); +  clocks_mimo_config(MC_WE_DONT_LOCK | MC_PROVIDE_CLK_TO_MIMO); + +#if 0 +  // make bit 15 of Tx gpio's be a s/w output +  hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +#if 1 +  output_regs->debug_mux_ctrl = 1; +  hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); +  hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + +  // initialize double buffering state machine for ethernet -> serdes + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    eth_pkt_inspector); + + +  // initialize double buffering state machine for serdes -> ethernet + +  if (FW_SETS_SEQNO){ +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      fw_sets_seqno_inspector); +  } +  else { +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      dbsm_nop_inspector); +  } + +  // tell app_common that this dbsm could be sending to the ethernet +  ac_could_be_sending_to_eth = &dsp_rx_sm; + + +  // kick off the state machines +  dbsm_start(&dsp_tx_sm); +  dbsm_start(&dsp_rx_sm); + +  //int which = 0; + +  while(1){ +    // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); +    // which ^= 0x8000; + +    buffer_irq_handler(0); +  } +} diff --git a/firmware/microblaze/apps/cruft/factory_test.c b/firmware/microblaze/apps/cruft/factory_test.c new file mode 100644 index 000000000..e1fbb0e40 --- /dev/null +++ b/firmware/microblaze/apps/cruft/factory_test.c @@ -0,0 +1,438 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <clocks.h> +#include "sd.h" + +#define FW_SETS_SEQNO	1	// define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno;	// used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between ethernet and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu + +#define	DSP_RX_BUF_0	2	// dsp rx -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> eth +#define	DSP_TX_BUF_0	4	// eth -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> dsp tx + +/* + * ================================================================ + *   configure DSP TX double buffering state machine (eth -> dsp) + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_ETH, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past transport header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + +/* + * ================================================================ + *   configure DSP RX double buffering state machine (dsp -> eth) + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_DSP, +  DSP_RX_FIRST_LINE, +  BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { +  PORT_ETH, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from list_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool         streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int          streaming_frame_count = 0; +#define FRAMES_PER_CMD	1000 + +bool is_streaming(void){ return streaming_p; } + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ +  // setup RX DSP regs +  dsp_rx_regs->clear_state = 1;			// reset + +  streaming_p = true; +  streaming_frame_count = FRAMES_PER_CMD; + +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);			// set "chain" bit + +  // kick off the state machine +  dbsm_start(&dsp_rx_sm); + +  dsp_rx_regs->rx_time = 0;		// enqueue first of two commands + +  // make sure this one and the rest have the "now" and "chain" bits set. +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);				 + +  dsp_rx_regs->rx_time = 0;		// enqueue second command +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ +  host_mac_addr = *host;	// remember who we're sending to + +  /* +   * Construct  ethernet header and word0 and preload into two buffers +   */ +  u2_eth_packet_t	pkt; +  memset(&pkt, 0, sizeof(pkt)); +  pkt.ehdr.dst = *host; +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; +  u2p_set_word0(&pkt.fixed, 0, 0); +  // DSP RX will fill in timestamp + +  memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); +  memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + +  if (FW_SETS_SEQNO) +    fw_seqno = 0; + +  streaming_items_per_frame = p->items_per_frame; +  restart_streaming(); +} + + +void +stop_rx_cmd(void) +{ +  streaming_p = false; +  dsp_rx_regs->clear_state = 1;	// flush cmd queue +  bp_clear_buf(DSP_RX_BUF_0); +  bp_clear_buf(DSP_RX_BUF_1); +} + + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +  int tx_scale = 256; +  int interp = 32; + +  // setup some defaults + +  dsp_tx_regs->freq = 0; +  dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; +  dsp_tx_regs->interp_rate = interp; +} + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY.  This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet.  A bit of a kludge + * but it should work. + */ +bool  +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this)	// returns false +{ +  uint32_t *p = buffer_ram(buf_this); +  uint32_t seqno = fw_seqno++; + +  // KLUDGE all kinds of nasty magic numbers and embedded knowledge +  uint32_t t = p[4]; +  t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); +  p[4] = t; + +  // queue up another rx command when required +  if (streaming_p && --streaming_frame_count == 0){ +    streaming_frame_count = FRAMES_PER_CMD; +    dsp_rx_regs->rx_time = 0; +  } + +  return false;		// we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  dbsm_process_status(&dsp_tx_sm, status); +  dbsm_process_status(&dsp_rx_sm, status); +} + +int test_ram() +{ +  int i,j,k; +  output_regs->ram_page = 1<<10; +   +  extram[0] = 0xDEADBEEF; +  extram[1] = 0xF00D1234; +  extram[7] = 0x76543210; +   +  output_regs->ram_page = 2<<10; +  extram[7] = 0x55555555; +  extram[1] = 0xaaaaaaaa; +  extram[0] = 0xeeeeeeee; +   +  output_regs->ram_page = 1<<10; +   +  i = extram[0]; +  k = extram[1]; +  j = extram[7]; +   +  if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { +    puts("RAM FAIL1!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +   +  output_regs->ram_page = 2<<10; + +  j = extram[7]; +  k = extram[1]; +  i = extram[0]; + +  if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { +    puts("RAM FAIL2!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +  return 1; +} + +int test_sd() +{ +  int i = sd_init(); +  if(i==0) { +    puts("FAILED INIT of Card\n"); +    return 0; +  } +   +  unsigned char buf[512]; +  i = sd_read_block(2048,buf); +  if(i == 0) { +    puts("READ Command Rejected\n"); +    return 0; +  } +  if((buf[0]==0xb8)&&(buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x50)) +    ; +  else { +    puts("Read bad data from SD Card\n"); +    return 0; +  } +  return 1; +} + +int +main(void) +{ +  u2_init(); + +  putstr("\nFactory Test\n"); + +  print_mac_addr(ethernet_mac_addr()->addr); +  newline(); + +  if(test_sd()) +    puts("SD OK\n"); +  else { +    puts("SD FAIL\n"); +    //    hal_finish(); +    //return 0; +  } +  if(test_ram()) +    puts("RAM OK\n"); +  else { +    puts("RAM FAIL\n"); +    hal_finish(); +    return 0; +  } + +  print_mac_addr(ethernet_mac_addr()->addr); +  newline(); + +  output_regs->led_src = 0x7;  // make bottom 3 controlled by HW + +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + +  clocks_enable_tx_dboard(true,1); +  clocks_mimo_config(MC_WE_LOCK_TO_SMA); +#if 0 +  // make bit 15 of Tx gpio's be a s/w output +  hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +  output_regs->debug_mux_ctrl = 1; +#if 0 +  hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); +  hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    eth_pkt_inspector); + + +  // initialize double buffering state machine for DSP RX -> Ethernet + +  if (FW_SETS_SEQNO){ +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      fw_sets_seqno_inspector); +  } +  else { +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      dbsm_nop_inspector); +  } + +  // tell app_common that this dbsm could be sending to the ethernet +  ac_could_be_sending_to_eth = &dsp_rx_sm; + + +  // program tx registers +  setup_tx(); + +  // kick off the state machine +  dbsm_start(&dsp_tx_sm); + +  //int which = 0; + +  while(1){ +    // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); +    // which ^= 0x8000; + +    buffer_irq_handler(0); + +    int pending = pic_regs->pending;		// poll for under or overrun + +    if (pending & PIC_UNDERRUN_INT){ +      dbsm_handle_tx_underrun(&dsp_tx_sm); +      pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt +      putchar('U'); +    } + +    if (pending & PIC_OVERRUN_INT){ +      dbsm_handle_rx_overrun(&dsp_rx_sm); +      pic_regs->pending = PIC_OVERRUN_INT;	// clear pending interrupt + +      // FIXME Figure out how to handle this robustly. +      // Any buffers that are emptying should be allowed to drain... + +      if (streaming_p){ +	// restart_streaming(); +	// FIXME report error +      } +      else { +	// FIXME report error +      } +      putchar('O'); +    } +  } +} diff --git a/firmware/microblaze/apps/cruft/gen_eth_packets.c b/firmware/microblaze/apps/cruft/gen_eth_packets.c new file mode 100644 index 000000000..4d521f6bf --- /dev/null +++ b/firmware/microblaze/apps/cruft/gen_eth_packets.c @@ -0,0 +1,187 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "memcpy_wa.h" +#include "print_rmon_regs.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +// ---------------------------------------------------------------- + +static eth_mac_addr_t dst_mac_addr = +  {{  0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}; + +// ---------------------------------------------------------------- + +// #define	PACKET_SIZE 1500		// bytes +// #define ETH_DATA_RATE 1000000		// 1MB/s +// #define	ETH_PACKET_RATE (ETH_DATA_RATE/PACKET_SIZE)	// 13,3333 pkts/s + +// static int timer_delta = MASTER_CLK_RATE/ETH_PACKET_RATE;	// ticks between interrupts + +static int timer_delta = (int)(MASTER_CLK_RATE * 1e-3);		// tick at 1 kHz +static int sim_timer_delta = (int)(MASTER_CLK_RATE * 100e-6);	// tick at 10 kHz + +static volatile bool send_packet_now = false;   // timer handler sets this +static volatile bool link_is_up = false;	// eth handler sets this + +int packet_number = 0; + + +#define CPU_TX_BUF	0	// cpu xmits ethernet frames from here +#define CPU_RX_BUF	1	// receive ethernet frames here + +// ---------------------------------------------------------------- + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ +  link_is_up = speed == 0 ? false : true; +  hal_set_leds(link_is_up ? 0x2 : 0x0, 0x2); +  printf("\neth link changed: speed = %d\n", speed); +} + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +  send_packet_now = 1; +} + + +static void +init_packet(int *buf, const u2_eth_packet_t *pkt, int bufnum) +{ +  int i = 0; +  int mark = ((bufnum & 0xff) << 24) | 0x005A0000; + +  for (i = 0; i < BP_NLINES; i++){ +    buf[i] = mark | i; +    mark ^= 0x00FF0000; +  } + +  // copy header into buffer +  memcpy_wa(buf, pkt, sizeof(*pkt)); +} + +static void +init_packets(void) +{ +  u2_eth_packet_t	pkt __attribute__((aligned (4))); + +  memset(&pkt, 0, sizeof(pkt)); + +  pkt.ehdr.dst = dst_mac_addr; +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; +  pkt.fixed.word0 = 0x01234567; +  pkt.fixed.timestamp = 0xffffffff; + +  // init just the one we're using +  init_packet((void *)buffer_ram(CPU_TX_BUF), &pkt, CPU_TX_BUF); +} + +int +main(void) +{ +  int npackets_sent = 0; + +  u2_init(); + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + +  putstr("\ngen_eth_packets\n"); +   +  hal_set_leds(0x0, 0x3); + +  init_packets(); + +  pic_register_handler(IRQ_TIMER, timer_irq_handler); + +  if (hwconfig_simulation_p()) +    timer_delta = sim_timer_delta; + +  hal_set_timeout(timer_delta); + +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + +  /* +  if (hwconfig_simulation_p()){ +    eth_mac->speed = 4;	// hardcode mac speed to 1000 +    link_is_up = true; +  } +  */ + +  // fire off a receive from the ethernet +  bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE); + +  while(1){ +    uint32_t status = buffer_pool_status->status; + +    if (status & (BPS_DONE(CPU_RX_BUF) | BPS_ERROR(CPU_RX_BUF))){ +      bp_clear_buf(CPU_RX_BUF); +      // ignore incoming ethernet packets; they were looped back in sim +      bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE); +    } + +    if (status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))){ +      if (status & BPS_ERROR(CPU_TX_BUF)){ +	putchar('E'); +      } +      bp_clear_buf(CPU_TX_BUF); +      npackets_sent++; +      if ((npackets_sent & 0xF) == 0){	// print after every 16 packets +	//print_rmon_regs(); +	putchar('.'); +      } +    } + +    if (link_is_up && send_packet_now && (status & BPS_IDLE(CPU_TX_BUF))){ +      send_packet_now = false; + +      // kick off the next packet +      // FIXME set packet number in packet + +      bp_send_from_buf(CPU_TX_BUF, PORT_ETH, 1, 0, 255);	// 1KB total +      hal_toggle_leds(0x1); +    } +  } + +  hal_finish(); +  return 1; +} diff --git a/firmware/microblaze/apps/cruft/gen_pause_frames.c b/firmware/microblaze/apps/cruft/gen_pause_frames.c new file mode 100644 index 000000000..0f81dafff --- /dev/null +++ b/firmware/microblaze/apps/cruft/gen_pause_frames.c @@ -0,0 +1,207 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "u2_eth_packet.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> + + +// ---------------------------------------------------------------- + +unsigned char dst_mac_addr[6] = { +  0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +// ---------------------------------------------------------------- + +// #define	PACKET_SIZE 1500		// bytes +// #define ETH_DATA_RATE 1000000		// 1MB/s +// #define	ETH_PACKET_RATE (ETH_DATA_RATE/PACKET_SIZE)	// 13,3333 pkts/s + +// static int timer_delta = MASTER_CLK_RATE/ETH_PACKET_RATE;	// ticks between interrupts + +static int timer_delta = MASTER_CLK_RATE/1000;	// tick at 1kHz + +static volatile bool send_packet_now = false;   // timer handler sets this +static volatile bool link_is_up = false;	// eth handler sets this + +int packet_number = 0; + +// ---------------------------------------------------------------- + +// debugging output on tx pins +#define LS_MASK  0xE0000 +#define LS_1000  0x80000 +#define LS_100   0x40000 +#define LS_10    0x20000 + + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ +  int v = 0; +  switch(speed){ +  case 10: +    v = LS_10; +    link_is_up = true; +    break; +     +  case 100: +    v = LS_100; +    link_is_up = true; +    break; +     +  case 1000: +    v = LS_100; +    link_is_up = true; +    break; + +  default: +    v = 0; +    link_is_up = false; +    break; +  } + +  hal_gpio_set_tx(v, LS_MASK);	/* set debug bits on d'board */ + +  putstr("\neth link changed: speed = "); +  puthex16_nl(speed); +} + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +  send_packet_now = 1; +} + + +void +buffer_irq_handler(unsigned irq) +{ +  // FIXME +} + +static void +init_packet(int *buf, const u2_eth_packet_t *pkt, int bufnum) +{ +  int i = 0; +  int mark = ((bufnum & 0xff) << 24) | 0x005A0000; + +  for (i = 0; i < BP_NLINES; i++){ +    buf[i] = mark | i; +    mark ^= 0x00FF0000; +  } + +  // copy header into buffer +  memcpy_wa(buf, pkt, sizeof(*pkt)); +} + +static void +init_packets(void) +{ +  int	i; +   +  u2_eth_packet_t	pkt __attribute__((aligned (4))); + +  for (i = 0; i < 6; i++){ +    pkt.ehdr.dst.addr[i] = dst_mac_addr[i]; +  } +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; + +  // fill ALL buffers for debugging +  for (i = 0; i < 8; i++) +    init_packet((void *)buffer_ram(i), &pkt, i); +} + +static int led_counter = 0; + +int +main(void) +{ +  int send_pause = 1; +   +  u2_init(); + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + +  putstr("\ngen_eth_packets\n"); +   +  // Control LEDs +  output_regs->leds = 0x00; + +  init_packets(); + +  // pic_register_handler(IRQ_BUFFER, buffer_irq_handler);  // poll for now +  pic_register_handler(IRQ_TIMER, timer_irq_handler); +  hal_set_timeout(timer_delta); + +  ethernet_register_link_changed_callback(link_changed_callback); + +  ethernet_init(); + +  eth_mac->pause_frame_send_en = 1; +  eth_mac->pause_quanta_set = 16384 / 512; + +  // eth_mac->speed = 4;	// FIXME hardcode mac speed to 1000 + +  while(1){ +    if (link_is_up && send_packet_now){ +      send_packet_now = false; + + +      if (send_pause) +	eth_mac->xon_cpu = 1; +      else +	eth_mac->xon_cpu = 0; + +      send_pause ^= 1; + +      // kick off the next packet +      // FIXME set packet number in packet + +#if 0 +      bp_send_from_buf(0, PORT_ETH, 1, 0, 255);	// 1KB total + +      while ((buffer_pool_status->status & (BPS_DONE_0|BPS_ERROR_0)) == 0) +	; +      bp_clear_buf(0); +#endif + +      output_regs->leds = ((++led_counter) & 0x1) | (link_is_up ? 0x2 : 0x0); +    } +  } + +  hal_finish(); +  return 1; +} diff --git a/firmware/microblaze/apps/cruft/hello.c b/firmware/microblaze/apps/cruft/hello.c new file mode 100644 index 000000000..bce843093 --- /dev/null +++ b/firmware/microblaze/apps/cruft/hello.c @@ -0,0 +1,30 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "stdio.h" + +int +main(void) +{ +  u2_init(); + +  puts("Hello World"); +  puts("Goodbye World"); + +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/ibs_rx_test.c b/firmware/microblaze/apps/cruft/ibs_rx_test.c new file mode 100644 index 000000000..bdc04747e --- /dev/null +++ b/firmware/microblaze/apps/cruft/ibs_rx_test.c @@ -0,0 +1,82 @@ +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "nonstdio.h" + +#define PORT 2    // ethernet = 2, serdes = 0 +int dsp_rx_buf, dsp_tx_buf, serdes_rx_buf, serdes_tx_buf; +int dsp_rx_idle, dsp_tx_idle, serdes_rx_idle, serdes_tx_idle; + +int buffer_state[4]; + +static void __attribute__((unused)) +wait_until_status_nonzero(void)  +{ +  while (buffer_pool_status->status == 0) +    ; +} + +int +main(void) +{ +  int i; +   +  u2_init(); + +  output_regs->adc_ctrl = 0x0A; + +  dsp_rx_regs->freq = 0; +  dsp_rx_regs->scale_iq = (1 << 16) | 1; +  dsp_rx_regs->decim_rate = 8; + +  volatile unsigned int *buffer0 = buffer_ram(0); +  volatile unsigned int *buffer1 = buffer_ram(1); +  volatile unsigned int *buffer2 = buffer_ram(2); +   +  putstr("Starting RX\n"); +  bp_clear_buf(0); +  bp_receive_to_buf(0, 1, 1, 0, 99); + +  dsp_rx_regs->rx_command = (50 << 9) | 100;   // Numlines, lines per frame +  dsp_rx_regs->rx_time = 0x2000; + +  dsp_rx_regs->rx_command = (137 << 9) | 50;   // Numlines, lines per frame +  dsp_rx_regs->rx_time = 0x2200; + +  while (buffer_pool_status->status == 0) +    ; +  bp_clear_buf(0); +  bp_clear_buf(1); +  bp_receive_to_buf(1, 1, 1, 0, 99); +  while (buffer_pool_status->status == 0) +    ; +  bp_clear_buf(2); +  bp_receive_to_buf(2, 1, 1, 0, 99); +  while (buffer_pool_status->status == 0) +    ; +   +  for(i=0;i<100;i++) { +    puthex(i); +    putstr("   "); +    puthex_nl(buffer0[i]); +  } +  for(i=0;i<60;i++) { +    puthex(i); +    putstr("   "); +    puthex_nl(buffer1[i]); +  } +  for(i=0;i<60;i++) { +    puthex(i); +    putstr("   "); +    puthex_nl(buffer2[i]); +  } +  //while(timer_regs -> time < 0x6000) +  //  {} + +  putstr("Done\n"); +  hal_finish(); +   +  return 1; +} diff --git a/firmware/microblaze/apps/cruft/ibs_tx_test.c b/firmware/microblaze/apps/cruft/ibs_tx_test.c new file mode 100644 index 000000000..ff9446d92 --- /dev/null +++ b/firmware/microblaze/apps/cruft/ibs_tx_test.c @@ -0,0 +1,160 @@ +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "nonstdio.h" + +// Globals +#define EMPTY 0 +#define FILLING 1 +#define FULL 2 +#define EMPTYING 3 + +#define PORT 2    // ethernet = 2, serdes = 0 +int dsp_rx_buf, dsp_tx_buf, serdes_rx_buf, serdes_tx_buf; +int dsp_rx_idle, dsp_tx_idle, serdes_rx_idle, serdes_tx_idle; + +int buffer_state[4]; + +static void +wait_until_status_nonzero(void) +{ +  while (buffer_pool_status->status == 0) +    ; +} + +int +main(void) +{ +  int i; +   +  u2_init(); +   +  dsp_tx_regs->freq = 0; +  dsp_tx_regs->scale_iq = (1 << 16) | 1; +  dsp_tx_regs->interp_rate = 8; + +  // Write data to be sent into the first buffer +  volatile unsigned int *buffer0 = buffer_ram(0); +  volatile unsigned int *buffer1 = buffer_ram(1); +   + +  putstr("Starting to fill in RAM\n"); +  for(i=0;i<512;i++)  +    buffer0[i] = i; +  putstr("Filled in RAM\n"); +   +  buffer0[0] = 7; // start and end of buffer, send immediately +  buffer0[1] = 0x0000;  // start time +  bp_clear_buf(0); +  bp_send_from_buf(0, 1, 1, 0, 9); +  while (buffer_pool_status->status == 0) +    ; +  while(timer_regs -> time < 0x6000) +    {} + +  buffer0[0] = 3; // start and end of buffer +  buffer0[1] = 0x8000;  // start time +  bp_clear_buf(0); +  bp_send_from_buf(0, 1, 1, 0, 9); +  while (buffer_pool_status->status == 0) +    ; +  while(timer_regs -> time < 0x8400) +    {} + +  buffer0[0] = 3; // start and end of buffer +  buffer0[1] = 0x8800;  // start time +  bp_clear_buf(0); +  bp_send_from_buf(0, 1, 1, 0, 9); +  while (buffer_pool_status->status == 0) +    ; +  while(timer_regs -> time < 0x9000) +    {} + +  buffer0[0] = 0x2;  // not last +  buffer0[1] = 0x9100;  // start time +  bp_clear_buf(0); +  bp_send_from_buf(0, 1, 1, 0, 9); +  while (buffer_pool_status->status == 0) +    ; +  buffer0[0] = 0x1;  // last +  buffer0[1] = 0x0000;  // start time +  bp_clear_buf(0); +  bp_send_from_buf(0, 1, 1, 0, 9); +  while (buffer_pool_status->status == 0) +    ; + +   +  buffer0[0] = 0x3;  // first and last +  buffer0[1] = 0x8000;  // Time in the past +  bp_clear_buf(0); +  bp_send_from_buf(0, 1, 1, 0, 9); +  while (buffer_pool_status->status == 0) +    ; + +  /* +  buffer0[0] = 0x2; // not last +  buffer0[1] = 0x9600;  // start time +  bp_clear_buf(0); +  bp_send_from_buf(0, 1, 1, 0, 9); +  while (buffer_pool_status->status == 0) +    ; +  */ + +  while(timer_regs -> time < 0xa000) +    {} + +  putstr("Done\n"); + +  while(1) +    {} +  hal_finish(); +   +  // Send a bunch, let them pile up in FIFO +  bp_send_from_buf(0, 2, 1, 21, 80);    wait_until_status_nonzero(); +  bp_clear_buf(0); +  putstr("First add'l TX done\n"); +  bp_send_from_buf(0, 2, 1, 81, 288);   wait_until_status_nonzero(); +  bp_clear_buf(0); +  bp_send_from_buf(0, 2, 1, 289, 292);  wait_until_status_nonzero(); +  bp_clear_buf(0); +  bp_send_from_buf(0, 2, 1, 293, 326);  wait_until_status_nonzero(); +  bp_clear_buf(0); +  bp_send_from_buf(0, 2, 1, 327, 399);  wait_until_status_nonzero(); +  bp_clear_buf(0); +  bp_send_from_buf(0, 2, 1, 400, 511);  wait_until_status_nonzero(); +  bp_clear_buf(0); +  putstr("All add'l TX done\n"); +   +  bp_receive_to_buf(1, 2, 1, 21, 80);   wait_until_status_nonzero(); +  bp_clear_buf(1); +  putstr("First add'l RX done\n"); +  bp_receive_to_buf(1, 2, 1, 81, 288);  wait_until_status_nonzero(); +  bp_clear_buf(1); +  bp_receive_to_buf(1, 2, 1, 289, 292); wait_until_status_nonzero(); +  bp_clear_buf(1); +  bp_receive_to_buf(1, 2, 1, 293, 326); wait_until_status_nonzero(); +  bp_clear_buf(1); +  bp_receive_to_buf(1, 2, 1, 327, 399); wait_until_status_nonzero(); +  bp_clear_buf(1); +  bp_receive_to_buf(1, 2, 1, 400, 511); wait_until_status_nonzero(); +  bp_clear_buf(1); +  putstr("All add'l RX done\n"); + +  for(i=0;i<512;i++) +    if(buffer0[i] != buffer1[i]) { +      putstr("ERROR at location: "); +      puthex_nl(i); +      putstr("Value sent: "); +      puthex_nl(buffer0[i]); +      putstr("Value rcvd: "); +      puthex_nl(buffer1[i]); +      //break; +    } +   +  putstr("Done Testing\n"); +   +  hal_finish(); +  return 1; +} diff --git a/firmware/microblaze/apps/cruft/mimo_app_common_v2.c b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c new file mode 100644 index 000000000..5dbecb0d0 --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c @@ -0,0 +1,582 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mimo_app_common_v2.h" +#include "buffer_pool.h" +#include "memcpy_wa.h" +#include "ethernet.h" +#include "nonstdio.h" +#include "print_rmon_regs.h" +#include "db.h" +#include "db_base.h" +#include "clocks.h" +#include "u2_init.h" +#include <string.h> + +volatile bool link_is_up = false;	// eth handler sets this +int cpu_tx_buf_dest_port = PORT_ETH; + +// If this is non-zero, this dbsm could be writing to the ethernet +dbsm_t *ac_could_be_sending_to_eth; + +static unsigned char exp_seqno __attribute__((unused)) = 0; + +void abort(void); + +static bool +burn_mac_addr(const op_burn_mac_addr_t *p) +{ +  return ethernet_set_mac_addr(&p->addr); +} + +static bool +sync_to_pps(const op_generic_t *p) +{ +  timesync_regs->sync_on_next_pps = 1; +  putstr("SYNC to PPS\n"); +  return true; +} + +static bool +config_mimo_cmd(const op_config_mimo_t *p) +{ +  clocks_mimo_config(p->flags); +  return true; +} + +void +set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt) +{ +  reply_pkt->ehdr.dst = cmd_pkt->ehdr.src; +  reply_pkt->ehdr.src = *ethernet_mac_addr(); +  reply_pkt->ehdr.ethertype = U2_ETHERTYPE; +  reply_pkt->thdr.flags = 0; +  reply_pkt->thdr.fifo_status = 0;	// written by protocol engine +  reply_pkt->thdr.seqno = 0;		// written by protocol engine +  reply_pkt->thdr.ack = 0;		// written by protocol engine +  u2p_set_word0(&reply_pkt->fixed, 0, CONTROL_CHAN); +  reply_pkt->fixed.timestamp = timer_regs->time; +} + +static void +send_reply(unsigned char *reply, size_t reply_len) +{ +  if (reply_len < 64) +    reply_len = 64; + +  // wait for buffer to become idle +  hal_set_leds(0x4, 0x4); +  while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0) +    ; +  hal_set_leds(0x0, 0x4); + +  // copy reply into CPU_TX_BUF +  memcpy_wa(buffer_ram(CPU_TX_BUF), reply, reply_len); + +  // wait until nobody else is sending to the ethernet +  if (ac_could_be_sending_to_eth){ +    hal_set_leds(0x8, 0x8); +    dbsm_wait_for_opening(ac_could_be_sending_to_eth); +    hal_set_leds(0x0, 0x8); +  } + +  if (0){ +    printf("sending_reply to port %d, len = %d\n", cpu_tx_buf_dest_port, (int)reply_len); +    print_buffer(buffer_ram(CPU_TX_BUF), reply_len/4); +  } + +  // fire it off +  bp_send_from_buf(CPU_TX_BUF, cpu_tx_buf_dest_port, 1, 0, reply_len/4); + +  // wait for it to complete (not long, it's a small pkt) +  while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0) +    ; + +  bp_clear_buf(CPU_TX_BUF); +} + + +static size_t +op_id_cmd(const op_generic_t *p, +	  void *reply_payload, size_t reply_payload_space) +{ +  op_id_reply_t *r = (op_id_reply_t *) reply_payload; +  if (reply_payload_space < sizeof(*r))	// no room +    return 0; + +  // Build reply subpacket + +  r->opcode = OP_ID_REPLY; +  r->len = sizeof(op_id_reply_t); +  r->rid = p->rid; +  r->addr = *ethernet_mac_addr(); +  r->hw_rev = (u2_hw_rev_major << 8) | u2_hw_rev_minor; +  // r->fpga_md5sum = ;	// FIXME +  // r->sw_md5sum = ;	// FIXME + +  return r->len; +} + + +static size_t +config_tx_v2_cmd(const op_config_tx_v2_t *p, +		 void *reply_payload, size_t reply_payload_space) +{ +  op_config_tx_reply_v2_t *r = (op_config_tx_reply_v2_t *) reply_payload; +  if (reply_payload_space < sizeof(*r)) +    return 0;					// no room + +  struct tune_result	tune_result; +  memset(&tune_result, 0, sizeof(tune_result)); + +  bool ok = true; +   +#if 0 +  if (p->valid & CFGV_GAIN){ +    ok &= db_set_gain(tx_dboard, p->gain); +  } + +  if (p->valid & CFGV_FREQ){ +    bool was_streaming = is_streaming(); +    if (was_streaming) +      stop_rx_cmd(); +     +    u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo); +    bool tune_ok = db_tune(tx_dboard, f, &tune_result); +    ok &= tune_ok; +    print_tune_result("Tx", tune_ok, f, &tune_result); + +    if (was_streaming) +      restart_streaming(); +  } + +  if (p->valid & CFGV_INTERP_DECIM){ +    int interp = p->interp; +    int hb1 = 0; +    int hb2 = 0; + +    if (!(interp & 1)){ +      hb2 = 1; +      interp = interp >> 1; +    } + +    if (!(interp & 1)){ +      hb1 = 1; +      interp = interp >> 1; +    } +     +    if (interp < MIN_CIC_INTERP || interp > MAX_CIC_INTERP) +      ok = false; +    else { +      dsp_tx_regs->interp_rate = (hb1<<9) | (hb2<<8) | interp; +      // printf("Interp: %d, register %d\n", p->interp, (hb1<<9) | (hb2<<8) | interp); +    } +  } + +  if (p->valid & CFGV_SCALE_IQ){ +    dsp_tx_regs->scale_iq = p->scale_iq; +  } +#endif + +  // Build reply subpacket + +  r->opcode = OP_CONFIG_TX_REPLY_V2; +  r->len = sizeof(*r); +  r->rid = p->rid; +  r->ok = ok; +  r->inverted = tune_result.inverted; +  r->baseband_freq_hi = u2_fxpt_freq_hi(tune_result.baseband_freq); +  r->baseband_freq_lo = u2_fxpt_freq_lo(tune_result.baseband_freq); +  r->duc_freq_hi = u2_fxpt_freq_hi(tune_result.dxc_freq); +  r->duc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq); +  r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq); +  r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq); +  return r->len; +} + +static size_t +config_rx_v2_cmd(const op_config_rx_v2_t *p,  +		 void *reply_payload, size_t reply_payload_space) +{ +  op_config_rx_reply_v2_t *r = (op_config_rx_reply_v2_t *) reply_payload; +  if (reply_payload_space < sizeof(*r)) +    return 0;				// no room + +  struct tune_result	tune_result; +  memset(&tune_result, 0, sizeof(tune_result)); + +  bool ok = true; +   +  if (p->valid & CFGV_GAIN){ +    ok &= db_set_gain(rx_dboard, p->gain); +  } + +  if (p->valid & CFGV_FREQ){ +    bool was_streaming = is_streaming(); +    if (was_streaming) +      stop_rx_cmd(); +     +    u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo); +    bool tune_ok = db_tune(rx_dboard, f, &tune_result); +    ok &= tune_ok; +    print_tune_result("Rx", tune_ok, f, &tune_result); + +    if (was_streaming) +      restart_streaming(); +  } + +  if (p->valid & CFGV_INTERP_DECIM){ +    int decim = p->decim; +    int hb1 = 0; +    int hb2 = 0; +     +    if(!(decim & 1)) { +      hb2 = 1; +      decim = decim >> 1; +    } +     +    if(!(decim & 1)) { +      hb1 = 1; +      decim = decim >> 1; +    } +     +    if (decim < MIN_CIC_DECIM || decim > MAX_CIC_DECIM) +      ok = false; +    else { +      dsp_rx_regs->decim_rate = (hb1<<9) | (hb2<<8) | decim; +      // printf("Decim: %d, register %d\n", p->decim, (hb1<<9) | (hb2<<8) | decim); +    } +  } + +  if (p->valid & CFGV_SCALE_IQ){ +    dsp_rx_regs->scale_iq = p->scale_iq; +  } + +  // Build reply subpacket + +  r->opcode = OP_CONFIG_RX_REPLY_V2; +  r->len = sizeof(*r); +  r->rid = p->rid; +  r->ok = ok; +  r->inverted = tune_result.inverted; +  r->baseband_freq_hi = u2_fxpt_freq_hi(tune_result.baseband_freq); +  r->baseband_freq_lo = u2_fxpt_freq_lo(tune_result.baseband_freq); +  r->ddc_freq_hi = u2_fxpt_freq_hi(tune_result.dxc_freq); +  r->ddc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq); +  r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq); +  r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq); + +  return r->len; +} + +static size_t +read_time_cmd(const op_generic_t *p, +	      void *reply_payload, size_t reply_payload_space) +{ +  op_read_time_reply_t *r = (op_read_time_reply_t *) reply_payload; +  if (reply_payload_space < sizeof(*r))		 +    return 0;					// no room + +  r->opcode = OP_READ_TIME_REPLY; +  r->len = sizeof(*r); +  r->rid = p->rid; +  r->time = timer_regs->time; + +  return r->len; +} + +static void +fill_db_info(u2_db_info_t *p, const struct db_base *db) +{ +  p->dbid = db->dbid; +  p->freq_min_hi = u2_fxpt_freq_hi(db->freq_min); +  p->freq_min_lo = u2_fxpt_freq_lo(db->freq_min); +  p->freq_max_hi = u2_fxpt_freq_hi(db->freq_max); +  p->freq_max_lo = u2_fxpt_freq_lo(db->freq_max); +  p->gain_min = db->gain_min; +  p->gain_max = db->gain_max; +  p->gain_step_size = db->gain_step_size; +} + +static size_t +dboard_info_cmd(const op_generic_t *p, +		void *reply_payload, size_t reply_payload_space) +{ +  op_dboard_info_reply_t *r = (op_dboard_info_reply_t *) reply_payload; +  if (reply_payload_space < sizeof(*r))		 +    return 0;					// no room + +  r->opcode = OP_DBOARD_INFO_REPLY; +  r->len = sizeof(*r); +  r->rid = p->rid; +  r->ok = true; + +  fill_db_info(&r->tx_db_info, tx_dboard); +  fill_db_info(&r->rx_db_info, rx_dboard); + +  return r->len; +} + +static size_t +peek_cmd(const op_peek_t *p, +	 void *reply_payload, size_t reply_payload_space) +{ +  op_generic_t *r = (op_generic_t *) reply_payload; + +  putstr("peek: addr="); puthex32(p->addr); +  printf(" bytes=%u\n", p->bytes); + +  if ((reply_payload_space < (sizeof(*r) + p->bytes)) || +      p->bytes > MAX_SUBPKT_LEN - sizeof(op_generic_t)) { +    putstr("peek: insufficient reply packet space\n"); +    return 0;			// FIXME do partial read? +  } + +  r->opcode = OP_PEEK_REPLY; +  r->len = sizeof(*r)+p->bytes; +  r->rid = p->rid; +  r->ok = true; + +  memcpy_wa(reply_payload+sizeof(*r), (void *)p->addr, p->bytes); + +  return r->len; +} + +static bool +poke_cmd(const op_poke_t *p) +{ +  int bytes = p->len - sizeof(*p); +  putstr("poke: addr="); puthex32(p->addr); +  printf(" bytes=%u\n", bytes); + +  uint8_t *src = (uint8_t *)p + sizeof(*p); +  memcpy_wa((void *)p->addr, src, bytes); + +  return true; +} + +static size_t +generic_reply(const op_generic_t *p, +	      void *reply_payload, size_t reply_payload_space, +	      bool ok) +{ +  op_generic_t *r = (op_generic_t *) reply_payload; +  if (reply_payload_space < sizeof(*r))		 +    return 0;					// no room + +  r->opcode = p->opcode | OP_REPLY_BIT; +  r->len = sizeof(*r); +  r->rid = p->rid; +  r->ok = ok; + +  return r->len; +} + +static size_t +add_eop(void *reply_payload, size_t reply_payload_space) +{ +  op_generic_t *r = (op_generic_t *) reply_payload; +  if (reply_payload_space < sizeof(*r))		 +    return 0;					// no room + +  r->opcode = OP_EOP; +  r->len = sizeof(*r); +  r->rid = 0; +  r->ok =  0; + +  return r->len; +} + +void +handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) +{ +  unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4; +  unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)]; +  int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t); + +  // initialize reply +  memset(reply, 0, sizeof(reply)); +  set_reply_hdr((u2_eth_packet_t *) reply, pkt); + +  // point to beginning of payload (subpackets) +  unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t); +  int payload_len = len - sizeof(u2_eth_packet_t); + +  size_t subpktlen = 0; + +  while (payload_len >= sizeof(op_generic_t)){ +    const op_generic_t *gp = (const op_generic_t *) payload; +    subpktlen = 0; + +    // printf("\nopcode = %d\n", gp->opcode); + +    switch(gp->opcode){ +    case OP_EOP:		// end of subpackets +      goto end_of_subpackets; + +    case OP_ID: +      subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space); +      break; +     +    case OP_CONFIG_TX_V2: +      subpktlen = config_tx_v2_cmd((op_config_tx_v2_t *) payload, +				   reply_payload, reply_payload_space); +      break; + +    case OP_CONFIG_RX_V2: +      subpktlen = config_rx_v2_cmd((op_config_rx_v2_t *) payload, +				   reply_payload, reply_payload_space); +      break; + +    case OP_START_RX_STREAMING: +      start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) payload); +      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true); +      break; +     +    case OP_STOP_RX: +      stop_rx_cmd(); +      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true); +      break; +     +    case OP_BURN_MAC_ADDR: +      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, +				burn_mac_addr((op_burn_mac_addr_t *) payload)); +      break; + +    case OP_CONFIG_MIMO: +      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, +				config_mimo_cmd((op_config_mimo_t *) payload)); +      break; + +    case OP_READ_TIME: +      subpktlen = read_time_cmd(gp, reply_payload, reply_payload_space); +      break; + +    case OP_DBOARD_INFO: +      subpktlen = dboard_info_cmd(gp, reply_payload, reply_payload_space); +      break; + +    case OP_SYNC_TO_PPS: +      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, +				sync_to_pps((op_generic_t *) payload)); +      break; + +    case OP_PEEK: +      subpktlen = peek_cmd((op_peek_t *)payload, reply_payload, reply_payload_space); +      break; + +    case OP_POKE: +      subpktlen = generic_reply(gp, reply_payload, reply_payload_space, +				poke_cmd((op_poke_t *)payload)); +      break; + +    default: +      printf("app_common_v2: unhandled opcode = %d\n", gp->opcode); +      break; +    } + +    int t = (gp->len + 3) & ~3;		// bump to a multiple of 4 +    payload += t; +    payload_len -= t; + +    subpktlen = (subpktlen + 3) & ~3;	// bump to a multiple of 4 +    reply_payload += subpktlen; +    reply_payload_space -= subpktlen; +  } + + end_of_subpackets: + +  // add the EOP marker +  subpktlen = add_eop(reply_payload, reply_payload_space); +  subpktlen = (subpktlen + 3) & ~3;	// bump to a multiple of 4 +  reply_payload += subpktlen; +  reply_payload_space -= subpktlen; + +  send_reply(reply, reply_payload - reply); +} + + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +int +eth_pkt_inspector(bsm12_t *sm, int bufno) +{ +  u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); +  size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4; + +  //static size_t last_len = 0; + +  // hal_toggle_leds(0x1); + +  // inspect rcvd frame and figure out what do do. + +  if (pkt->ehdr.ethertype != U2_ETHERTYPE) +    return true;	// ignore, probably bogus PAUSE frame from MAC + +  int chan = u2p_chan(&pkt->fixed); + +  switch (chan){ +  case CONTROL_CHAN: +    handle_control_chan_frame(pkt, byte_len); +    return -1; +    break; + +  case 0: +    return 0;	// pass it off to DSP TX + +  case 1: +    return 1;	// pass it off to SERDES TX + +  default: +    abort(); +    break; +  } +} + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ +  link_is_up = speed != 0; +  hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); +  printf("\neth link changed: speed = %d\n", speed); +} + + +void +print_tune_result(char *msg, bool tune_ok, +		  u2_fxpt_freq_t target_freq, struct tune_result *r) +{ +#if 0 +  printf("db_tune %s %s\n", msg, tune_ok ? "true" : "false"); +  putstr("  target_freq   "); print_fxpt_freq(target_freq); newline(); +  putstr("  baseband_freq "); print_fxpt_freq(r->baseband_freq); newline(); +  putstr("  dxc_freq      "); print_fxpt_freq(r->dxc_freq); newline(); +  putstr("  residual_freq "); print_fxpt_freq(r->residual_freq); newline(); +  printf("  inverted      %s\n", r->inverted ? "true" : "false"); +#endif +} diff --git a/firmware/microblaze/apps/cruft/mimo_app_common_v2.h b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h new file mode 100644 index 000000000..1e62ced37 --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h @@ -0,0 +1,63 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_APP_COMMON_H +#define INCLUDED_APP_COMMON_H + +#include <stdbool.h> +#include "usrp2_eth_packet.h" +#include "bsm12.h" +#include "memory_map.h" +#include "hal_io.h" +#include <stddef.h> +#include <db.h> + +#define CPU_TX_BUF 	7	// cpu -> eth + +#define	_AL4 __attribute__((aligned (4))) + +extern volatile bool link_is_up;	// eth handler sets this + +// If there's a dbsm that sends to the ethernet, put it's address here +extern dbsm_t *ac_could_be_sending_to_eth; + +extern int cpu_tx_buf_dest_port; + +void set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt); + +/* + * Called when an ethernet packet is received. + */ +int eth_pkt_inspector(bsm12_t *sm, int bufno); + + +void link_changed_callback(int speed); + +void +print_tune_result(char *msg, bool tune_ok, +		  u2_fxpt_freq_t target_freq, struct tune_result *r); + + +void start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p); +void stop_rx_cmd(void); +void restart_streaming(void); +bool is_streaming(void); + +void handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len); + +#endif /* INCLUDED_APP_COMMON_H */ diff --git a/firmware/microblaze/apps/cruft/mimo_tx.c b/firmware/microblaze/apps/cruft/mimo_tx.c new file mode 100644 index 000000000..e0f8aa6fa --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_tx.c @@ -0,0 +1,363 @@ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This is a down and dirty test program that confirms that the we can + * coherently transmit different signals to two USRP2s connected via a + * mimo cable.  This code runs in the USRP2 connected to the ethernet. + * The other USRP runs mimo_tx_slave.  The host runs test_mimo_tx. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "bsm12.h" +#include "mimo_app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include "clocks.h" + +#define FW_SETS_SEQNO	1	// define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno;	// used when f/w is filling in sequence numbers +#endif + + +/* + * Experimental code to transmit packets to DSP Tx and SERDES + * + * Hard wire the Tx config so we don't have to deal with control stuff yet. + */ + +#define	BUF_BSM12_0	4 +#define	BUF_BSM12_1	5 +#define	BUF_BSM12_2	6 + +//#define CPU_TX_BUF	7	// cpu -> eth + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from ethernet +buf_cmd_args_t bsm12_recv_args = { +  PORT_ETH, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t bsm12_send0_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past transport header +  0			// filled in from last_line register +}; + +// send to SERDES +buf_cmd_args_t bsm12_send1_args = { +  PORT_SERDES, +  0,			// starts just past transport header +  0			// filled in from last_line register +}; + +bsm12_t bsm12_sm;	// the state machine + +#if 0 +/* + * ================================================================ + *   configure DSP RX double buffering state machine (dsp -> eth) + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_DSP, +  DSP_RX_FIRST_LINE, +  BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { +  PORT_ETH, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from list_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine +#endif + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool         streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int          streaming_frame_count = 0; +#define FRAMES_PER_CMD	1000 + +bool is_streaming(void){ return streaming_p; } + + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ +#if 0 +  // setup RX DSP regs +  dsp_rx_regs->clear_state = 1;			// reset + +  streaming_p = true; +  streaming_frame_count = FRAMES_PER_CMD; + +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);			// set "chain" bit + +  // kick off the state machine +  dbsm_start(&dsp_rx_sm); + +  dsp_rx_regs->rx_time = 0;		// enqueue first of two commands + +  // make sure this one and the rest have the "now" and "chain" bits set. +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);				 + +  dsp_rx_regs->rx_time = 0;		// enqueue second command +#endif +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ +#if 0 +  host_mac_addr = *host;	// remember who we're sending to + +  /* +   * Construct  ethernet header and word0 and preload into two buffers +   */ +  u2_eth_packet_t	pkt; +  memset(&pkt, 0, sizeof(pkt)); +  pkt.ehdr.dst = *host; +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; +  u2p_set_word0(&pkt.fixed, 0, 0); +  // DSP RX will fill in timestamp + +  memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); +  memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + +  if (FW_SETS_SEQNO) +    fw_seqno = 0; + +  streaming_items_per_frame = p->items_per_frame; +  restart_streaming(); +#endif +} + + +void +stop_rx_cmd(void) +{ +#if 0 +  streaming_p = false; +  dsp_rx_regs->clear_state = 1;	// flush cmd queue +  bp_clear_buf(DSP_RX_BUF_0); +  bp_clear_buf(DSP_RX_BUF_1); +#endif +} + + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; + +  int tx_scale = 2500; +  int interp = 8;		// * 4 + +  // setup some defaults + +  dsp_tx_regs->freq = 429496730;	// 10MHz +  dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; +  dsp_tx_regs->interp_rate = (1 << 9) | (1 << 8) | interp; +} + + +#if 0 +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY.  This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet.  A bit of a kludge + * but it should work. + */ +int +fw_sets_seqno_inspector(bsm12_t *sm, int buf_this) +{ +  uint32_t *p = buffer_ram(buf_this); +  uint32_t seqno = fw_seqno++; + +  // KLUDGE all kinds of nasty magic numbers and embedded knowledge +  uint32_t t = p[4]; +  t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); +  p[4] = t; + +  // queue up another rx command when required +  if (streaming_p && --streaming_frame_count == 0){ +    streaming_frame_count = FRAMES_PER_CMD; +    dsp_rx_regs->rx_time = 0; +  } + +  return false;		// we didn't handle the packet +} +#endif +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  bsm12_process_status(&bsm12_sm, status); +} + +int +main(void) +{ +  u2_init(); + +  putstr("\nMIMO Tx\n"); +  print_mac_addr(ethernet_mac_addr()->addr); +  newline(); + +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + +  clocks_mimo_config(MC_WE_DONT_LOCK | MC_PROVIDE_CLK_TO_MIMO); + +#if 0 +  // make bit 15 of Tx gpio's be a s/w output +  hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +  output_regs->debug_mux_ctrl = 1; +#if 0 +  hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); +  hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  bsm12_init(&bsm12_sm, BUF_BSM12_0, +	     &bsm12_recv_args, &bsm12_send0_args, &bsm12_send1_args, +	     eth_pkt_inspector); + + +#if 0 +  // initialize double buffering state machine for DSP RX -> Ethernet + +  if (FW_SETS_SEQNO){ +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      fw_sets_seqno_inspector); +  } +  else { +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      dbsm_nop_inspector); +  } + +  // tell app_common that this dbsm could be sending to the ethernet +  ac_could_be_sending_to_eth = &dsp_rx_sm; +#endif + + +  // program tx registers +  setup_tx(); + +  // kick off the state machine +  bsm12_start(&bsm12_sm); + +  //int which = 0; + +  while(1){ +    // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); +    // which ^= 0x8000; + +    buffer_irq_handler(0); + +    int pending = pic_regs->pending;		// poll for under or overrun + +    if (pending & PIC_UNDERRUN_INT){ +      // dbsm_handle_tx_underrun(&dsp_tx_sm); +      pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt +      putchar('U'); +    } + +    if (pending & PIC_OVERRUN_INT){ +      // dbsm_handle_rx_overrun(&dsp_rx_sm); +      pic_regs->pending = PIC_OVERRUN_INT;	// clear pending interrupt + +      // FIXME Figure out how to handle this robustly. +      // Any buffers that are emptying should be allowed to drain... + +      if (streaming_p){ +	// restart_streaming(); +	// FIXME report error +      } +      else { +	// FIXME report error +      } +      putchar('O'); +    } +  } +} diff --git a/firmware/microblaze/apps/cruft/mimo_tx_slave.c b/firmware/microblaze/apps/cruft/mimo_tx_slave.c new file mode 100644 index 000000000..cdf9c03c2 --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_tx_slave.c @@ -0,0 +1,376 @@ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This is a down and dirty test program that confirms that the we can + * coherently transmit different signals to two USRP2s connected via a + * mimo cable.  This code runs in the USRP2 NOT connected to the + * ethernet.  The USRP connected to the ethernet runs mimo_tx.  The + * host runs test_mimo_tx. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include "clocks.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +#define FW_SETS_SEQNO	1	// define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno;	// used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between serdes and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to serdes flow + * Buffers 4 and 5 are used to double-buffer the serdes to DSP Tx flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu + +#define	DSP_RX_BUF_0	2	// dsp rx -> serdes (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> serdes +#define	DSP_TX_BUF_0	4	// serdes -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// serdes -> dsp tx + +/* + * ================================================================== + *   configure DSP TX double buffering state machine (serdes -> dsp) + * ================================================================== + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from serdes +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_SERDES, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past transport header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + +/* + * ================================================================= + *   configure DSP RX double buffering state machine (dsp -> serdes) + * ================================================================= + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_DSP, +  DSP_RX_FIRST_LINE, +  BP_LAST_LINE +}; + +// send to serdes +buf_cmd_args_t dsp_rx_send_args = { +  PORT_SERDES, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from list_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool         streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int          streaming_frame_count = 0; +#define FRAMES_PER_CMD	1000 + +bool is_streaming(void){ return streaming_p; } + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ +  // setup RX DSP regs +  dsp_rx_regs->clear_state = 1;			// reset + +  streaming_p = true; +  streaming_frame_count = FRAMES_PER_CMD; + +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);			// set "chain" bit + +  // kick off the state machine +  dbsm_start(&dsp_rx_sm); + +  dsp_rx_regs->rx_time = 0;		// enqueue first of two commands + +  // make sure this one and the rest have the "now" and "chain" bits set. +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);				 + +  dsp_rx_regs->rx_time = 0;		// enqueue second command +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ +  host_mac_addr = *host;	// remember who we're sending to + +  /* +   * Construct  ethernet header and word0 and preload into two buffers +   */ +  u2_eth_packet_t	pkt; +  memset(&pkt, 0, sizeof(pkt)); +  pkt.ehdr.dst = *host; +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; +  u2p_set_word0(&pkt.fixed, 0, 0); +  // DSP RX will fill in timestamp + +  memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); +  memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + +  if (FW_SETS_SEQNO) +    fw_seqno = 0; + +  streaming_items_per_frame = p->items_per_frame; +  restart_streaming(); +} + + +void +stop_rx_cmd(void) +{ +  streaming_p = false; +  dsp_rx_regs->clear_state = 1;	// flush cmd queue +  bp_clear_buf(DSP_RX_BUF_0); +  bp_clear_buf(DSP_RX_BUF_1); +} + + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +  int tx_scale = 2500; +  int interp = 8;		// * 4 + +  // setup some defaults + +  dsp_tx_regs->freq = 429496730;	// 10MHz +  dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; +  dsp_tx_regs->interp_rate = (1 << 9) | (1 << 8) | interp; +} + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY.  This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet.  A bit of a kludge + * but it should work. + */ +bool  +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this)	// returns false +{ +  uint32_t *p = buffer_ram(buf_this); +  uint32_t seqno = fw_seqno++; + +  // KLUDGE all kinds of nasty magic numbers and embedded knowledge +  uint32_t t = p[4]; +  t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); +  p[4] = t; + +  // queue up another rx command when required +  if (streaming_p && --streaming_frame_count == 0){ +    streaming_frame_count = FRAMES_PER_CMD; +    dsp_rx_regs->rx_time = 0; +  } + +  return false;		// we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  // hal_toggle_leds(LED_A); + +  uint32_t  status = buffer_pool_status->status; + +  if (0 && (status & ~BPS_IDLE_ALL)){ +    putstr("status = "); +    puthex32_nl(status); +  } + +  dbsm_process_status(&dsp_tx_sm, status); +  dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ +  u2_init(); + +  output_regs->led_src = 0x3;		// h/w controls bottom two bits +  clocks_enable_test_clk(true, 1); + +  putstr("\nMIMO Tx Slave\n"); + +  cpu_tx_buf_dest_port = PORT_SERDES; + +  // ethernet_register_link_changed_callback(link_changed_callback); +  // ethernet_init(); + +  clocks_mimo_config(MC_WE_LOCK_TO_MIMO); + +  // puts("post clocks_mimo_config"); + +#if 0 +  // make bit 15 of Tx gpio's be a s/w output +  hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +#if 0 +  output_regs->debug_mux_ctrl = 1; +  hal_gpio_set_sels(GPIO_TX_BANK, "0000000000000000"); +  hal_gpio_set_sels(GPIO_RX_BANK, "0000000000000000"); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); +  hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    eth_pkt_inspector); + + +  //output_regs->flush_icache = 1; +  +  // initialize double buffering state machine for DSP RX -> Ethernet + +  if (FW_SETS_SEQNO){ +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      fw_sets_seqno_inspector); +  } +  else { +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      dbsm_nop_inspector); +  } + +  // puts("post dbsm_init's"); + +  // tell app_common that this dbsm could be sending to the ethernet +  ac_could_be_sending_to_eth = &dsp_rx_sm; + + +  // program tx registers +  setup_tx(); + +  // puts("post setup_tx"); + +  // kick off the state machine +  dbsm_start(&dsp_tx_sm); + +  // puts("post dbsm_start"); + +  //int which = 0; + +  while(1){ +    // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); +    // which ^= 0x8000; + +    buffer_irq_handler(0); + +    int pending = pic_regs->pending;		// poll for under or overrun + +    if (pending & PIC_UNDERRUN_INT){ +      dbsm_handle_tx_underrun(&dsp_tx_sm); +      pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt +      putchar('U'); +    } + +    if (pending & PIC_OVERRUN_INT){ +      dbsm_handle_rx_overrun(&dsp_rx_sm); +      pic_regs->pending = PIC_OVERRUN_INT;	// clear pending interrupt + +      // FIXME Figure out how to handle this robustly. +      // Any buffers that are emptying should be allowed to drain... + +      if (streaming_p){ +	// restart_streaming(); +	// FIXME report error +      } +      else { +	// FIXME report error +      } +      putchar('O'); +    } +  } +} diff --git a/firmware/microblaze/apps/cruft/rcv_eth_packets.c b/firmware/microblaze/apps/cruft/rcv_eth_packets.c new file mode 100644 index 000000000..03fc94354 --- /dev/null +++ b/firmware/microblaze/apps/cruft/rcv_eth_packets.c @@ -0,0 +1,233 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> + + +// ---------------------------------------------------------------- + +static eth_mac_addr_t dst_mac_addr = +  {{  0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}; + + +// ---------------------------------------------------------------- + +#define	PACKET_SIZE 1500		// bytes +#define ETH_DATA_RATE 1000000		// 1MB/s +#define	ETH_PACKET_RATE (ETH_DATA_RATE/PACKET_SIZE)	// 13,3333 pkts/s + +#define TIMER_RATE 100000000		// 100 MHz clock + +static int timer_delta = TIMER_RATE/ETH_PACKET_RATE;	// ticks between interrupts + +static volatile bool send_packet_now = false;   // timer handler sets this +static volatile bool link_is_up = false;	// eth handler sets this + +int packet_number = 0; + +// ---------------------------------------------------------------- + +// debugging output on tx pins +#define LS_MASK  0xE0000 +#define LS_1000  0x80000 +#define LS_100   0x40000 +#define LS_10    0x20000 + + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ +  int v = 0; +  switch(speed){ +  case 10: +    v = LS_10; +    link_is_up = true; +    break; +     +  case 100: +    v = LS_100; +    link_is_up = true; +    break; +     +  case 1000: +    v = LS_100; +    link_is_up = true; +    break; + +  default: +    v = 0; +    link_is_up = false; +    break; +  } + +  //hal_gpio_set_tx(v, LS_MASK);	/* set debug bits on d'board */ + +  putstr("\neth link changed: speed = "); +  puthex16_nl(speed); +} + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +  send_packet_now = 1; +} + + +void +buffer_irq_handler(unsigned irq) +{ +  // FIXME +} + +static void +init_packet(int *buf, const u2_eth_packet_t *pkt, int bufnum) +{ +  int i = 0; +  int mark = ((bufnum & 0xff) << 24) | 0x005A0000; + +  for (i = 0; i < BP_NLINES; i++){ +    buf[i] = mark | i; +    mark ^= 0x00FF0000; +  } + +  // copy header into buffer +  memcpy_wa(buf, pkt, sizeof(*pkt)); +} + +static void +init_packets(void) +{ +  int	i; +   +  u2_eth_packet_t	pkt __attribute__((aligned (4))); + +  pkt.ehdr.dst = dst_mac_addr; +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; + +  // fill ALL buffers for debugging +  for (i = 0; i < 8; i++) +    init_packet((void *)buffer_ram(i), &pkt, i); +} + +int +main(void) +{ +  u2_init(); + +  int	prev_leds = -1; +  int	new_leds  = 0x00; +  output_regs->leds = 0x00; + +  int peak_hold_count = 0; + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + +  putstr("\nrcv_eth_packets\n"); +   +  init_packets(); + +  // pic_register_handler(IRQ_BUFFER, buffer_irq_handler);  // poll for now + +  // FIXME turn off timer since I don't think MTS and MFS instructions are implemented +  // pic_register_handler(IRQ_TIMER, timer_irq_handler); +  // hal_set_timeout(timer_delta); + +  ethernet_register_link_changed_callback(link_changed_callback); + +  ethernet_init(); + +  //eth_mac->speed = 4;	// FIXME hardcode mac speed to 1000 + +  // kick off a receive +  bp_receive_to_buf(2, PORT_ETH, 1, 0, 511); + +  while(1){ +    // u2_eth_packet_t	pkt; + +    new_leds = 0; +    if (link_is_up) +      new_leds = 0x2; + +    if ((buffer_pool_status->status & (BPS_DONE_2|BPS_ERROR_2)) != 0){ +      // we've got a packet! + +#if 0 +      // copy to stack buffer so we can byte address it +      memcpy_wa(&pkt, (void *)buffer_ram(2), sizeof(pkt)); +       +      putstr("Rx: src: "); +      print_mac_addr(pkt.ehdr.dst_addr); +      putstr(" dst: "); +      print_mac_addr(pkt.ehdr.src_addr); +      putstr(" ethtype: "); +      puthex16(pkt.ehdr.ethertype); +      putstr(" len: "); +      int len = (buffer_pool_status->last_line[2] + 1) * 4; +      puthex16_nl(len); +#else +      volatile int *bp = buffer_ram(2); +      int	i; +      for (i = 0; i < 16; i++){ +	puthex8(i); +	putchar(':'); +	puthex32_nl(bp[i]); +      } +#endif +       +      // kick off next receive +      bp_clear_buf(2); +      bp_receive_to_buf(2, PORT_ETH, 1, 0, 511); + +      peak_hold_count = 2048 * 10; +    } + +    if (peak_hold_count > 0){ +      peak_hold_count--; +      new_leds |= 0x1; +    } + +    if (new_leds != prev_leds){ +      prev_leds = new_leds; +      output_regs->leds = new_leds; +    } +  } + +  hal_finish(); +  return 1; +} diff --git a/firmware/microblaze/apps/cruft/read_dbids.c b/firmware/microblaze/apps/cruft/read_dbids.c new file mode 100644 index 000000000..24c6d9ab4 --- /dev/null +++ b/firmware/microblaze/apps/cruft/read_dbids.c @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <nonstdio.h> +#include <u2_init.h> +#include <stdbool.h> +#include <usrp2_i2c_addr.h> +#include <i2c.h> + + +int main(void) +{ +  u2_init(); + +  puts("\nread_dbids"); + +  unsigned char dbid_tx[2]; +  unsigned char dbid_rx[2]; +  bool ok; + +  ok = eeprom_read(I2C_ADDR_TX_A, 1, dbid_tx, 2); +  if (!ok){ +    puts("failed to read Tx Daugherboard EEPROM"); +  } +  else { +    putstr("Tx Daugherboard ID: "); +    puthex8(dbid_tx[1]);    // MSB +    puthex8(dbid_tx[0]);    // LSB +    newline(); +  } + +  ok = eeprom_read(I2C_ADDR_RX_A, 1, dbid_rx, 2); +  if (!ok){ +    puts("failed to read Rx Daugherboard EEPROM"); +  } +  else { +    putstr("Rx Daugherboard ID: "); +    puthex8(dbid_rx[1]);    // MSB +    puthex8(dbid_rx[0]);    // LSB +    newline(); +  } + +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/sd_bounce.c b/firmware/microblaze/apps/cruft/sd_bounce.c new file mode 100644 index 000000000..c1b48f170 --- /dev/null +++ b/firmware/microblaze/apps/cruft/sd_bounce.c @@ -0,0 +1,153 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/*  + * Loopback SERDES to SERDES + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "nonstdio.h" +#include "memset_wa.h" +#include <dbsm.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <clocks.h> + + + +// ---------------------------------------------------------------- + +#define SERDES_RX_BUF_0		0 +#define	SERDES_RX_BUF_1		1 + +/* + * ================================================================ + *      configure SD RX double buffering state machine + * ================================================================ + */ + +// receive from SERDES +buf_cmd_args_t sd_recv_args = { +  PORT_SERDES, +  0, +  BP_LAST_LINE +}; + +// send to SERDES +buf_cmd_args_t sd_send_args = { +  PORT_SERDES, +  0,		// starts with packet in line 0 +  0,		// filled in from list_line register +}; + +dbsm_t sd_sm;	// the state machine + + + + +// ---------------------------------------------------------------- + +#if 0 +static bool +check_packet(int *buf, int nlines) +{ +  bool ok = true; +  int i = 0; +  for (i = 0; i < nlines; i++){ +    int expected = ((2*i + 0) << 16) | (2*i+1); +    if (buf[i] != expected){ +      ok = false; +      printf("buf[%d] = 0x%x  expected = 0x%x\n", i, buf[i], expected); +    } +  } +  return ok; +} + +static void +zero_buffer(int bufno) +{ +  memset_wa(buffer_ram(bufno), 0, BP_NLINES * 4); +} +#endif + + +bool +sd_rx_inspector(dbsm_t *sm, int buf_this) +{ +  hal_toggle_leds(0x2); + +#if 0 +  int last_line = buffer_pool_status->last_line[buf_this]; +  bool ok = check_packet(buffer_ram(buf_this), last_line); +  static int good = 0; +  static int bad = 0; + +  if (ok) +    good++; +  else +    bad++; + +  if(good+bad == 10000) { +    printf("Good %d\tBad %d\n",good,bad); +    good = 0; +    bad = 0; +  } +#endif + +  return false; +} + + +inline static void +buffer_irq_handler(void) +{ +  uint32_t  status = buffer_pool_status->status; +  dbsm_process_status(&sd_sm, status); +} + + +int +main(void) +{ +  u2_init(); + +  putstr("\nsd_bounce\n"); + +  // Get our clock from the mimo interface +  clocks_mimo_config(MC_WE_LOCK_TO_MIMO); + +  dbsm_init(&sd_sm, SERDES_RX_BUF_0, +	    &sd_recv_args, &sd_send_args, +	    sd_rx_inspector); + +  // kick off the state machine +  dbsm_start(&sd_sm); + +  while(1){ +    buffer_irq_handler(); +  } +} diff --git a/firmware/microblaze/apps/cruft/sd_gentest.c b/firmware/microblaze/apps/cruft/sd_gentest.c new file mode 100644 index 000000000..35e912615 --- /dev/null +++ b/firmware/microblaze/apps/cruft/sd_gentest.c @@ -0,0 +1,269 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "nonstdio.h" +#include "memset_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <clocks.h> +#include <mdelay.h> + +// ---------------------------------------------------------------- + +int packet_number = 0; +volatile bool send_packet_now = 0; + +#define SERDES_TX_BUF	0 +#define	SERDES_RX_BUF 	1 + + +#define NLINES_PER_PKT	380 + + +// ---------------------------------------------------------------- + +//static int timer_delta = (int)(MASTER_CLK_RATE * 100e-6); +static int timer_delta = 1000000; // .01 second + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +  send_packet_now = true; +} + + +static void +init_packet(int *buf) +{ +  int i = 0; +  for (i = 0; i < BP_NLINES; i++){ +    buf[i] = ((2*i + 0) << 16) | (2*i+1); +  } +} + +static bool +check_packet(int *buf, int nlines) +{ +  bool ok = true; +  int i = 0; +  for (i = 0; i < nlines; i++){ +    int expected = ((2*i + 0) << 16) | (2*i+1); +    if (buf[i] != expected){ +      ok = false; +      printf("buf[%d] = 0x%x  expected = 0x%x\n", i, buf[i], expected); +    } +  } +  return ok; +} + +static void +zero_buffer(int bufno) +{ +  memset_wa(buffer_ram(bufno), 0, BP_NLINES * 4); +} + +static void +init_packets(void) +{ +  // init just the one we're using +  init_packet(buffer_ram(SERDES_TX_BUF)); +} + +int +main(void) +{ +  u2_init(); + +  // We're free running and provide clock to the MIMO interface +  clocks_mimo_config(MC_WE_DONT_LOCK | MC_PROVIDE_CLK_TO_MIMO); + + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  // output_regs->debug_mux_ctrl = 1; +  // hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  // hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + +  putstr("\nsd_gentest\n"); +   +  // Set up serdes (already enabled) +  //output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN | SERDES_LOOPEN); +  //output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN); + +  init_packets(); + +  // pic_register_handler(IRQ_TIMER, timer_irq_handler); + +  //if (hwconfig_simulation_p()) +  //  timer_delta = sim_timer_delta; + +  // start a receive from sd +  zero_buffer(SERDES_RX_BUF); +  bp_receive_to_buf(SERDES_RX_BUF, PORT_SERDES, 1, 0, BP_LAST_LINE); + +  // fire off the first packet +  bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); +  hal_set_timeout(timer_delta); +  int ready_to_send = 0; + +  int counter __attribute__((unused)) = 0; +  int sent = 1; +  int txerr = 0; +  int rxerr = 0; +  int rcvd = 0; +  int rxcrc = 0; +  int sent_acc = 0; +  int txerr_acc = 0; +  int rxerr_acc = 0; +  int rcvd_acc = 0; +  int rxcrc_acc = 0; + +#define EXPECTING_PKT() ((counter & 0x1) == 0) +#define	SEND_PKT()      ((counter & 0x1) != 0) + +  bool got_packet = false; + +  while(1){ +    uint32_t status = buffer_pool_status->status; + +    if (status & (BPS_DONE(SERDES_RX_BUF))){ +      bp_clear_buf(SERDES_RX_BUF); +      got_packet = true; + +      //hal_toggle_leds(0x2); + +      // check packet +      int last_line = buffer_pool_status->last_line[SERDES_RX_BUF]-1; +      bool ok = check_packet(buffer_ram(SERDES_RX_BUF), last_line); +       +      if (ok) { +	rcvd++; +	//putchar('r'); +      } +      else { +	rcvd++; +	rxcrc++; +	//putchar('P'); +      } +      // start a receive from sd +      zero_buffer(SERDES_RX_BUF); +      bp_receive_to_buf(SERDES_RX_BUF, PORT_SERDES, 1, 0, BP_LAST_LINE); +    } + +    if (status & (BPS_ERROR(SERDES_RX_BUF))){ +      bp_clear_buf(SERDES_RX_BUF); +      got_packet = true; +      rcvd++; +      rxerr++; +      //putchar('E'); + +      // start a receive from sd +      zero_buffer(SERDES_RX_BUF); +      bp_receive_to_buf(SERDES_RX_BUF, PORT_SERDES, 1, 0, BP_LAST_LINE); +    } + +    if (status & (BPS_DONE(SERDES_TX_BUF))){ +      bp_clear_buf(SERDES_TX_BUF); +      //putchar('t'); +      bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); +      //mdelay(1); +      int	i; +      for (i = 0; i < 50; i++){ +	asm volatile ("or  r0, r0, r0\n\ +		   or  r0, r0, r0\n    \ +		   or  r0, r0, r0\n    \ +		   or  r0, r0, r0\n    \ +		   or  r0, r0, r0\n    \ +		   or  r0, r0, r0\n    \ +		   or  r0, r0, r0\n"); +      } +      sent ++; +      ready_to_send = 1; +      //hal_toggle_leds(0x1); +    } + +    if (status & BPS_ERROR(SERDES_TX_BUF)){ +      bp_clear_buf(SERDES_TX_BUF); +      sent++; +      txerr++; +      ready_to_send = 1; +      //putchar('X'); +    } + +    if(sent >=1000) { +      printf("Status\tSENT %d\tTXERR %d\t",sent,txerr); +      printf("RX %d\tERR %d\tCRC %d\tMISSED %d\n",rcvd, rxerr, rxcrc, sent-rcvd); +      sent_acc += sent; sent = 0; +      txerr_acc += txerr; txerr = 0; +      rcvd_acc += rcvd; rcvd = 0; +      rxerr_acc += rxerr; rxerr = 0; +      rxcrc_acc += rxcrc; rxcrc = 0; +    } + +    if(sent_acc >=10000) { +      printf("\nOverall\tSENT %d\tTXERR %d\t",sent_acc,txerr_acc); +      printf("RX %d\tERR %d\tCRC %d\tMISSED %d\n\n",rcvd_acc, rxerr_acc, rxcrc_acc, sent_acc-rcvd_acc); +      sent_acc = 0; +      txerr_acc = 0; +      rcvd_acc = 0; +      rxerr_acc = 0; +      rxcrc_acc = 0; +    } +#if 0 +    int pending = pic_regs->pending; +    if (pending & PIC_TIMER_INT){ +      hal_set_timeout(timer_delta); +       +      /* +	if (EXPECTING_PKT()){ +	if (!got_packet) +	  putchar('T'); +	got_packet = false; +      } + +      if (SEND_PKT()){ +	if (status & BPS_IDLE(SERDES_TX_BUF)) +	  bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); +      } +      counter++; +      */ + +      putchar('T'); +      if(ready_to_send) { +	bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); +	counter++; +	ready_to_send = 0; +      } +       +      pic_regs->pending = PIC_TIMER_INT;	// clear pending interrupt +    } +#endif +  } +   +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/serdes_to_dsp.c b/firmware/microblaze/apps/cruft/serdes_to_dsp.c new file mode 100644 index 000000000..4994e0a69 --- /dev/null +++ b/firmware/microblaze/apps/cruft/serdes_to_dsp.c @@ -0,0 +1,179 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu +//#define CPU_TX_BUF 	1	// cpu -> eth + +#define	DSP_RX_BUF_0	2	// dsp rx -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> eth +#define	DSP_TX_BUF_0	4	// eth -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> dsp tx + +/* + * ================================================================ + *      configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_SERDES, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past transport header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +  int tx_scale = 256; +  int interp = 32; + +  op_config_tx_t def_config; +  memset(&def_config, 0, sizeof(def_config)); +  def_config.phase_inc  = 408021893;			// 9.5 MHz [2**32 * fc/fsample] +  def_config.scale_iq = (tx_scale << 16) | tx_scale; +  def_config.interp = interp; + +  // setup Tx DSP regs +  config_tx_cmd(&def_config); +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  //hal_toggle_leds(0x2); + +  uint32_t  status = buffer_pool_status->status; + +  dbsm_process_status(&dsp_tx_sm, status); + +  if (status & BPS_DONE(CPU_TX_BUF)){ +    bp_clear_buf(CPU_TX_BUF); +  } +} + +int +main(void) +{ +  u2_init(); + +  // Get our clock from the mimo interface + +  clocks_enable_test_clk(true,1); +  clocks_mimo_config(MC_WE_LOCK_TO_MIMO); +   +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + +  putstr("\nserdes_to_dsp\n"); + +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    eth_pkt_inspector); + +  // program tx registers +  setup_tx(); + +  // kick off the state machine +  dbsm_start(&dsp_tx_sm); + +  while(1){ +    buffer_irq_handler(0); + +    int pending = pic_regs->pending;	// poll for under or overrun + +    if (pending & PIC_UNDERRUN_INT){ +      dbsm_handle_tx_underrun(&dsp_tx_sm); +      pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt +      putchar('U'); +    } +  } +} + diff --git a/firmware/microblaze/apps/cruft/serdes_txrx.c b/firmware/microblaze/apps/cruft/serdes_txrx.c new file mode 100644 index 000000000..2c47c9628 --- /dev/null +++ b/firmware/microblaze/apps/cruft/serdes_txrx.c @@ -0,0 +1,368 @@ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include "clocks.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +#define FW_SETS_SEQNO	1	// define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno;	// used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between serdes and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to serdes flow + * Buffers 4 and 5 are used to double-buffer the serdes to DSP Tx flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu + +#define	DSP_RX_BUF_0	2	// dsp rx -> serdes (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> serdes +#define	DSP_TX_BUF_0	4	// serdes -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// serdes -> dsp tx + +/* + * ================================================================== + *   configure DSP TX double buffering state machine (serdes -> dsp) + * ================================================================== + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from serdes +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_SERDES, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past transport header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + +/* + * ================================================================= + *   configure DSP RX double buffering state machine (dsp -> serdes) + * ================================================================= + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_DSP, +  DSP_RX_FIRST_LINE, +  BP_LAST_LINE +}; + +// send to serdes +buf_cmd_args_t dsp_rx_send_args = { +  PORT_SERDES, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from list_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool         streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int          streaming_frame_count = 0; +#define FRAMES_PER_CMD	1000 + +bool is_streaming(void){ return streaming_p; } + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ +  // setup RX DSP regs +  dsp_rx_regs->clear_state = 1;			// reset + +  streaming_p = true; +  streaming_frame_count = FRAMES_PER_CMD; + +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);			// set "chain" bit + +  // kick off the state machine +  dbsm_start(&dsp_rx_sm); + +  dsp_rx_regs->rx_time = 0;		// enqueue first of two commands + +  // make sure this one and the rest have the "now" and "chain" bits set. +  dsp_rx_regs->rx_command = +    MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, +	      streaming_items_per_frame, +	      1, 1);				 + +  dsp_rx_regs->rx_time = 0;		// enqueue second command +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ +  host_mac_addr = *host;	// remember who we're sending to + +  /* +   * Construct  ethernet header and word0 and preload into two buffers +   */ +  u2_eth_packet_t	pkt; +  memset(&pkt, 0, sizeof(pkt)); +  pkt.ehdr.dst = *host; +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; +  u2p_set_word0(&pkt.fixed, 0, 0); +  // DSP RX will fill in timestamp + +  memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); +  memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + +  if (FW_SETS_SEQNO) +    fw_seqno = 0; + +  streaming_items_per_frame = p->items_per_frame; +  restart_streaming(); +} + + +void +stop_rx_cmd(void) +{ +  streaming_p = false; +  dsp_rx_regs->clear_state = 1;	// flush cmd queue +  bp_clear_buf(DSP_RX_BUF_0); +  bp_clear_buf(DSP_RX_BUF_1); +} + + +static void +setup_tx() +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +  int tx_scale = 256; +  int interp = 32; + +  // setup some defaults + +  dsp_tx_regs->freq = 0; +  dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; +  dsp_tx_regs->interp_rate = interp; +} + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY.  This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet.  A bit of a kludge + * but it should work. + */ +bool  +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this)	// returns false +{ +  uint32_t *p = buffer_ram(buf_this); +  uint32_t seqno = fw_seqno++; + +  // KLUDGE all kinds of nasty magic numbers and embedded knowledge +  uint32_t t = p[4]; +  t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); +  p[4] = t; + +  // queue up another rx command when required +  if (streaming_p && --streaming_frame_count == 0){ +    streaming_frame_count = FRAMES_PER_CMD; +    dsp_rx_regs->rx_time = 0; +  } + +  return false;		// we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ +  // hal_toggle_leds(LED_A); + +  uint32_t  status = buffer_pool_status->status; + +  if (0 && (status & ~BPS_IDLE_ALL)){ +    putstr("status = "); +    puthex32_nl(status); +  } + +  dbsm_process_status(&dsp_tx_sm, status); +  dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ +  u2_init(); + +  output_regs->led_src = 0x3;		// h/w controls bottom two bits +  clocks_enable_test_clk(true, 1); + +  putstr("\nSERDES TxRx\n"); + +  cpu_tx_buf_dest_port = PORT_SERDES; + +  // ethernet_register_link_changed_callback(link_changed_callback); +  // ethernet_init(); + +  clocks_mimo_config(MC_WE_LOCK_TO_MIMO); + +  // puts("post clocks_mimo_config"); + +#if 0 +  // make bit 15 of Tx gpio's be a s/w output +  hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +#if 0 +  output_regs->debug_mux_ctrl = 1; +  hal_gpio_set_sels(GPIO_TX_BANK, "0000000000000000"); +  hal_gpio_set_sels(GPIO_RX_BANK, "0000000000000000"); +  hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); +  hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    eth_pkt_inspector); + + +  //output_regs->flush_icache = 1; +  +  // initialize double buffering state machine for DSP RX -> Ethernet + +  if (FW_SETS_SEQNO){ +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      fw_sets_seqno_inspector); +  } +  else { +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      dbsm_nop_inspector); +  } + +  // puts("post dbsm_init's"); + +  // tell app_common that this dbsm could be sending to the ethernet +  ac_could_be_sending_to_eth = &dsp_rx_sm; + + +  // program tx registers +  setup_tx(); + +  // puts("post setup_tx"); + +  // kick off the state machine +  dbsm_start(&dsp_tx_sm); + +  // puts("post dbsm_start"); + +  //int which = 0; + +  while(1){ +    // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); +    // which ^= 0x8000; + +    buffer_irq_handler(0); + +    int pending = pic_regs->pending;		// poll for under or overrun + +    if (pending & PIC_UNDERRUN_INT){ +      dbsm_handle_tx_underrun(&dsp_tx_sm); +      pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt +      putchar('U'); +    } + +    if (pending & PIC_OVERRUN_INT){ +      dbsm_handle_rx_overrun(&dsp_rx_sm); +      pic_regs->pending = PIC_OVERRUN_INT;	// clear pending interrupt + +      // FIXME Figure out how to handle this robustly. +      // Any buffers that are emptying should be allowed to drain... + +      if (streaming_p){ +	// restart_streaming(); +	// FIXME report error +      } +      else { +	// FIXME report error +      } +      putchar('O'); +    } +  } +} diff --git a/firmware/microblaze/apps/cruft/set_hw_rev.c b/firmware/microblaze/apps/cruft/set_hw_rev.c new file mode 100644 index 000000000..d4ac8ff81 --- /dev/null +++ b/firmware/microblaze/apps/cruft/set_hw_rev.c @@ -0,0 +1,45 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#include <u2_init.h> +#include <nonstdio.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> + +#define HW_REV_MAJOR 0 +#define HW_REV_MINOR 3 + +int +main(void) +{ +  u2_init(); + +  putstr("\nset_hw_rev\n"); + +  bool ok = true; +  unsigned char maj = HW_REV_MAJOR; +  unsigned char min = HW_REV_MINOR; +  ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &maj, 1); +  ok &= eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &min, 1); + +  if (ok) +    printf("OK: set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); +  else +    printf("FAILED to set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); + +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/test1.c b/firmware/microblaze/apps/cruft/test1.c new file mode 100644 index 000000000..c3cc3be56 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test1.c @@ -0,0 +1,282 @@ +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include "nonstdio.h" + +// Globals +#define EMPTY 0 +#define FILLING 1 +#define FULL 2 +#define EMPTYING 3 + +#define PORT 2    // ethernet = 2, serdes = 0 +int dsp_rx_buf, dsp_tx_buf, serdes_rx_buf, serdes_tx_buf; +int dsp_rx_idle, dsp_tx_idle, serdes_rx_idle, serdes_tx_idle; + +int buffer_state[4]; + + +void double_buffering(int port); + +// +// We register this in the secondary interrupt vector. +// It's called on buffer manager interrupts +// +void +buffer_irq_handler(unsigned irq) +{ +  double_buffering(PORT); +} + +int +main(void) +{ +  int i; + +  u2_init(); + +  // Control LEDs +  output_regs->leds = 0x02; + +  // Turn on ADCs +  output_regs->adc_ctrl = 0x0A; + +  // Set up TX Chain +  dsp_tx_regs->freq = 0; +  dsp_tx_regs->scale_iq = (1 << 16) | 1; +  dsp_tx_regs->interp_rate = 8; + +  // Set up RX Chain +  dsp_rx_regs->freq = 0; +  dsp_rx_regs->scale_iq = (1 << 16) | 1; +  dsp_rx_regs->decim_rate = 8; + +  // Set up buffer control, using only 4 for now +  for(i=0;i<4;i++)  +    buffer_state[i] = EMPTY; + +  // Set up DSP RX +  buffer_state[0] = FILLING; +  serdes_tx_idle = 1; +  bp_receive_to_buf(0, 1, 1, 10, 509);  // DSP_RX to buffer 0, use 500 lines + +  //dsp_rx_regs->run_rx = 1;           // Start DSP_RX +  putstr("Done DSP RX setup\n"); + +  // Set up serdes RX +  buffer_state[2] = FILLING; +  dsp_tx_idle = 1; +  bp_receive_to_buf(2, PORT, 1, 5, 504); + +  while (buffer_pool_status->status == 0)  // wait for completion of DSP RX +    ; + +  putstr("Done DSP TX setup\n"); +  //dsp_tx_regs->run_tx = 1; + +  // register interrupt handler +  pic_register_handler(IRQ_BUFFER, buffer_irq_handler); + +  while (1) +    ; + +  hal_finish(); +  return 1; +} + +void  +double_buffering(int port) { +  unsigned int localstatus = buffer_pool_status->status; + +  if(localstatus & BPS_DONE_0) { +    bp_clear_buf(0); +    if(buffer_state[0] == FILLING) { +      buffer_state[0] = FULL; +      if(buffer_state[1] == EMPTY) { +	bp_receive_to_buf(1, 1, 1, 10, 509);  // DSP_RX to buffer 1, use 500 lines +	buffer_state[1] = FILLING; +      } +      else +	dsp_rx_idle = 1; +      if(serdes_tx_idle) { +	serdes_tx_idle = 0; +	bp_send_from_buf(0, port, 1, 10, 509);  // SERDES_TX from buffer 0 +	buffer_state[0] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[0] = EMPTY; +      if(dsp_rx_idle) { +	dsp_rx_idle = 0; +	bp_receive_to_buf(0, 1, 1, 10, 509);  // DSP_RX to buffer 0, use 500 lines +	buffer_state[0] = FILLING; +      } +      if(buffer_state[1] == FULL) { +	bp_send_from_buf(1, port, 1, 10, 509);  // SERDES_TX from buffer 1 +	buffer_state[1] = EMPTYING; +      } +      else +	serdes_tx_idle = 1; +    } +    putstr("Int Proc'ed 0\n"); +  } +  if(localstatus & BPS_DONE_1) { +    bp_clear_buf(1); +    if(buffer_state[1] == FILLING) { +      buffer_state[1] = FULL; +      if(buffer_state[0] == EMPTY) { +	bp_receive_to_buf(0, 1, 1, 10, 509);  // DSP_RX to buffer 1, use 500 lines +	buffer_state[0] = FILLING; +      } +      else +	dsp_rx_idle = 1; +      if(serdes_tx_idle) { +	serdes_tx_idle = 0; +	bp_send_from_buf(1, port, 1, 10, 509);  // SERDES_TX from buffer 1 +	buffer_state[1] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[1] = EMPTY; +      if(dsp_rx_idle) { +	dsp_rx_idle = 0; +	bp_receive_to_buf(1, 1, 1, 10, 509);  // DSP_RX to buffer 1, use 500 lines +	buffer_state[1] = FILLING; +      } +      if(buffer_state[0] == FULL) { +	bp_send_from_buf(0, port, 1, 10, 509);  // SERDES_TX from buffer 0 +	buffer_state[0] = EMPTYING; +      } +      else +	serdes_tx_idle = 1; +    } +  putstr("Int Proc'ed 1\n"); +  } +  if(localstatus & BPS_DONE_2) { +    bp_clear_buf(2); +    if(buffer_state[2] == FILLING) { +      buffer_state[2] = FULL; +      if(buffer_state[3] == EMPTY) { +	bp_receive_to_buf(3, port, 1, 5, 504);  // SERDES_RX to buffer 3, use 500 lines +	buffer_state[3] = FILLING; +      } +      else +	serdes_rx_idle = 1; +      if(dsp_tx_idle) { +	dsp_tx_idle = 0; +	bp_send_from_buf(2, 1, 1, 5, 504);  // DSP_TX from buffer 2 +	buffer_state[2] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[2] = EMPTY; +      if(serdes_rx_idle) { +	serdes_rx_idle = 0; +	bp_receive_to_buf(2, port, 1, 5, 504);  // SERDES_RX to buffer 2 +	buffer_state[2] = FILLING; +      } +      if(buffer_state[3] == FULL) { +	bp_send_from_buf(3, 1, 1, 5, 504);  // DSP_TX from buffer 3 +	buffer_state[3] = EMPTYING; +      } +      else +	dsp_tx_idle = 1; +    } +  putstr("Int Proc'ed 2\n"); +  } +  if(localstatus & BPS_DONE_3) { +    bp_clear_buf(3); +    if(buffer_state[3] == FILLING) { +      buffer_state[3] = FULL; +      if(buffer_state[2] == EMPTY) { +	bp_receive_to_buf(2, port, 1, 5, 504);  // SERDES_RX to buffer 2, use 500 lines +	buffer_state[2] = FILLING; +      } +      else +	serdes_rx_idle = 1; +      if(dsp_tx_idle) { +	dsp_tx_idle = 0; +	bp_send_from_buf(3, 1, 1, 5, 504);  // DSP_TX from buffer 3 +	buffer_state[3] = EMPTYING; +      } +    } +    else {  // buffer was emptying +      buffer_state[3] = EMPTY; +      if(serdes_rx_idle) { +	serdes_rx_idle = 0; +	bp_receive_to_buf(3, port, 1, 5, 504);  // SERDES_RX to buffer 3 +	buffer_state[3] = FILLING; +      } +      if(buffer_state[2] == FULL) { +	bp_send_from_buf(2, 1, 1, 5, 504);  // DSP_TX from buffer 2 +	buffer_state[2] = EMPTYING; +      } +      else +	dsp_tx_idle = 1; +    } +  putstr("Int Proc'ed 3\n"); +  } +} + +// Spare Code + +#if 0   +  // Set up LSDAC +  int i = 0; +  while(1) { +    int command = (3 << 19) | (0 << 16) |  (i & 0xffff); +    spi_transact(SPI_TXONLY, SPI_SS_TX_DAC, command, 24, 1); // negate TX phase +    i++; +  } +#endif + +#if 0   +  // Write to buffer 0 +  int *buf = (int *)(BUFFER_BASE + BUFFER_0); +  puthex_nl((int)buf); + +  for(i=0;i<BUFFER_SIZE;i++) +    buf[i] = i; + +  putstr("Filled buffer 0\n"); + +  // Write to buffer 1 +  buf = (int *)(BUFFER_BASE + BUFFER_1); +  puthex_nl((int)buf); +  for(i=0;i<BUFFER_SIZE;i++) +    buf[i] =  i + ((i^0xFFFF) << 16); + +  putstr("Filled buffer 1\n"); + +#endif + +#if 0 +  // rx SERDES into buffer #2  (buf,port,step,fl,ll) +  bp_receive_to_buf(2, 0, 1, 10, 300); +  putstr("SERDES RX buffer setup\n"); + +  // send SERDES from buffer #0 (buf,port,step,fl,ll) +  bp_send_from_buf(0, 0, 1, 20, 200); +  putstr("SERDES TX buffer setup\n"); + +#endif + +#if 0 +  // send to DACs from buffer #1 +  bp_send_from_buf(1 /*buf#*/, 1 /*port*/, 1 /*step*/, 20 /*fl*/, 250 /*ll*/); +  putstr("DAC Buffer setup\n"); +#endif + +#if 0 +  //putstr("ENTER INT\n"); +  for(i=0;i<8;i++) +    if(*status & (1<<i)) { +      //putstr("Clearing buf "); +      puthex_nl(i); +      bp_clear_buf(i); +    } +  //putstr("EXIT INT\n"); +#endif diff --git a/firmware/microblaze/apps/cruft/test_db_spi.c b/firmware/microblaze/apps/cruft/test_db_spi.c new file mode 100644 index 000000000..f4fa98ef1 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_db_spi.c @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <u2_init.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <spi.h> + +int +main(void) +{ +  u2_init(); + +  puts("\ntest_db_spi"); + +  while(1){ +    spi_transact(SPI_TXONLY, SPI_SS_RX_DB, 0xCC33, 16, SPIF_PUSH_FALL); +    spi_transact(SPI_TXONLY, SPI_SS_TX_DB, 0x33CC, 16, SPIF_PUSH_FALL); +  } +} diff --git a/firmware/microblaze/apps/cruft/test_i2c.c b/firmware/microblaze/apps/cruft/test_i2c.c new file mode 100644 index 000000000..f349ead88 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_i2c.c @@ -0,0 +1,108 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdint.h> +#include <u2_init.h>		/* FIXME */ +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <string.h> +#include <hal_io.h> + + + +#define ASSERT_TRUE(x) \ +  do { \ +    if (!(x)){ \ +      printf("ASSERT_TRUE failed on line %d\n", __LINE__); \ +      nerrors++; \ +    } \ +  } while(0) + +#define ASSERT_FALSE(x) \ +  do { \ +    if (x){ \ +      printf("ASSERT_FALSE failed on line %d\n", __LINE__); \ +      nerrors++; \ +    } \ +  } while(0) + + +#define BUFSIZE 128 + +int +main(void) +{ +  int i; +  bool ok; +  int  nerrors = 0; +  uint8_t buf[BUFSIZE]; +  int not_dev_addr = 0x35;	// no device with this address on the i2c bus. +  int offset; +  int len; +   +  u2_init(); + +  puts("test_i2c\n"); + +  // try writing a non-existent device +  buf[0] = 0xA5; +  ok = i2c_write(not_dev_addr, buf, 1); +  ASSERT_FALSE(ok); + +  // try read from non-existent device +  buf[0] = 0; +  ok = i2c_read(not_dev_addr, buf, 1); +  ASSERT_FALSE(ok); + +  // try writing eeprom +  offset = 31; +  len = 8; +  memset(buf, 0, sizeof(buf)); +  for (i = 0; i < len; i++) +    buf[i] = i; +  ok = eeprom_write(I2C_ADDR_MBOARD, offset, buf, len); +  ASSERT_TRUE(ok); + +  // now try to read it back +  offset = 31; +  len = 8; +  memset(buf, 0, sizeof(buf)); +  ok = eeprom_read(I2C_ADDR_MBOARD, offset, buf, len); +  ASSERT_TRUE(ok); + +  // check result +  for (i = 0; i < len; i++){ +    if (buf[i] != i){ +      printf("buf[%d] = %d, should be %d\n", i, buf[i], i); +      nerrors++; +    } +  } +   +  if (nerrors == 0){ +    output_regs->leds = 0x3; +    puts("PASSED\n"); +  } +  else { +    output_regs->leds = 0x0; +    puts("FAILED\n"); +  } + +  hal_finish(); +  return 0; +} + diff --git a/firmware/microblaze/apps/cruft/test_lsadc.c b/firmware/microblaze/apps/cruft/test_lsadc.c new file mode 100644 index 000000000..5fda29cd7 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_lsadc.c @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <lsadc.h> +#include <lsdac.h> +#include <u2_init.h> +#include <nonstdio.h> +#include <hal_io.h> + +int +main(void) +{ +  u2_init(); + +  puts("\ntest_lsadc"); + +  uint32_t r; + +  unsigned int up_counter = 0; +   +  while (1){ +    unsigned int v; +    v = up_counter; + +    lsdac_write_rx(0, v << 0); +    lsdac_write_rx(2, v << 1); + +#if 1 +    r = lsadc_read_rx(0); +    lsdac_write_rx(1, r & 0x0fff); +    //puthex32_nl(r); +#endif + +#if 1 +    r = lsadc_read_rx(1); +    lsdac_write_rx(3, r & 0x0fff); +    //puthex32_nl(r); +#endif + +    up_counter++; +  } +} diff --git a/firmware/microblaze/apps/cruft/test_lsdac.c b/firmware/microblaze/apps/cruft/test_lsdac.c new file mode 100644 index 000000000..8c1bf333b --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_lsdac.c @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <lsdac.h> +#include <u2_init.h> +#include <nonstdio.h> +#include <hal_io.h> + +int +main(void) +{ +  u2_init(); + +  puts("\ntest_lsdac"); + +  unsigned int up_counter = 0; +  unsigned int dn_counter = 0; + +  while(1){ +    unsigned int v; +    v = up_counter; +    lsdac_write_rx(0, v << 0); +    lsdac_write_rx(1, v << 1); +    lsdac_write_rx(2, v << 2); +    lsdac_write_rx(3, v << 3); + +    v = up_counter; +    lsdac_write_tx(0, v << 0); +    lsdac_write_tx(1, v << 1); +    lsdac_write_tx(2, v << 2); +    lsdac_write_tx(3, v << 3); + +    up_counter++; +    dn_counter--; +  } +} diff --git a/firmware/microblaze/apps/cruft/test_phy_comm.c b/firmware/microblaze/apps/cruft/test_phy_comm.c new file mode 100644 index 000000000..d312ca4cc --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_phy_comm.c @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +// check communication with ethernet PHY chip + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "ethernet.h" +#include "pic.h" +#include "nonstdio.h" + + +#define DELTA_T     12500000  		// .125s (10ns per tick) +//#define DELTA_T      10000 + +// debugging output on tx pins +#define LS_MASK  0xE0000 +#define LS_1000  0x80000 +#define LS_100   0x40000 +#define LS_10    0x20000 + + + +#define U2_ETHERTYPE 0xBEEF + + +static volatile int led_link_up_flag = 0; + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ +  int v = 0; +  switch(speed){ +  case 10: +    v = LS_10; +    led_link_up_flag = 0x2; +    break; +     +  case 100: +    v = LS_100; +    led_link_up_flag = 0x2; +    break; +     +  case 1000: +    v = LS_100; +    led_link_up_flag = 0x2; +    break; + +  default: +    v = 0; +    led_link_up_flag = 0; +    break; +  } + +  //hal_gpio_set_tx(v, LS_MASK);	/* set debug bits on d'board */ + +  putstr("\neth link changed: speed = "); +  puthex_nl(speed); +} + +void +timer_handler(unsigned irq) +{ +  static int led_counter = 0; + +  hal_set_timeout(DELTA_T);	// schedule next timeout +  output_regs->leds = (led_counter++ & 0x1) | led_link_up_flag; +} + +int +main(void) +{ +  u2_init(); + +  putstr("\n test_phy_comm\n"); + +  pic_register_handler(IRQ_ONETIME, timer_handler); +  hal_set_timeout(DELTA_T);	// schedule timeout + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + +  ethernet_register_link_changed_callback(link_changed_callback); + +  output_regs->phy_ctrl = 1;	/* reset the eth PHY */ +  output_regs->phy_ctrl = 0; + +  ethernet_init(); + +  while(1) +    ; + +  return 0; +} diff --git a/firmware/microblaze/apps/cruft/test_ram.c b/firmware/microblaze/apps/cruft/test_ram.c new file mode 100644 index 000000000..77ee693f6 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_ram.c @@ -0,0 +1,105 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdint.h> +#include <u2_init.h>		/* FIXME */ +#include <sd.h> +#include <string.h> +#include <hal_io.h> +#include <nonstdio.h> +#include <hal_uart.h> + +#define ASSERT_TRUE(x) \ +  do { \ +    if (!(x)){ \ +      printf("ASSERT_TRUE failed on line %d\n", __LINE__); \ +      nerrors++; \ +    } \ +  } while(0) + +#define ASSERT_FALSE(x) \ +  do { \ +    if (x){ \ +      printf("ASSERT_FALSE failed on line %d\n", __LINE__); \ +      nerrors++; \ +    } \ +  } while(0) + + +#define BUFSIZE 128 + +int test_ram() +{ +  int i,j,k; +  output_regs->ram_page = 1<<10; +   +  extram[0] = 0xDEADBEEF; +  extram[1] = 0xF00D1234; +  extram[7] = 0x76543210; +   +  output_regs->ram_page = 2<<10; +  extram[7] = 0x55555555; +  extram[1] = 0xaaaaaaaa; +  extram[0] = 0xeeeeeeee; +   +  output_regs->ram_page = 1<<10; +   +  i = extram[0]; +  k = extram[1]; +  j = extram[7]; +   +  if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { +    puts("RAM FAIL1!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +   +  output_regs->ram_page = 2<<10; + +  j = extram[7]; +  k = extram[1]; +  i = extram[0]; + +  if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { +    puts("RAM FAIL2!\n"); +    puthex32_nl(i); +    puthex32_nl(j); +    puthex32_nl(k); +    return 0; +  } +  return 1; +} + +int +main(void) +{ + +  u2_init(); +  puts("\ntest_ram\n"); +  int success = test_ram(); +  if(success) +    puts("RAM Passed Tests\n"); +  else +    puts("RAM Failed\n"); + +  hal_finish(); +  return 0; +} + diff --git a/firmware/microblaze/apps/cruft/test_sd.c b/firmware/microblaze/apps/cruft/test_sd.c new file mode 100644 index 000000000..494432d7f --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_sd.c @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdint.h> +#include <u2_init.h>		/* FIXME */ +#include <sd.h> +#include <string.h> +#include <hal_io.h> +#include <nonstdio.h> + + +#define ASSERT_TRUE(x) \ +  do { \ +    if (!(x)){ \ +      printf("ASSERT_TRUE failed on line %d\n", __LINE__); \ +      nerrors++; \ +    } \ +  } while(0) + +#define ASSERT_FALSE(x) \ +  do { \ +    if (x){ \ +      printf("ASSERT_FALSE failed on line %d\n", __LINE__); \ +      nerrors++; \ +    } \ +  } while(0) + + +#define BUFSIZE 128 + +int +main(void) +{ +  int i; +  unsigned char buf[512]; + +  u2_init(); + +  puts("\ntest_sd\n"); +   + +  i = sd_init(); +  if(i) +    puts("Successfully Init'ed Card\n"); +  else +    puts("FAILED INIT of Card\n"); + +  i = sd_read_block(2048,buf); +  if(i) { +    puts("READ Command accepted\n"); +    for(i=0;i<512;i++) +      if((i&15) == 15) +	puthex8_nl(buf[i]); +      else { +	puthex8(buf[i]); +	putchar(' '); +      } +  } +  else +    puts("READ Command Rejected\n"); +   +  puts("Done"); +  hal_finish(); +  return 0; +} + diff --git a/firmware/microblaze/apps/cruft/timer_test.c b/firmware/microblaze/apps/cruft/timer_test.c new file mode 100644 index 000000000..44e80b5f1 --- /dev/null +++ b/firmware/microblaze/apps/cruft/timer_test.c @@ -0,0 +1,57 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include "nonstdio.h" +#include "hal_io.h" + +#define DELTA_T  500  		// 5 us (10ns per tick) + + +void  +timer_handler(unsigned irq) +{ +  hal_set_timeout(DELTA_T); + +  putstr("Tick: "); +  puthex_nl(0); +} + +int +main(void) +{ +  u2_init(); + +  // setup timer + +  putstr("Setting up timer\n"); +  pic_register_handler(IRQ_ONETIME, timer_handler); + +  hal_set_timeout(DELTA_T); + +  while (1) +    ; + +  putstr("Done Testing\n"); +   +  hal_finish(); +  return 1; +} diff --git a/firmware/microblaze/apps/cruft/tx_standalone.c b/firmware/microblaze/apps/cruft/tx_standalone.c new file mode 100644 index 000000000..1645fa8ba --- /dev/null +++ b/firmware/microblaze/apps/cruft/tx_standalone.c @@ -0,0 +1,339 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "memcpy_wa.h" +#include "dbsm.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#define	_AL4 __attribute__((aligned (4))) + +#define USE_BUFFER_INTERRUPT	0	// 0 or 1 + + +static int timer_delta = MASTER_CLK_RATE/1000;	// tick at 1kHz + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu +#define CPU_TX_BUF 	1	// cpu -> eth + +#define	DSP_RX_BUF_0	2	// dsp rx -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> eth +#define	DSP_TX_BUF_0	4	// eth -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> dsp tx + + +/* + * ================================================================ + *      configure DSP RX double buffering state machine + * ================================================================ + */ + + +// 4 lines of ethernet hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE		  5 +#define DSP_RX_SAMPLES_PER_FRAME	128 +#define	DSP_RX_EXTRA_LINES		  1	// writes timestamp + +// Receive from DSP Rx +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_DSP, +  DSP_RX_FIRST_LINE, +  BP_LAST_LINE +}; + +// send to ethernet +buf_cmd_args_t dsp_rx_send_args = { +  PORT_ETH, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from last_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine + +/* + * ================================================================ + *      configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE		  4 +#define DSP_TX_SAMPLES_PER_FRAME	250	// not used except w/ debugging +#define	DSP_TX_EXTRA_LINES		  2	// reads word0 + timestamp + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_ETH, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past ethernet header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + +/* + * send constant buffer to DSP TX + */ +static inline void  +SEND_CONST_TO_DSP_TX(void) +{ +  bp_send_from_buf(DSP_TX_BUF_0, PORT_DSP, 1, +		   DSP_TX_FIRST_LINE, +		   DSP_TX_FIRST_LINE + DSP_TX_EXTRA_LINES + DSP_TX_SAMPLES_PER_FRAME - 1); +} + +// ---------------------------------------------------------------- + + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void link_changed_callback(int speed); +static volatile bool link_is_up = false;	// eth handler sets this + + +void +timer_irq_handler(unsigned irq) +{ +  hal_set_timeout(timer_delta);	// schedule next timeout +} + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ +  dsp_tx_regs->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); +  dbsm_stop(&dsp_tx_sm); + +  // FIXME anything else? + +  putstr("\nirq: underrun\n"); +} + +// Rx DSP overrun +void +overrun_irq_handler(unsigned irq) +{ +  dsp_rx_regs->clear_state = 1; +  bp_clear_buf(DSP_RX_BUF_0); +  bp_clear_buf(DSP_RX_BUF_1); +  dbsm_stop(&dsp_rx_sm); + +  // FIXME anything else? + +  putstr("\nirq: overrun\n"); +} + +static void +start_tx_transfers(void) +{ +  bp_clear_buf(DSP_TX_BUF_0);	// FIXME, really goes in state machine +  bp_clear_buf(DSP_TX_BUF_1); + +  // fill everything with a constant 32k + 0j + +  uint32_t const_sample = (32000 << 16) | 0; +  int i; +  for (i = 0; i < BP_NLINES; i++){ +    buffer_ram(DSP_TX_BUF_0)[i] = const_sample; +    buffer_ram(DSP_TX_BUF_1)[i] = const_sample; +  } + +  /* +   * Construct  ethernet header and word0 and preload into two buffers +   */ +  u2_eth_packet_t	pkt; +  memset(&pkt, 0, sizeof(pkt)); +  //pkt.ehdr.dst = *host; +  pkt.ehdr.src = *ethernet_mac_addr(); +  pkt.ehdr.ethertype = U2_ETHERTYPE; +  u2p_set_word0(&pkt.fixed, +		U2P_TX_IMMEDIATE | U2P_TX_START_OF_BURST, 0); +  u2p_set_timestamp(&pkt.fixed, T_NOW); + +  memcpy_wa(buffer_ram(DSP_TX_BUF_0), &pkt, sizeof(pkt)); +  memcpy_wa(buffer_ram(DSP_TX_BUF_1), &pkt, sizeof(pkt)); + + +  int tx_scale = 256; + +  // setup Tx DSP regs +  dsp_tx_regs->clear_state = 1;			// reset +  dsp_tx_regs->freq = 408021893;		// 9.5 MHz [2**32 * fc/fsample] +  dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; +  dsp_tx_regs->interp_rate = 32; + +  // kick off the state machine +  // dbsm_start(&dsp_rx_sm); + +  SEND_CONST_TO_DSP_TX();	// send constant buffer to DSP TX +} + + +void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  if (0){ +    putstr("irq: "); +    puthex32(status); +    putchar('\n'); +  } + +  if (status & BPS_ERROR_ALL){ +    // FIXME rare path, handle error conditions +  } + +  if (status & BPS_DONE(DSP_TX_BUF_0)){ +    bp_clear_buf(DSP_TX_BUF_0); +    SEND_CONST_TO_DSP_TX(); +    hal_toggle_leds(0x1); +  } + +} + +int +main(void) +{ +  u2_init(); + +  // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output +  //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); +  //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + +  putstr("\ntx_only\n"); +   +  // Control LEDs +  hal_set_leds(0x0, 0x3); + +  if (USE_BUFFER_INTERRUPT) +    pic_register_handler(IRQ_BUFFER,   buffer_irq_handler); + +  pic_register_handler(IRQ_OVERRUN,  overrun_irq_handler); +  pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + +  //pic_register_handler(IRQ_TIMER, timer_irq_handler); +  //hal_set_timeout(timer_delta); + +  ethernet_register_link_changed_callback(link_changed_callback); + +  ethernet_init(); + +  // initialize double buffering state machine for DSP RX -> Ethernet +  dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	    &dsp_rx_recv_args, &dsp_rx_send_args, +	    dbsm_nop_inspector); + +  // setup receive from ETH +  // bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE); + +#if 0 +  if (hwconfig_simulation_p()){ +    // If we're simulating, pretend that we got a start command from the host +    eth_mac_addr_t host = {{ 0x00, 0x0A, 0xE4, 0x3E, 0xD2, 0xD5 }}; +    start_rx_cmd(&host); +  } +#endif + +  start_tx_transfers();		// send constant buffers to DSP TX + +  while(1){ +    if (!USE_BUFFER_INTERRUPT) +      buffer_irq_handler(0); +  } +} + +// ---------------------------------------------------------------- + +// debugging output on tx pins +#define LS_MASK  0xE0000 +#define LS_1000  0x80000 +#define LS_100   0x40000 +#define LS_10    0x20000 + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ +  int v = 0; +  switch(speed){ +  case 10: +    v = LS_10; +    link_is_up = true; +    break; +     +  case 100: +    v = LS_100; +    link_is_up = true; +    break; +     +  case 1000: +    v = LS_100; +    link_is_up = true; +    break; + +  default: +    v = 0; +    link_is_up = false; +    break; +  } + +  //hal_gpio_set_tx(v, LS_MASK);	/* set debug bits on d'board */ + +  // hal_set_leds(link_is_up ? 0x2 : 0x0, 0x2); + +  printf("\neth link changed: speed = %d\n", speed); +} diff --git a/firmware/microblaze/apps/flash_test.c b/firmware/microblaze/apps/flash_test.c new file mode 100644 index 000000000..5b4569030 --- /dev/null +++ b/firmware/microblaze/apps/flash_test.c @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <hal_io.h> +#include <hal_uart.h> +#include <xilinx_s3_icap.h> +#include <nonstdio.h> +#include <spi_flash.h> +#include <spi.h> +#include <clocks.h> +#include <string.h> + +//just a test to write to SPI flash and retrieve the same values. +//uses the MOBFLEET SPI flash library + +void delay(uint32_t t) { +	while(t-- != 0) asm("NOP"); +} + +int main(int argc, char *argv[]) { +	uint16_t i, t; +	uint8_t buf[260]; +	const uint8_t testdata[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}; + +  hal_disable_ints();	// In case we got here via jmp 0x0 +//	spi_init(); +  hal_uart_init(); +//	clocks_init(); //set up AD9510, enable FPGA clock @ 1x divisor + +	puts("SPI Flash test\n"); +	puts("Initializing SPI\n"); + +	spif_init(); +	delay(800000); +	puts("Erasing sector 1\n"); +	spi_flash_erase(0x00010000, 256); +	delay(800000); +	puts("Reading back data\n"); +	spi_flash_read(0x00010000, 256, buf); +	delay(800000); + +	t=1; +	for(i=4; i<250; i++) { +		if(buf[i] != 0xFF) t=0; +	} + +	if(!t) puts("Data was not initialized to 0xFF. Unsuccessful erase or read\n"); +	else puts("Data initialized to 0xFF, erase confirmed\n"); + +	puts("Writing test buffer\n"); +	spi_flash_program(0x00010000, 16, testdata); +	//memset(buf, 0, 256); + +	delay(800000); +	puts("Wrote data, reading back\n"); + +	spi_flash_read(0x00010000, 16, buf); + +	if(memcmp(testdata, buf, 16)) puts("Data is not the same between read and write. Unsuccessful write or read\n"); +	else puts("Successful write! Flash write correct\n"); + +	return 0; +} diff --git a/firmware/microblaze/apps/hardware_testbed.c b/firmware/microblaze/apps/hardware_testbed.c new file mode 100644 index 000000000..e68e68ff7 --- /dev/null +++ b/firmware/microblaze/apps/hardware_testbed.c @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <xilinx_s3_icap.h> +#include <spi_flash.h> +//#include <spi_flash_private.h> +#include <clocks.h> +#include <ihex.h> +#include <bootloader_utils.h> +#include <string.h> +#include <hal_uart.h> +#include <spi.h> + +//so this is just an evolving file used to set up and test different bits of hardware (EEPROM, clock chip, A/D, D/A, PHY) +void delay(uint32_t t) { +	while(t-- != 0) asm("NOP"); +} + +int main(int argc, char *argv[]) { + +	hal_disable_ints(); +  hal_uart_init(); +	spi_init(); + +	puts("Hardware testbed. Init clocks..."); + +	clocks_init(); + +	//now, hopefully, we should be running at 100MHz instead of 50MHz, meaning our UART is twice as fast and we're talking at 230400. + +	while(1) { +		delay(500000); +		puts("Eat at Joe's."); +	} + + + + + +	return 0; +} diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c new file mode 100644 index 000000000..9c1873e1c --- /dev/null +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -0,0 +1,587 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <lwip/ip.h> +#include <lwip/udp.h> +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "dbsm.h" +#include <net/padded_eth_hdr.h> +#include <net_common.h> +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include "clocks.h" +#include "usrp2/fw_common.h" +#include <i2c_async.h> +#include <i2c.h> +#include <ethertype.h> +#include <arp_cache.h> +#include "udp_fw_update.h" + +/* + * Full duplex Tx and Rx between ethernet and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx  eth flow + */ +//#define CPU_RX_BUF	0	// eth -> cpu + +#define	DSP_RX_BUF_0	2	// dsp rx -> eth (double buffer) +#define	DSP_RX_BUF_1	3	// dsp rx -> eth +#define	DSP_TX_BUF_0	4	// eth -> dsp tx (double buffer) +#define	DSP_TX_BUF_1	5	// eth -> dsp tx + +/* + * ================================================================ + *   configure DSP TX double buffering state machine (eth -> dsp) + * ================================================================ + */ + +// DSP Tx reads ethernet header words +#define DSP_TX_FIRST_LINE ((sizeof(padded_eth_hdr_t) + sizeof(struct ip_hdr) + sizeof(struct udp_hdr))/sizeof(uint32_t)) + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { +  PORT_ETH, +  0, +  BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { +  PORT_DSP, +  DSP_TX_FIRST_LINE,	// starts just past transport header +  0			// filled in from last_line register +}; + +dbsm_t dsp_tx_sm;	// the state machine + +/* + * ================================================================ + *   configure DSP RX double buffering state machine (dsp -> eth) + * ================================================================ + */ + +static const uint32_t rx_ctrl_word = 1 << 16; + +// DSP Rx writes ethernet header words +#define DSP_RX_FIRST_LINE sizeof(rx_ctrl_word)/sizeof(uint32_t) + +static bool dbsm_rx_inspector(dbsm_t *sm, int buf_this){ +    size_t num_lines = buffer_pool_status->last_line[buf_this]-DSP_RX_FIRST_LINE; +    ((uint32_t*)buffer_ram(buf_this))[0] = (num_lines*sizeof(uint32_t)) | (1 << 16); +    return false; +} + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { +  PORT_DSP, +  DSP_RX_FIRST_LINE, +  BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { +  PORT_ETH, +  0,		// starts with ethernet header in line 0 +  0,		// filled in from list_line register +}; + +dbsm_t dsp_rx_sm;	// the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + +static void setup_network(void); + +// ---------------------------------------------------------------- +// the fast-path setup global variables +// ---------------------------------------------------------------- +static eth_mac_addr_t fp_mac_addr_src, fp_mac_addr_dst; +static struct socket_address fp_socket_src, fp_socket_dst; + +// ---------------------------------------------------------------- +void start_rx_streaming_cmd(void); +void stop_rx_cmd(void); + +static void print_ip_addr(const void *t){ +    uint8_t *p = (uint8_t *)t; +    printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]); +} + +void handle_udp_data_packet( +    struct socket_address src, struct socket_address dst, +    unsigned char *payload, int payload_len +){ +    //its a tiny payload, load the fast-path variables +    fp_mac_addr_src = *ethernet_mac_addr(); +    arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst); +    fp_socket_src = dst; +    fp_socket_dst = src; +    printf("Storing for fast path:\n"); +    printf("  source mac addr: "); +    print_mac_addr(fp_mac_addr_src.addr); newline(); +    printf("  source ip addr: "); +    print_ip_addr(&fp_socket_src.addr); newline(); +    printf("  source udp port: %d\n", fp_socket_src.port); +    printf("  destination mac addr: "); +    print_mac_addr(fp_mac_addr_dst.addr); newline(); +    printf("  destination ip addr: "); +    print_ip_addr(&fp_socket_dst.addr); newline(); +    printf("  destination udp port: %d\n", fp_socket_dst.port); +    newline(); + +    //setup network and vrt +    setup_network(); + +    // kick off the state machine +    dbsm_start(&dsp_rx_sm); + +} + +#define OTW_GPIO_BANK_TO_NUM(bank) \ +    (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK)) + +//setup the output data +static usrp2_ctrl_data_t ctrl_data_out; +static struct socket_address i2c_src; +static struct socket_address spi_src; + +static volatile bool i2c_done = false; +void i2c_read_done_callback(void) { +  //printf("I2C read done callback\n"); +  i2c_async_data_ready(ctrl_data_out.data.i2c_args.data); +  i2c_done = true; +  i2c_register_callback(0); +} + +void i2c_write_done_callback(void) { +  //printf("I2C write done callback\n"); +  i2c_done = true; +  i2c_register_callback(0); +} + +static volatile bool spi_done = false; +static volatile uint32_t spi_readback_data; +void get_spi_readback_data(void) { +  ctrl_data_out.data.spi_args.data = spi_get_data(); +  spi_done = true; +  spi_register_callback(0); +} + +void handle_udp_ctrl_packet( +    struct socket_address src, struct socket_address dst, +    unsigned char *payload, int payload_len +){ +    //printf("Got ctrl packet #words: %d\n", (int)payload_len); +    const usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; +    uint32_t ctrl_data_in_id = ctrl_data_in->id; + +    //ensure that the protocol versions match +    if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){ +        printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n", +            USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver +        ); +        ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO; +    } + +    //ensure that this is not a short packet +    if (payload_len < sizeof(usrp2_ctrl_data_t)){ +        printf("!Error in control packet handler: Expected payload length %d, but got %d\n", +            (int)sizeof(usrp2_ctrl_data_t), payload_len +        ); +        ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT; +    } + +    //setup the output data +    ctrl_data_out.proto_ver = USRP2_FW_COMPAT_NUM; +    ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT; +    ctrl_data_out.seq=ctrl_data_in->seq; + +    //handle the data based on the id +    switch(ctrl_data_in_id){ + +    /******************************************************************* +     * Addressing +     ******************************************************************/ +    case USRP2_CTRL_ID_WAZZUP_BRO: +        ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE; +        memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); +        send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); +        break; + +    /******************************************************************* +     * SPI +     ******************************************************************/ +    case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ +            //transact +            bool success = spi_async_transact( +                //(ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, +                ctrl_data_in->data.spi_args.dev,      //which device +                ctrl_data_in->data.spi_args.data,     //32 bit data +                ctrl_data_in->data.spi_args.num_bits, //length in bits +                (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | //flags +                (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL, +                get_spi_readback_data //callback +            ); + +            //load output +            ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; +            spi_src = src; +        } +//        send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); +        break; + +    /******************************************************************* +     * I2C +     ******************************************************************/ +    case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{ +            uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; +            i2c_register_callback(i2c_read_done_callback); +            i2c_async_read( +                ctrl_data_in->data.i2c_args.addr, +                num_bytes +            ); +            i2c_src = src; +//            i2c_dst = dst; +            ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; +            ctrl_data_out.data.i2c_args.bytes = num_bytes; +        } +        break; + +    case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{ +            uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; +            i2c_register_callback(i2c_read_done_callback); +            i2c_async_write( +                ctrl_data_in->data.i2c_args.addr, +                ctrl_data_in->data.i2c_args.data, +                num_bytes +            ); +            i2c_src = src; +//            i2c_dst = dst; +            ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; +            ctrl_data_out.data.i2c_args.bytes = num_bytes; +        } +        break; + +    /******************************************************************* +     * Peek and Poke Register +     ******************************************************************/ +    case USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO: +        if (0){//ctrl_data_in->data.poke_args.addr < 0xC000){ +            printf("error! tried to poke into 0x%x\n", ctrl_data_in->data.poke_args.addr); +        } +        else switch(ctrl_data_in->data.poke_args.num_bytes){ +        case sizeof(uint64_t): +            *((uint32_t *) ctrl_data_in->data.poke_args.addrhi) = (uint32_t)ctrl_data_in->data.poke_args.datahi; +            //continue to uint32_t for low addr: + +        case sizeof(uint32_t): +            *((uint32_t *) ctrl_data_in->data.poke_args.addr) = (uint32_t)ctrl_data_in->data.poke_args.data; +            break; + +        case sizeof(uint16_t): +            *((uint16_t *) ctrl_data_in->data.poke_args.addr) = (uint16_t)ctrl_data_in->data.poke_args.data; +            break; + +        case sizeof(uint8_t): +            *((uint8_t *) ctrl_data_in->data.poke_args.addr) = (uint8_t)ctrl_data_in->data.poke_args.data; +            break; + +        } +        ctrl_data_out.id = USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE; +        send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); +        break; + +    case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: +        switch(ctrl_data_in->data.poke_args.num_bytes){ +        case sizeof(uint64_t): +            ctrl_data_out.data.poke_args.datahi = *((uint32_t *) ctrl_data_in->data.poke_args.addrhi); +            //continue to uint32_t for low addr: + +        case sizeof(uint32_t): +            ctrl_data_out.data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); +            break; + +        case sizeof(uint16_t): +            ctrl_data_out.data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr); +            break; + +        case sizeof(uint8_t): +            ctrl_data_out.data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr); +            break; + +        } +        ctrl_data_out.id = USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE; +        send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); +        break; + +    case USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO:{ +      //executes a readline()-style read, up to num_bytes long, up to and including newline +      int num_bytes = ctrl_data_in->data.uart_args.bytes; +      if(num_bytes > 20) num_bytes = 20; +      num_bytes = fngets_timeout(ctrl_data_in->data.uart_args.dev, (char *) ctrl_data_out.data.uart_args.data, num_bytes); +      ctrl_data_out.id = USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE; +      ctrl_data_out.data.uart_args.bytes = num_bytes; +      break; +    } + +    case USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO:{ +      int num_bytes = ctrl_data_in->data.uart_args.bytes; +      if(num_bytes > 20) num_bytes = 20; +      //before we write to the UART, we flush the receive buffer +      //this assumes that we're interested in the reply +      hal_uart_rx_flush(ctrl_data_in->data.uart_args.dev); +      fnputstr(ctrl_data_in->data.uart_args.dev, (char *) ctrl_data_in->data.uart_args.data, num_bytes); +      ctrl_data_out.id = USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE; +      ctrl_data_out.data.uart_args.bytes = num_bytes; +      break; +    } + +    default: +        ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; +        send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); +    } +     +} + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +static bool +eth_pkt_inspector(dbsm_t *sm, int bufno) +{ +  //point me to the ethernet frame +  uint32_t *buff = (uint32_t *)buffer_ram(bufno); + +  //treat this as fast-path data? +  // We have to do this operation as fast as possible. +  // Therefore, we do not check all the headers, +  // just check that the udp port matches +  // and that the vrt header is non zero. +  // In the future, a hardware state machine will do this... +  if ( //warning! magic numbers approaching.... +      (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && +      ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[1] != USRP2_INVALID_VRT_HEADER) +  ) return false; + +  //test if its an ip recovery packet +  typedef struct{ +      padded_eth_hdr_t eth_hdr; +      char code[4]; +      union { +        struct ip_addr ip_addr; +      } data; +  }recovery_packet_t; +  recovery_packet_t *recovery_packet = (recovery_packet_t *)buff; +  if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){ +      printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline(); +      set_ip_addr(&recovery_packet->data.ip_addr); +      return true; +  } + +  //pass it to the slow-path handler +  size_t len = buffer_pool_status->last_line[bufno] - 3; +  handle_eth_packet(buff, len); +  return true; +} + +//------------------------------------------------------------------ + +/* + * 1's complement sum for IP and UDP headers + * + * init chksum to zero to start. + */ +static unsigned int +CHKSUM(unsigned int x, unsigned int *chksum) +{ +  *chksum += x; +  *chksum = (*chksum & 0xffff) + (*chksum>>16); +  *chksum = (*chksum & 0xffff) + (*chksum>>16); +  return x; +} + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +volatile bool link_is_up = false;	// eth handler sets this +void +link_changed_callback(int speed) +{ +  link_is_up = speed != 0; +  hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); +  printf("\neth link changed: speed = %d\n", speed); +  if (link_is_up) send_gratuitous_arp(); +} + +static void setup_network(void){ + +  //setup ethernet header machine +  sr_udp_sm->eth_hdr.mac_dst_0_1 = (fp_mac_addr_dst.addr[0] << 8) | fp_mac_addr_dst.addr[1]; +  sr_udp_sm->eth_hdr.mac_dst_2_3 = (fp_mac_addr_dst.addr[2] << 8) | fp_mac_addr_dst.addr[3]; +  sr_udp_sm->eth_hdr.mac_dst_4_5 = (fp_mac_addr_dst.addr[4] << 8) | fp_mac_addr_dst.addr[5]; +  sr_udp_sm->eth_hdr.mac_src_0_1 = (fp_mac_addr_src.addr[0] << 8) | fp_mac_addr_src.addr[1]; +  sr_udp_sm->eth_hdr.mac_src_2_3 = (fp_mac_addr_src.addr[2] << 8) | fp_mac_addr_src.addr[3]; +  sr_udp_sm->eth_hdr.mac_src_4_5 = (fp_mac_addr_src.addr[4] << 8) | fp_mac_addr_src.addr[5]; +  sr_udp_sm->eth_hdr.ether_type = ETHERTYPE_IPV4; + +  //setup ip header machine +  unsigned int chksum = 0; +  sr_udp_sm->ip_hdr.ver_ihl_tos = CHKSUM(0x4500, &chksum);    // IPV4,  5 words of header (20 bytes), TOS=0 +  sr_udp_sm->ip_hdr.total_length = UDP_SM_INS_IP_LEN;             // Don't checksum this line in SW +  sr_udp_sm->ip_hdr.identification = CHKSUM(0x0000, &chksum);    // ID +  sr_udp_sm->ip_hdr.flags_frag_off = CHKSUM(0x4000, &chksum);    // don't fragment +  sr_udp_sm->ip_hdr.ttl_proto = CHKSUM(0x2011, &chksum);    // TTL=32, protocol = UDP (17 decimal) +  //sr_udp_sm->ip_hdr.checksum .... filled in below +  uint32_t src_ip_addr = fp_socket_src.addr.addr; +  uint32_t dst_ip_addr = fp_socket_dst.addr.addr; +  sr_udp_sm->ip_hdr.src_addr_high = CHKSUM(src_ip_addr >> 16, &chksum);    // IP src high +  sr_udp_sm->ip_hdr.src_addr_low = CHKSUM(src_ip_addr & 0xffff, &chksum); // IP src low +  sr_udp_sm->ip_hdr.dst_addr_high = CHKSUM(dst_ip_addr >> 16, &chksum);    // IP dst high +  sr_udp_sm->ip_hdr.dst_addr_low = CHKSUM(dst_ip_addr & 0xffff, &chksum); // IP dst low +  sr_udp_sm->ip_hdr.checksum = UDP_SM_INS_IP_HDR_CHKSUM | (chksum & 0xffff); + +  //setup the udp header machine +  sr_udp_sm->udp_hdr.src_port = fp_socket_src.port; +  sr_udp_sm->udp_hdr.dst_port = fp_socket_dst.port; +  sr_udp_sm->udp_hdr.length = UDP_SM_INS_UDP_LEN; +  sr_udp_sm->udp_hdr.checksum = UDP_SM_LAST_WORD;		// zero UDP checksum +} + +inline static void +buffer_irq_handler(unsigned irq) +{ +  uint32_t  status = buffer_pool_status->status; + +  dbsm_process_status(&dsp_tx_sm, status); +  dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ +  u2_init(); + +//we do this to see if we should set a default ip addr or not +#ifdef USRP2P +  bool safe_fw = find_safe_booted_flag(); +  set_safe_booted_flag(0); +  if(safe_fw) { +    set_default_ip_addr(); +    set_default_mac_addr(); +  } +#endif + +  putstr("\nTxRx-NEWETH\n"); +  print_mac_addr(ethernet_mac_addr()->addr); +  newline(); +  print_ip_addr(get_ip_addr()); newline(); +  printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM); +  printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM); + +  //1) register the addresses into the network stack +  register_mac_addr(ethernet_mac_addr()); +  register_ip_addr(get_ip_addr()); +   +  //2) register callbacks for udp ports we service +  register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet); +  register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); +  register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet); + +  //3) setup ethernet hardware to bring the link up +  ethernet_register_link_changed_callback(link_changed_callback); +  ethernet_init(); + +  // initialize double buffering state machine for ethernet -> DSP Tx + +  dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, +	    &dsp_tx_recv_args, &dsp_tx_send_args, +	    eth_pkt_inspector); + + +  // initialize double buffering state machine for DSP RX -> Ethernet + +    dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, +	      &dsp_rx_recv_args, &dsp_rx_send_args, +	      dbsm_rx_inspector); + +  sr_tx_ctrl->clear_state = 1; +  bp_clear_buf(DSP_TX_BUF_0); +  bp_clear_buf(DSP_TX_BUF_1); + +  // kick off the state machine +  dbsm_start(&dsp_tx_sm); + +  //int which = 0; + +  while(1){ +    // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); +    // which ^= 0x8000; + +    buffer_irq_handler(0); + +    if(i2c_done) { +      i2c_done = false; +      send_udp_pkt(USRP2_UDP_CTRL_PORT, i2c_src, &ctrl_data_out, sizeof(ctrl_data_out)); +      //printf("Sending UDP packet from main loop for I2C...\n"); +    } + +    if(spi_done) { +      spi_done = false; +      send_udp_pkt(USRP2_UDP_CTRL_PORT, spi_src, &ctrl_data_out, sizeof(ctrl_data_out)); +    } + +    int pending = pic_regs->pending;		// poll for under or overrun + +    if (pending & PIC_UNDERRUN_INT){ +      //dbsm_handle_tx_underrun(&dsp_tx_sm); +      pic_regs->pending = PIC_UNDERRUN_INT;	// clear interrupt +      putchar('U'); +    } + +    if (pending & PIC_OVERRUN_INT){ +      //dbsm_handle_rx_overrun(&dsp_rx_sm); +      pic_regs->pending = PIC_OVERRUN_INT;	// clear pending interrupt + +      // FIXME Figure out how to handle this robustly. +      // Any buffers that are emptying should be allowed to drain... + +      putchar('O'); +    } +  } +} diff --git a/firmware/microblaze/apps/uart_flash_loader.c b/firmware/microblaze/apps/uart_flash_loader.c new file mode 100644 index 000000000..d67b84677 --- /dev/null +++ b/firmware/microblaze/apps/uart_flash_loader.c @@ -0,0 +1,169 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +//#include <stdio.h> +#include <stdlib.h> +#include <memory_map.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <hal_uart.h> +#include <xilinx_s3_icap.h> +#include <spi_flash.h> +#include <spi_flash_private.h> +//#include <clocks.h> +#include <ihex.h> +#include <bootloader_utils.h> + +//uses UART to load files to Flash in Intel HEX 16-bit format. +//this is one example of a "safe" firmware image to be loaded by a bootloader into main RAM. +//this CANNOT write to main RAM, since it is resident there. + +//Sector 0-31: Safe FPGA bootloader image +//Sector 32-63: Production bootloader image +//Sector 64: Production firmware image +//Sector 127: Safe firmware image + + +void uart_flash_loader(void) { + +	char buf[256]; //input data buffer +	uint8_t ihx[32]; //ihex data buffer +	uint32_t slot_offset = PROD_FW_IMAGE_LOCATION_ADDR; //initial slot offset to program to. +	uint32_t extended_addr = 0x00000000; //extended Intel hex segment address + +	size_t sector_size = spi_flash_log2_sector_size(); +	ihex_record_t ihex_record; +	ihex_record.data = ihx; +	int i; + + +	//not gonna win a turing prize for my C text parsing +	while(1) { +		gets(buf); +		if(!strncmp(buf, "!SECTORSIZE", 7)) { //return the sector size in log format +			putstr("OK "); +			puthex8((uint32_t) sector_size); //err, this should probably be decimal for human readability. we do have itoa now... +			putstr("\n"); +		} +		else if(!strncmp(buf, "!SETADDR", 7)) { //set start address for programming +			slot_offset = atol(&buf[8]); +			puts("OK"); +//			puthex32(slot_offset); +//			putstr("\n"); +		} +		else if(!strncmp(buf, "!ERASE", 6)) { //erase a sector +			uint32_t sector = atol(&buf[6]); +			uint32_t size = 2 << (sector_size-1); +			uint32_t addr = sector << sector_size; + +			spi_flash_erase(addr, size); //we DO NOT implement write protection here. it is up to the HOST PROGRAM to not issue an ERASE unless it means it. +																	 //unfortunately the Flash cannot write-protect the segments that really matter, so we only use global write-protect +																	 //as a means of avoiding accidental writes from runaway code / garbage on the SPI bus. +			puts("OK"); +		} +//can't exactly run firmware if you're already executing out of main RAM +/*		else if(!strncmp(buf, "!RUNSFW", 7)) { +			if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { +				puts("OK"); +				spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); +				start_program(RAM_BASE); +			} else { +				puts("NOK"); +			} +		} +		else if(!strncmp(buf, "!RUNPFW", 7)) { +			if(is_valid_fw_image(PROD_FW_IMAGE_LOCATION_ADDR)) { +				puts("OK"); +				spi_flash_read(PROD_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES-1, (void *)RAM_BASE); +				start_program(RAM_BASE); +			} else { +				puts("NOK"); +			} +		} +*/ +		else if(!strncmp(buf, "!RUNPFPGA", 8)) { +			if(is_valid_fpga_image(PROD_FPGA_IMAGE_LOCATION_ADDR)) { +				puts("OK"); +				//icap_reload_fpga(PROD_FPGA_IMAGE_LOCATION_ADDR); +			} else { +				puts("NOK"); +			}				 +		} +		else if(!strncmp(buf, "!RUNSFPGA", 8)) { +			if(is_valid_fpga_image(SAFE_FPGA_IMAGE_LOCATION_ADDR)) { +				puts("OK"); +				//icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); +			} else { +				puts("NOK"); +			} +		} +		else if(!strncmp(buf, "!READ", 5)) { +			uint32_t addr = atol(&buf[5]); +			spi_flash_read(addr, 16, ihx); +			for(i=0; i < 16; i++) { +				puthex8(ihx[i]); +			} +			putstr("\n"); +		} + +		else if(!ihex_parse(buf, &ihex_record)) { //last, try to see if the input was a valid IHEX line +			switch (ihex_record.type) { +				case 0: +					spi_flash_program(ihex_record.addr + slot_offset + extended_addr, ihex_record.length, ihex_record.data); +					puts("OK"); +					break; +				case 1: +					//here we would expect a CRC checking or something else to take place. for now we do nothing. +					//well, we set the extended segment addr back to 0 +					extended_addr = 0; +					puts("DONE"); +					break; +				case 4: +					//set the upper 16 bits of the address +					extended_addr = ((ihex_record.data[0] << 8) + ihex_record.data[1]) << 16; +					puts("OK"); +					break; +				default: +					puts("NOK"); +			} +		} +		else puts("NOK"); +	} //while(1) +} + +void delay(uint32_t t) { +	while(t-- != 0) asm("NOP"); +} + +int main(int argc, char *argv[]) { +	uint8_t buf[32]; +	int i = 0; + +  hal_disable_ints();	// In case we got here via jmp 0x0 + +//	delay(10000000); + +	//before anything else you might want to blinkenlights just to indicate code startup to the user. + +  hal_uart_init(); +	spif_init(); +//	i2c_init(); //for EEPROM +	puts("USRP2+ UART firmware loader"); + +//	puts("Debug: loading production image, 10 bytes."); + +//	spi_flash_read(PROD_FW_IMAGE_LOCATION_ADDR, 10, buf); +//	for(i=0; i < 10; i++) { +//		puthex8(buf[i]); +//	} + +	uart_flash_loader(); + + 	//shouldn't get here. should reboot. +	puts("shit happened.\n"); + +	return 0; +} diff --git a/firmware/microblaze/bin/bin_to_mif.py b/firmware/microblaze/bin/bin_to_mif.py new file mode 100755 index 000000000..cefce4e92 --- /dev/null +++ b/firmware/microblaze/bin/bin_to_mif.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import struct +import sys + +hextab = ('0000', '0001', '0010', '0011', +          '0100', '0101', '0110', '0111', +          '1000', '1001', '1010', '1011', +          '1100', '1101', '1110', '1111') + +def w_to_binary_ascii(w): +    return ''.join([hextab[(w >> 4*i) & 0xf] for i in range(7,-1,-1)]) + +def bin_to_mif(bin_input_file, mif_output_file): +    ifile = open(bin_input_file, 'rb') +    ofile = open(mif_output_file, 'w') +    idata = ifile.read() +    fmt = ">%dI" % ((len(idata) / 4),) +    words = struct.unpack(fmt, idata) +    for w in words: +        ofile.write(w_to_binary_ascii(w)) +        ofile.write('\n') + +if __name__ == '__main__': +    if len(sys.argv) != 3: +        sys.stderr.write("usage: bin_to_mif bin_input_file mif_output_file\n") +        raise SystemExit, 1 +     +    bin_to_mif(sys.argv[1], sys.argv[2]) diff --git a/firmware/microblaze/bin/bin_to_ram_macro_init.py b/firmware/microblaze/bin/bin_to_ram_macro_init.py new file mode 100755 index 000000000..65cf2dbdf --- /dev/null +++ b/firmware/microblaze/bin/bin_to_ram_macro_init.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +import struct +import sys + +def do_8_words(ofile, which_ram, row, words): +    ofile.write("defparam bootram.RAM%d.INIT_%02X=256'h" % (which_ram, row)) +    ofile.write("%08x_%08x_%08x_%08x_%08x_%08x_%08x_%08x;\n" % ( +        words[7], words[6], words[5], words[4], words[3], words[2], words[1], words[0])) + +def bin_to_ram_macro_init(bin_input_file, ram_init_output_file): +    ifile = open(bin_input_file, 'rb') +    ofile = open(ram_init_output_file, 'w') +    idata = ifile.read() +    fmt = ">%dI" % ((len(idata) / 4),) +    words = struct.unpack(fmt, idata) + +    # pad to a multiple of 8 words +    r = len(words) % 8 +    if r != 0: +        words += (8 - r) * (0,) + +    if len(words) > 2048: +        sys.stderr.write("bin_to_macro_init: error: input file %s is > 8KiB\n" % (bin_input_file,)) +        sys.exit(1) + +    # first 2KB +    for i in range(0, min(512, len(words)), 8): +        do_8_words(ofile, 0, i/8, words[i:i+8]) + +    # second 2KB +    for i in range(512, min(1024, len(words)), 8): +        do_8_words(ofile, 1, (i/8) % 64, words[i:i+8]) + +		# third 2KB +    for i in range(1024, min(1536, len(words)), 8): +        do_8_words(ofile, 2, (i/8) % 64, words[i:i+8]) + +		# last 2KB +    for i in range(1536, len(words), 8): +        do_8_words(ofile, 3, (i/8) % 64, words[i:i+8]) + +if __name__ == '__main__': +    if len(sys.argv) != 3: +        sys.stderr.write("usage: bin_to_ram_macro_init bin_input_file ram_init_output_file\n") +        sys.exit(1) +     +    bin_to_ram_macro_init(sys.argv[1], sys.argv[2]) diff --git a/firmware/microblaze/bin/elf_to_sbf b/firmware/microblaze/bin/elf_to_sbf new file mode 100755 index 000000000..d1be10c0d --- /dev/null +++ b/firmware/microblaze/bin/elf_to_sbf @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +import sys +import struct +from optparse import OptionParser +from pprint import pprint + +import sbf + +# see /usr/include/elf.h for the various magic values + + +_ehdr_fmt = ">16sHH5I6H" +_ehdr_fmt_size = struct.calcsize(_ehdr_fmt) +_phdr_fmt = ">8I" +_phdr_fmt_size = struct.calcsize(_phdr_fmt) + +class elf32_ehdr(object): +    def __init__(self, s): +        (self.ident, self.type, self.machine, self.version, self.entry, +         self.phoff, self.shoff, self.flags, self.ehsize, +         self.phentsize, self.phnum, self.shentsize, self.shnum, +         self.shstrndx) = struct.unpack(_ehdr_fmt, s) + +class elf32_phdr(object): +    def __init__(self, s): +        (self.type, self.offset, self.vaddr, self.paddr, +         self.filesz, self.memsz, +         self.flags, self.align) = struct.unpack(_phdr_fmt, s) + +    def __repr__(self): +        return "<elf32_phdr %s offset=%d paddr=0x%x, filesz=%d>" % ( +            p_type_str(self.type), self.offset, self.paddr, self.filesz) + + +def p_type_str(t): +    if t <= 8: +        return ('NULL', 'LOAD', 'DYNAMIC', 'INTERP', 'NOTE', 'SHLIB', 'PHDR', 'TLS', 'NUM')[t] +    return "0x%x" % (t,) + + + +def _get_ehdr(f): +    if len(f) < _ehdr_fmt_size: +        return False +    ehdr = elf32_ehdr(f[0:_ehdr_fmt_size]) +    return ehdr + +     +def elf32_big_endian_exec_p(f): +    ehdr = _get_ehdr(f) +    if not ehdr: +        return False +     +    #pprint(ehdr, sys.stderr) +    e_ident = ehdr.ident +    if not e_ident.startswith('\177ELF'): +        return False +    if (ord(e_ident[4]) != 1            # EI_CLASS == CLASS32 +        or ord(e_ident[5]) != 2         # EI_DATA == DATA2MSB +        or ord(e_ident[6]) != 1         # EI_VERSION == EV_CURRENT +        ): +        return False + +    if ehdr.type != 2:                  # e_type == ET_EXEC +        return False + +    return True + + + +# return (entry, (phdr, ...)) + +def get_elf32_prog_headers(f): +    ehdr = _get_ehdr(f) +    entry = ehdr.entry +    phoff = ehdr.phoff +    phentsize = ehdr.phentsize +    phnum = ehdr.phnum + +    def extract(i): +        start = phoff + i * phentsize +        end = start + phentsize +        return f[start:end] +     +    return (entry, [elf32_phdr(extract(i)) for i in range(phnum)]) +     + +def main(): +    usage = "%prog: [options] elf_file" +    parser = OptionParser() +    parser.add_option("-o", "--output", default=None, +                      help="specify output filename [default=stdout]") +    (options, args) = parser.parse_args() +    if len(args) != 1: +        parser.print_help() +        sys.exit(1) + +    elf_file = open(args[0], 'rb') + +    elf_contents = elf_file.read() +    if not elf32_big_endian_exec_p(elf_contents): +        sys.stderr.write("%s: not a big-endian 32-bit ELF executable\n" % (args[0],)) +        sys.exit(1) +         +    if options.output is None: +        sbf_file = sys.stdout +    else: +        sbf_file = open(options.output, 'wb') + +    (entry, phdrs) = get_elf32_prog_headers(elf_contents) +    #pprint(phdrs, sys.stderr) + +    def phdr_to_sec_desc(phdr): +        target_addr = phdr.paddr +        data = elf_contents[phdr.offset:phdr.offset+phdr.filesz] +        #print >>sys.stderr, "pdhr_to_sec_desc:", (target_addr, data) +        return sbf.sec_desc(target_addr, data) + +    sections = map(phdr_to_sec_desc, phdrs) +    # pprint(sections, sys.stderr) +    sbf.write_sbf(sbf_file, sbf.header(entry, sections)) + + +if __name__ == '__main__': +    main() diff --git a/firmware/microblaze/bin/sbf.py b/firmware/microblaze/bin/sbf.py new file mode 100644 index 000000000..8e2c868a5 --- /dev/null +++ b/firmware/microblaze/bin/sbf.py @@ -0,0 +1,134 @@ +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +_SBF_MAGIC = 'SBF!' +_SBF_DONT_EXECUTE = 0x1 +_SBF_MAX_SECTIONS = 14 +_SBF_HEADER_LEN = 128 + +import struct +import sys +from pprint import pprint + +def dump_data(f, offset, data): +    L = len(data) // 4 +    for i in range(L): +        f.write('%08x:  %08x\n' % (offset + 4 * i, struct.unpack('>I', data[4*i:4*(i+1)])[0])) +    remainder = len(data) - L * 4 +    if remainder != 0: +        f.write('%08x:  ' % (offset + L*4,)) +        i = 0 +        while i < remainder: +            f.write('%02x' % ((ord(data[L*4 + i]),))) +            i += 1 +        f.write('\n') + + + +class sec_desc(object): +    def __init__(self, target_addr, data): +        self.target_addr = target_addr +        self.data = data + +    def __repr__(self): +        #print >>sys.stderr, "target_addr:", self.target_addr +        #print >>sys.stderr, "data:", self.data +        return "<sec_desc target_addr=0x%x len=%d>" % ( +            self.target_addr, len(self.data)) + + +class header(object): +    def __init__(self, entry, sections): +        self.entry = entry +        self.section = sections + +    def dump(self, f): +        if self.entry == _SBF_DONT_EXECUTE: +            f.write("Entry: DONT_EXECUTE\n") +        else: +            f.write("Entry: 0x%x\n" % (self.entry,)) +        for i in range(len(self.section)): +            s = self.section[i] +            f.write("Section[%d]: target_addr = 0x%x  length = %d\n" % (i, +                                                                        s.target_addr, +                                                                        len(s.data))) +            dump_data(f, s.target_addr, s.data) + +    # +    # Returns an iterator.  Each yield returns (target_addr, data) +    # +    def iterator(self, max_piece=512): +        for s in self.section: +            offset = 0 +            L = len(s.data) +            while offset < L: +                n = min(max_piece, L - offset) +                yield (s.target_addr + offset, +                       s.data[offset:offset+n]) +                offset += n + + + +def read_sbf(input_file): +    """Parse an SBF file""" +     +    f = input_file.read(_SBF_HEADER_LEN) +    #if len(f) < _SBF_HEADER_LEN or not f.startswith(_SBF_MAGIC): +        #raise ValueError, '%s: not an SBF file' % (input_file.name,) +     +    def extract(i): +        start = 16+8*i +        stop = start+8 +        return struct.unpack('>2I', f[start:stop]) + +    def get_data(ss): +        L = ss[1] +        s = input_file.read(L) +        #if len(s) != L: +            #raise ValueError, '%s: file is too short' % (input_file.name(),) +        return s +         +    (magic, entry, nsections, reserved) = struct.unpack('>4s3I', f[0:16]) +    assert nsections <= _SBF_MAX_SECTIONS +    descs = [extract(i) for i in range(nsections)] +    #pprint(descs, sys.stderr) +    data = map(get_data, descs) +    secs = map(lambda ss, data: sec_desc(ss[0], data), descs, data) +    return header(entry, secs) + + +def write_sbf(output_file, sbf_header): +    assert(len(sbf_header.section) <= _SBF_MAX_SECTIONS) +    sbf_header.nsections = len(sbf_header.section) +    f = output_file + +    # write the file header +    f.write(struct.pack('>4s3I', _SBF_MAGIC, sbf_header.entry, sbf_header.nsections, 0)) + +    # write the section headers +    for i in range(sbf_header.nsections): +        f.write(struct.pack('>2I',  +                            sbf_header.section[i].target_addr, +                            len(sbf_header.section[i].data))) +    for i in range(_SBF_MAX_SECTIONS - sbf_header.nsections): +        f.write(struct.pack('>2I', 0, 0)) + +    # write the section data +    for i in range(sbf_header.nsections): +        f.write(sbf_header.section[i].data) + +    return True diff --git a/firmware/microblaze/bin/serial_loader b/firmware/microblaze/bin/serial_loader new file mode 100755 index 000000000..9bd5aada7 --- /dev/null +++ b/firmware/microblaze/bin/serial_loader @@ -0,0 +1,363 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +import termios +import tty +import os +import sys +import threading +import Queue +from optparse import OptionParser +import time + +import sbf + +GDB_ESCAPE = chr(0x7d) + +# Indexes for termios list. +IFLAG = 0 +OFLAG = 1 +CFLAG = 2 +LFLAG = 3 +ISPEED = 4 +OSPEED = 5 +CC = 6 + +class terminal(object): +    def __init__(self, device, speed_bits): +        fd = os.open(device, os.O_RDWR) +        if not os.isatty(fd): +            raise ValueError(device + " is not a tty") + +        self.read_file = os.fdopen(fd, "rb", 0) +        self.write_file = os.fdopen(os.dup(fd), "wb", 0) +        self.old_attrs = termios.tcgetattr(self.write_file.fileno()) +        #print "old_attrs: ", self.old_attrs +        attrs = list(self.old_attrs)    # copy of attributes +        attrs[ISPEED] = speed_bits      # set input and output speed +        attrs[OSPEED] = speed_bits +        termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs) +        tty.setraw(self.write_file.fileno())     # enable raw mode +        attrs = termios.tcgetattr(self.write_file.fileno()) +        attrs[CC][termios.VMIN] = 1     # minimim of 1 char +        attrs[CC][termios.VTIME] = 1    # wait no longer than 1/10 +        termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs) + +    def __del__(self): +        termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, self.old_attrs) +        self.read_file.close() +        self.write_file.close() + +    def read(self, n): +        """Read at most n bytes from tty""" +        return self.read_file.read(n) + +    def write(self, str): +        """Write str to tty.""" +        return self.write_file.write(str) + + +def hexnibble(i): +    return "0123456789abcdef"[i & 0xf] + +def build_pkt(payload): +    s = ['$'] +    checksum = 0 + +    for p in payload: +        if p in ('$', '#', GDB_ESCAPE): +            s.append(GDB_ESCAPE) +        s.append(p) +        checksum += ord(p) + +    checksum &= 0xff +    s.append('#') +    s.append(hexnibble(checksum >> 4)) +    s.append(hexnibble(checksum)) + +    return ''.join(s) + + +def build_memory_read_pkt(addr, len): +    return build_pkt(('m%x,%x' % (addr, len))) + +def build_memory_write_hex_pkt(addr, s): +    hexdata = ''.join(["%02x" % (ord(c),) for c in s]) +    return build_pkt(('M%x,%x:' % (addr, len(s))) + hexdata) + +def build_memory_write_pkt(addr, s): +    return build_pkt(('X%x,%x:' % (addr, len(s))) + s) + +def build_goto_pkt(addr): +    return build_pkt(('c%x' % (addr,))) + + +def get_packet(f): +    """Return a valid packet, or None on EOF or timeout""" +    LOOKING_FOR_DOLLAR = 0 +    LOOKING_FOR_HASH = 1 +    CSUM1 = 2 +    CSUM2 = 3 + +    fd = f.fileno() +     +    state = LOOKING_FOR_DOLLAR +    buf = [] + +    while True: +        ch = os.read(fd, 1) +        sys.stdout.write(ch) +        if len(ch) == 0: +            print("Returning None") +            return(None) +         +        if state == LOOKING_FOR_DOLLAR: +            if ch == '$': +                buf = [] +                state = LOOKING_FOR_HASH +            elif ch == '#': +                state = LOOKING_FOR_DOLLAR + +        elif state == LOOKING_FOR_HASH: +            if ch == '$': +                state = LOOKING_FOR_DOLLAR +            elif ch == '#': +                state = CSUM1 +            else: +                if ch == GDB_ESCAPE: +                    ch = getc() +                buf.append(ch) + +        elif state == CSUM1: +            chksum1 = ch +            state = CSUM2 + +        elif state == CSUM2: +            chksum2 = ch +            r = ''.join(buf) +            if chksum1 == '.' and chksum2 == '.': +                return r + +            expected_checksum = int(chksum1 + chksum2, 16) +            checksum = 0 +            for c in buf: +                checksum += ord(c) + +            checksum &= 0xff +            if checksum == expected_checksum: +                return r + +            state = LOOKING_FOR_DOLLAR + +        else: +            raise ValueError( "Invalid state") + + +class packet_reader_thread(threading.Thread): +    def __init__(self, tty_in, q): +        threading.Thread.__init__(self) +        self.setDaemon(1) +        self.tty_in = tty_in +        self.q = q +        self._keep_running = True +        self.start() + +    def run(self): +        while self._keep_running == True: +            p = get_packet(self.tty_in) +            if p is not None: +                self.q.put(('pkt', p)) + + +def _make_tr_table(): +    table = [] +    for c in range(256): +        if c < ord(' ') or c > ord('~'): +            table.append('.') +        else: +            table.append(chr(c)) +    return ''.join(table) +         + +class controller(object): +    def __init__(self, tty): +        self.tty = tty +        self.q = Queue.Queue(0) +        self.timers = {} +        self.next_tid = 1 +        self.current_tid = 0 +        self.ntimeouts = 0 +        self.packet_reader = packet_reader_thread(tty.read_file, self.q) +        self.state = None +        self.debug = False +        self.tt = _make_tr_table() + +        self.done = False +        self.addr = None +        self.bits = None + +    def shutdown(self): +        self.packet_reader._keep_running = False + +    def start_timeout(self, timeout_in_secs): +        def callback(tid): +            if self.timers.has_key(tid): +                del self.timers[tid] +            self.q.put(('timeout', tid)) +        self.next_tid += 1 +        tid = self.next_tid +        timer = threading.Timer(timeout_in_secs, callback, (tid,)) +        self.timers[tid] = timer +        timer.start() +        return tid + +    def cancel_timeout(self, tid): +        if self.timers.has_key(tid): +            self.timers[tid].cancel() +            del self.timers[tid] + +    def send_packet(self, pkt): +        if self.debug: +            if len(pkt) > 64: +                s = pkt[0:64] + '...' +            else: +                s = pkt +            sys.stdout.write('-> ' +  s.translate(self.tt) + '\n') +        self.tty.write(pkt); + +    def send_packet_start_timeout(self, pkt, secs): +        self.send_packet(pkt) +        self.current_tid = self.start_timeout(secs) +         +    def upload_code(self, sbf): +        MAX_PIECE = 512                 # biggest piece to send +        MWRITE_TIMEOUT = 0.1 + +        IDLE = 0 +        WAIT_FOR_ACK = 1 +        UPLOAD_DONE = 2 +        DONE = 3 +        FAILED = 4 + +        self.done = False +        it = sbf.iterator(MAX_PIECE) +        entry_addr = sbf.entry + +        def get_next_bits(): +            try: +                (self.addr, self.bits) = it.next() +            except StopIteration: +                self.done = True +             +        def is_done(): +            return self.done +         +        def send_piece(): +            pkt = build_memory_write_pkt(self.addr, self.bits) +            #pkt = build_memory_write_hex_pkt(self.addr, self.bits) +            self.send_packet_start_timeout(pkt, MWRITE_TIMEOUT) +            state = WAIT_FOR_ACK + +        def advance(): +            get_next_bits() +            if is_done(): +                self.state = DONE +                self.send_packet(build_goto_pkt(entry_addr)) +                 +            else: +                self.ntimeouts = 0 +                send_piece() + +        get_next_bits() +        if is_done():                   # empty file +            return True +         +        send_piece()                    # initial transition +         +        while 1: +            (event, value) = self.q.get() + +            if event == 'timeout' and value == self.current_tid: +                self.ntimeouts += 1 +                if self.ntimeouts >= 5: +                    return False        # say we failed +                send_piece()            # resend +                 + +            elif event == 'pkt': +                if value == 'OK': +                    self.cancel_timeout(self.current_tid) +                    advance() +                    if self.state == DONE: +                        return True +                else: +                    print("Error returned from firmware: " + value) +                    return False + +            else: +                print("Unknown event:", (event, value)) + +def main(): +    usage="%prog: [options] filename" +    parser = OptionParser(usage=usage) +    parser.add_option("-t", "--tty", type="string", default="/dev/ttyS0", +                      help="select serial port [default=%default]") + +    (options, args) = parser.parse_args() +    if len(args) != 1: +        parser.print_help() +        raise SystemExit(1) + + +    filename = args[0] +    f = open(filename, "rb") +    try: +        # Try to open the file as an SBF file +        sbf_header = sbf.read_sbf(f) +    except: +        # If that fails, build an SBF from the binary, assuming default +        # load address and entry point +        f.seek(0) +        t = f.read() +        if t.startswith('\177ELF'): +            sys.stderr.write("Can't load an ELF file.  Please use an SBF file instead.\n") +            raise SystemExit( 1) +        sbf_header = sbf.header(0x8000, [sbf.sec_desc(0x8000, t)]) +         + +    tty = terminal(options.tty, termios.B115200) +    ctrl = controller(tty) +    ok = ctrl.upload_code(sbf_header) +     +    if ok: +        print("OK") +        try: +            raw_input("Press Enter to exit: ") +        except KeyboardInterrupt: +            pass +        ctrl.shutdown() +        time.sleep(0.2) +         +    else: +        print("Upload failed") +        ctrl.shutdown() +     +     +     +if __name__ == "__main__": +    main() diff --git a/firmware/microblaze/bin/uart_ihex_flash_loader.py b/firmware/microblaze/bin/uart_ihex_flash_loader.py new file mode 100755 index 000000000..5a3300f34 --- /dev/null +++ b/firmware/microblaze/bin/uart_ihex_flash_loader.py @@ -0,0 +1,138 @@ +#!/usr/bin/python + +import serial +from optparse import OptionParser +import os, sys + +#TODO: pull everything but parser out of main() and put it in a separate function we can call from another script. lets us automate loading RAM+FLASH to produce a fully-loaded image. +#TODO: make it fail gracefully -- if it gets a NOK or times out, do at least one retry. +#TODO: put hooks in (eventually) to allow verifying a firmware image so the user can more safely update the "safe" image +#TODO: how about a progress indicator? FPGA images take FOREVER. you can use wc -l to get the number of lines, or do it with file i/o. + +def main(): +	usage="%prog: [options] filename" +	parser = OptionParser(usage=usage) +	parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0", +                     help="select serial port [default=%default]") +	parser.add_option("-b", "--baudrate", type=int, default=115200, +										 help="set baudrate [default=%default]") +	parser.add_option("-F", "--write-safe-firmware", action="store_const", const=1, dest="image", +										 help="write to safe firmware image") +	parser.add_option("-f", "--write-production-firmware", action="store_const", const=2, dest="image", +										 help="write to production firmware image") +	parser.add_option("-P", "--write-safe-fpga", action="store_const", const=3, dest="image", +										 help="write to safe FPGA image") +	parser.add_option("-p", "--write-production-fpga", action="store_const", const=4, dest="image", +										 help="write to production FPGA image") + +	(options, args) = parser.parse_args() + +	if(options.image is None): +		print("At least one of -f, -F, -p, -P must be specified.\n") +		parser.print_help() +		raise SystemExit(1) +	 +	if len(args) != 1: +		parser.print_help() +		raise SystemExit(1) + +	if(options.image == 3): +		print "Are you *really* sure you want to write to the failsafe FPGA image? If you mess this up your USRP2+ will become a brick. Press 'y' to continue, any other key to abort." +		if(raw_input().rstrip() is not "y"): +			print "Good choice." +			raise SystemExit(0) + +	elif(options.image == 1): +		print "Are you *really* sure you want to write to the failsafe firmware image? If you mess this up your USRP2+ will only be able to be reprogrammed via the UART RAM loader.\nPress 'y' to continue, any other key to abort." +		if(raw_input().rstrip() is not "y"): +			print "Good choice." +			raise SystemExit(0) + +	filename = args[0] +	f = open(filename, "r") + +	#now we start doing things... +	if(os.path.exists(options.tty) is False): +		sys.stderr.write("No serial port found at %s\n" % options.tty) +		raise SystemExit(1) +	 +	try: +		ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0) +	except serial.SerialException: +		sys.stderr.write("Unable to open serial port\n") +		raise SystemExit(1) + +	ser.open() + +#test to see if a valid USRP2+ in flash load mode is connected +	ser.write("garbage\n") +	ser.readline() +	ser.write("!SECTORSIZE\n") +	reply = ser.readline().rstrip() +	if("NOK" in reply): +		sys.stderr.write("Error writing to USRP2+. Try again.\n") +		raise SystemExit(1) +	elif("OK" in reply): +		sectorsize = int(reply[3:5], 16) +		print("USRP2+ found with sector size %i. Erasing old image." % 2**sectorsize) +	else: +		sys.stderr.write("Invalid response or no USRP2+ connected.\n") +		raise SystemExit(1) + +	if(options.image == 1): +		sectors = range(127, 128) +		runcmd = "!RUNSFD\n" +	elif(options.image == 2): +		sectors = range(64, 65) +		runcmd = "!RUNPFD\n" +	elif(options.image == 3): +		sectors = range(0,32) +		runcmd = "!RUNSFPGA\n" +	elif(options.image == 4): +		sectors = range(32,64) +		runcmd = "!RUNPFPGA\n" + +	writeaddr = sectors[0] << sectorsize +	if(options.image < 3): +		writeaddr -= 0x8000 #i know this is awkward, but we subtract 0x8000 from the address for firmware loads. the reason we do this is that the IHX files are located at 0x8000 (RAM_BASE), and +												#doing this here allows us to use the same IHX files for RAM load as for Flash load, without relocating in objcopy or relinking with another ld script. +												#this limits us to writing above 32K for our firmware images. since the safe FPGA image located at 0x00000000 takes up 2MB of space this isn't really a worry. +												#FPGA images (.mcs) always start at 0x00000000 so they don't need this relocation. + +	for sector in sectors: +		print "Erasing sector %i" % sector +		ser.write("!ERASE %i\n" % sector) +		reply = ser.readline() +		if("NOK" in reply): +			sys.stderr.write("Error erasing sector %i" % sector) +			raise SystemExit(1) +	 +	print "Setting start address to %i" % writeaddr +	ser.write("!SETADDR %i\n" % writeaddr) +	if("NOK" in reply): +		sys.stderr.write("Error setting address\n") +		raise SystemExit(1) +	else: +		print reply + + +	for line in f: +		ser.write(line.rstrip()+'\n') +		reply = ser.readline() +		if("NOK" in reply): #TODO: simplify this logic, use (reply.rstrip() is "NOK") +			print("Received NOK reply during data write") +			raise SystemExit(1) +		elif("DONE" in reply): +			print("Finished writing program. Loading...\n") +			ser.write(runcmd) +		elif("OK" not in reply): +			print("Received invalid reply %s during data write" % reply) +			raise SystemExit(1) +		else: +			print reply.rstrip() + '\t' + line.rstrip() + +	print ser.readline() + + +if __name__ == '__main__': +	main() diff --git a/firmware/microblaze/bin/uart_ihex_ram_loader.py b/firmware/microblaze/bin/uart_ihex_ram_loader.py new file mode 100755 index 000000000..c90fbe1d8 --- /dev/null +++ b/firmware/microblaze/bin/uart_ihex_ram_loader.py @@ -0,0 +1,70 @@ +#!/usr/bin/python + +import serial +from optparse import OptionParser +import os, sys + +def main(): +	usage="%prog: [options] filename" +	parser = OptionParser(usage=usage) +	parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0", +                     help="select serial port [default=%default]") +	parser.add_option("-b", "--baudrate", type=int, default=115200, +										 help="set baudrate [default=%default]") + +	(options, args) = parser.parse_args() +	if len(args) != 1: +		parser.print_help() +		raise SystemExit(1) + +	filename = args[0] +	f = open(filename, "r") + +	#all we have to do is load the IHX file and attempt to spit it out to the serial port. +	if(os.path.exists(options.tty) is False): +		sys.stderr.write("No serial port found at %s\n" % options.tty) +		raise SystemExit(1) +	 +	try: +		ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0) +	except serial.SerialException: +		sys.stderr.write("Unable to open serial port\n") +		raise SystemExit(1) + +	ser.open() + +#test to see if a valid USRP2+ in RAM load mode is connected + +	ser.write("WOOOOO\n"); +	reply = ser.readline() +	if("NOK" not in reply): +		sys.stderr.write("Valid USRP2+ not connected or no response received\n") +		raise SystemExit(1) +	else: +		print("USRP2+ found.") + +	for line in f: +		ser.write(line.rstrip() + '\n') +		reply = ser.readline() +		if("NOK" in reply): #blocks to wait for response +			print("Received NOK reply from USRP2+") +			raise SystemExit(1) +		elif("OK" not in reply): +			print("Received invalid reply!") +			raise SystemExit(1) +#		else: +#			print("OK received") + +	print "USRP2+ RAM programmed.\nLoading program." + +	#at this point it should have sent the end line of the file, which starts the program! +	#we'll just act like a dumb terminal now +#	ser.timeout = 0 +#	try: +#		while 1: +#			print ser.readline() +#	except KeyboardInterrupt: +#		raise SystemExit(0) + +if __name__ == '__main__': +	main() diff --git a/firmware/microblaze/bootstrap b/firmware/microblaze/bootstrap new file mode 100755 index 000000000..26987b0ec --- /dev/null +++ b/firmware/microblaze/bootstrap @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +rm -rf *.cache +rm -rf libusrp2/.deps +rm -rf libusrp2p/.deps + +aclocal +autoconf +libtoolize --automake +automake --add-missing --gnu --warnings=all diff --git a/firmware/microblaze/configure.ac b/firmware/microblaze/configure.ac new file mode 100644 index 000000000..f6986f2dd --- /dev/null +++ b/firmware/microblaze/configure.ac @@ -0,0 +1,54 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +################################################## +## Setup Autotools +################################################## +AC_PREREQ(2.60) +AC_INIT +AM_INIT_AUTOMAKE(uhd-mb, 0) + +################################################## +## Setup Compiler +################################################## +dnl Fix 2.64 cross compile detection for AVR and RTEMS +dnl by not trying to compile fopen. +m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.64], +  [m4_foreach([_GCC_LANG], [C, C++, Fortran, Fortran 77], +     [m4_define([_AC_LANG_IO_PROGRAM(]_GCC_LANG[)], m4_defn([AC_LANG_PROGRAM(]_GCC_LANG[)]))])])  + +AC_PROG_CC([mb-gcc]) +AM_PROG_CC_C_O +LT_INIT + +################################################## +## Setup Tools +################################################## +AC_PATH_PROG([MB_OBJCOPY], [mb-objcopy]) +AC_PATH_PROG([MB_OBJDUMP], [mb-objdump]) +AC_PATH_PROG([HEXDUMP],    [hexdump]) + +################################################## +## Create Files +################################################## +AC_CONFIG_FILES([ \ +    Makefile \ +    usrp2p/bootloader/Makefile \ +    usrp2/Makefile \ +    usrp2p/Makefile \ +]) +AC_OUTPUT diff --git a/firmware/microblaze/divisors.py b/firmware/microblaze/divisors.py new file mode 100755 index 000000000..d31bd4dad --- /dev/null +++ b/firmware/microblaze/divisors.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +speeds = (9600, 19200, 38400, 57600, 115200, 230400) + +master_clk = 100e6 +wb_clk = master_clk / 2 + +def divisor(speed): +    div0 = wb_clk // (speed * 16) +    div1 = div0 + 1 +    actual0 = actual_speed(div0) +    actual1 = actual_speed(div1) +    if abs(actual0 - speed) < abs(actual1 - speed): +        return div0 +    else: +        return div1 + +def actual_speed(divisor): +    return (wb_clk // divisor) / 16 + +def doit(speed): +    div = divisor(speed) +    actual = actual_speed(div) +    rel_error = (actual - speed) / speed +    print "target: %6d  divisor: %6d  actual: %11.4f  %6.3f%%" % (speed, div, actual, rel_error*100) + +def main(): +    print "wb_clk = %f" % (wb_clk,) +    for s in speeds: +        doit(s) + +if __name__ == '__main__': +    main() +     diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc new file mode 100644 index 000000000..38c630df4 --- /dev/null +++ b/firmware/microblaze/lib/Makefile.inc @@ -0,0 +1,50 @@ +# +# Copyright 2010 Ettus Research LLC +# +# Copyright 2007 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +COMMON_SRCS = \ +	$(top_srcdir)/lib/u2_init.c \ +	$(top_srcdir)/lib/abort.c \ +	$(top_srcdir)/lib/ad9510.c \ +	$(top_srcdir)/lib/bsm12.c \ +	$(top_srcdir)/lib/buffer_pool.c \ +	$(top_srcdir)/lib/clocks.c \ +	$(top_srcdir)/lib/dbsm.c \ +	$(top_srcdir)/lib/eeprom.c \ +	$(top_srcdir)/lib/eth_addrs.c \ +	$(top_srcdir)/lib/eth_mac.c \ +	$(top_srcdir)/lib/_exit.c \ +	$(top_srcdir)/lib/exit.c \ +	$(top_srcdir)/lib/hal_io.c \ +	$(top_srcdir)/lib/hal_uart.c \ +	$(top_srcdir)/lib/i2c.c \ +	$(top_srcdir)/lib/i2c_async.c \ +	$(top_srcdir)/lib/mdelay.c \ +	$(top_srcdir)/lib/memcpy_wa.c \ +	$(top_srcdir)/lib/memset_wa.c \ +	$(top_srcdir)/lib/nonstdio.c \ +	$(top_srcdir)/lib/pic.c \ +	$(top_srcdir)/lib/print_mac_addr.c \ +	$(top_srcdir)/lib/print_rmon_regs.c \ +	$(top_srcdir)/lib/print_buffer.c \ +	$(top_srcdir)/lib/printf.c \ +	$(top_srcdir)/lib/ihex.c \ +	$(top_srcdir)/lib/spi.c \ +	$(top_srcdir)/lib/net_common.c \ +	$(top_srcdir)/lib/arp_cache.c \ +	$(top_srcdir)/lib/banal.c diff --git a/firmware/microblaze/lib/_exit.c b/firmware/microblaze/lib/_exit.c new file mode 100644 index 000000000..9b40ab2ee --- /dev/null +++ b/firmware/microblaze/lib/_exit.c @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Stub so we can compile using 3.4 based mb-gcc + */ +void  +_exit(int status) +{ +  while (1) +    ; +} diff --git a/firmware/microblaze/lib/abort.c b/firmware/microblaze/lib/abort.c new file mode 100644 index 000000000..d1d709392 --- /dev/null +++ b/firmware/microblaze/lib/abort.c @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <nonstdio.h> + +extern void _exit(int status); + +void  +abort(void) +{ +  putstr("\n\nabort\n"); +  // FIXME loop blinking leds +  _exit(-1); +} diff --git a/firmware/microblaze/lib/ad9510.c b/firmware/microblaze/lib/ad9510.c new file mode 100644 index 000000000..4d3acb65d --- /dev/null +++ b/firmware/microblaze/lib/ad9510.c @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ad9510.h" +#include "spi.h" +#include <memory_map.h> + +#define RD (1 << 15) +#define WR (0 << 15) + +void +ad9510_write_reg(int regno, uint8_t value) +{ +  uint32_t inst = WR | (regno & 0xff); +  uint32_t v = (inst << 8) | (value & 0xff); +  spi_transact(SPI_TXONLY, SPI_SS_AD9510, v, 24, SPIF_PUSH_FALL); +} + +int +ad9510_read_reg(int regno) +{ +  uint32_t inst = RD | (regno & 0xff); +  uint32_t v = (inst << 8) | 0; +  uint32_t r = spi_transact(SPI_TXRX, SPI_SS_AD9510, v, 24, +			    SPIF_PUSH_FALL | SPIF_LATCH_FALL); +  return r & 0xff; +} diff --git a/firmware/microblaze/lib/ad9510.h b/firmware/microblaze/lib/ad9510.h new file mode 100644 index 000000000..a395e5223 --- /dev/null +++ b/firmware/microblaze/lib/ad9510.h @@ -0,0 +1,30 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_AD9510_H +#define INCLUDED_AD9510_H + +#include <stdint.h> + +/* + * Analog Device AD9510 1.2 GHz Clock Distribution IC w/ PLL + */ + +void ad9510_write_reg(int regno, uint8_t value); +int  ad9510_read_reg(int regno); + +#endif /* INCLUDED_AD9510_H */ diff --git a/firmware/microblaze/lib/arp_cache.c b/firmware/microblaze/lib/arp_cache.c new file mode 100644 index 000000000..9c586fa6b --- /dev/null +++ b/firmware/microblaze/lib/arp_cache.c @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "arp_cache.h" +#include <stddef.h> + +typedef struct { +  struct ip_addr	ip; +  eth_mac_addr_t	mac; +} arp_cache_t; + +#define	NENTRIES 8	// power-of-2 + +static size_t nentries; +static size_t victim; +static arp_cache_t cache[NENTRIES]; + +void +arp_cache_init(void) +{ +  nentries = 0; +  victim = 0; +} + +// returns non-negative index if found, else -1 +static int +arp_cache_lookup(const struct ip_addr *ip) +{ +  int i; +  for (i = 0; i < nentries; i++) +    if (cache[i].ip.addr == ip->addr) +      return i; + +  return -1; +} + +static int +arp_cache_alloc(void) +{ +  if (nentries < NENTRIES) +    return nentries++; + +  int i = victim; +  victim = (victim + 1) % NENTRIES; +  return i; +} + +void  +arp_cache_update(const struct ip_addr *ip, +		 const eth_mac_addr_t *mac) +{ +  int i = arp_cache_lookup(ip); +  if (i < 0){ +    i = arp_cache_alloc(); +    cache[i].ip = *ip; +    cache[i].mac = *mac; +  } +  else { +    cache[i].mac = *mac; +  } +} + +bool +arp_cache_lookup_mac(const struct ip_addr *ip, +		     eth_mac_addr_t *mac) +{ +  int i = arp_cache_lookup(ip); +  if (i < 0) +    return false; + +  *mac = cache[i].mac; +  return true; +} diff --git a/firmware/microblaze/lib/arp_cache.h b/firmware/microblaze/lib/arp_cache.h new file mode 100644 index 000000000..8e84a1f94 --- /dev/null +++ b/firmware/microblaze/lib/arp_cache.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_ARP_CACHE_H +#define INCLUDED_ARP_CACHE_H + +#include <lwip/ip_addr.h> +#include <net/eth_mac_addr.h> +#include <stdbool.h> + +void arp_cache_init(void); + +void arp_cache_update(const struct ip_addr *ip, +		      const eth_mac_addr_t *mac); + +bool arp_cache_lookup_mac(const struct ip_addr *ip, +			  eth_mac_addr_t *mac); + +#endif /* INCLUDED_ARP_CACHE_H */ diff --git a/firmware/microblaze/lib/banal.c b/firmware/microblaze/lib/banal.c new file mode 100644 index 000000000..42937957f --- /dev/null +++ b/firmware/microblaze/lib/banal.c @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <banal.h> + +uint32_t +get_uint32(const unsigned char *s) +{ +  return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; +} + +uint64_t +get_uint64(const unsigned char *s) +{ +  return (((uint64_t)get_uint32(s)) << 32) | get_uint32(s+4); +} diff --git a/firmware/microblaze/lib/banal.h b/firmware/microblaze/lib/banal.h new file mode 100644 index 000000000..7b3c71a20 --- /dev/null +++ b/firmware/microblaze/lib/banal.h @@ -0,0 +1,90 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_BANAL_H +#define INCLUDED_BANAL_H + +#include <stdint.h> +#include <lwip/ip_addr.h> + +/* + * 1's complement sum for IP and UDP headers + * + * init chksum to zero to start. + */ +static inline unsigned int +CHKSUM(unsigned int x, unsigned int *chksum) +{ +  *chksum += x; +  *chksum = (*chksum & 0xffff) + (*chksum>>16); +  *chksum = (*chksum & 0xffff) + (*chksum>>16); +  return x; +} + +unsigned int  +chksum_buffer(unsigned short *buf, int nshorts, unsigned int initial_chksum); + +//-------------- unsigned get_int 8, 16, 32, 64 --------------// + +static inline uint8_t +get_uint8(const unsigned char *s) +{ +  return s[0]; +} + +static inline uint16_t +get_uint16(const unsigned char *s) +{ +  return (s[0] << 8) | s[1]; +} + +uint32_t +get_uint32(const unsigned char *s); + +uint64_t +get_uint64(const unsigned char *s); + +//--------------- signed get_int 8, 16, 32, 64 --------------// + +static inline int8_t +get_int8(const unsigned char *s) +{ +  return get_uint8(s); +} + +static inline int16_t +get_int16(const unsigned char *s) +{ +  return get_uint16(s); +} + +static inline int32_t +get_int32(const unsigned char *s) +{ +  return get_uint32(s); +} + +static inline int64_t +get_int64(const unsigned char *s) +{ +  return get_uint64(s); +} + +void +print_ip(struct ip_addr ip); + +#endif /* INCLUDED_BANAL_H */ diff --git a/firmware/microblaze/lib/bootconfig.c b/firmware/microblaze/lib/bootconfig.c new file mode 100644 index 000000000..93adc05c2 --- /dev/null +++ b/firmware/microblaze/lib/bootconfig.c @@ -0,0 +1,101 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "bootconfig.h" +#include "bootconfig_private.h" +#include <stdint.h> +#include <stddef.h> +#include <i2c.h> +#include <quadradio/i2c_addr.h> +#include <mdelay.h> +#include <xilinx_v5_icap.h> +#include <nonstdio.h> + +eeprom_boot_info_t eeprom_shadow; + +static eeprom_boot_info_t eeprom_default = { +  .magic = EEPROM_BOOT_INFO_MAGIC, +  .nattempts = 1, +  .next_boot.fpga_image_number = 0, +  .next_boot.firmware_image_number = 0, +  .default_boot.fpga_image_number = 0, +  .default_boot.firmware_image_number = 0 +}; + +eeprom_boot_info_t * +_bc_get_eeprom_shadow(void) +{ +  return &eeprom_shadow; +} + + +bool +_bc_write_eeprom_shadow(void) +{ +  return eeprom_write(I2C_ADDR_MBOARD, BOOT_INFO_OFFSET, &eeprom_shadow, sizeof(eeprom_shadow)); +} + +void +bootconfig_init(void) +{ +  if (!eeprom_read(I2C_ADDR_MBOARD, BOOT_INFO_OFFSET, &eeprom_shadow, sizeof(eeprom_shadow)) +      || eeprom_shadow.magic != EEPROM_BOOT_INFO_MAGIC){ +    eeprom_shadow = eeprom_default; +    _bc_write_eeprom_shadow(); +  } +} + +bootconfig_t  +bootconfig_get_default(void) +{ +  return eeprom_shadow.default_boot; +} + +bool +bootconfig_set_default(bootconfig_t bc) +{ +  if (!validate_bootconfig(bc)) +    return false; + +  eeprom_shadow.default_boot  = bc; +  eeprom_shadow.next_boot  = bc; +  return _bc_write_eeprom_shadow(); +} + +void +bootconfig_boot(bootconfig_t bc) +{ +  if (!validate_bootconfig(bc)) +    return; + +  eeprom_shadow.next_boot = bc; +  eeprom_shadow.nattempts = 1; +  _bc_write_eeprom_shadow(); + +  if (1){ +    puts("\nbootconfig: chaining to FPGA slot 0 bootloader"); +    mdelay(100); +  } + +  while (1){ +    // Reload fpga with code from SPI flash address 0x0. +    icap_reload_fpga(0x00000000); +  } +}   diff --git a/firmware/microblaze/lib/bsm12.c b/firmware/microblaze/lib/bsm12.c new file mode 100644 index 000000000..3f17fe42d --- /dev/null +++ b/firmware/microblaze/lib/bsm12.c @@ -0,0 +1,319 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * buffer state machine: 1 input to two outputs + * + * Typically used to read packets from the ethernet and then after inspecting, + * handle the packet in firmware or pass it on to 1 of the 2 buffer destinations. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "bsm12.h" +#include "memory_map.h" +#include "buffer_pool.h" +#include <stdbool.h> +#include "nonstdio.h" +#include <stdlib.h> + +typedef enum { +  BS_EMPTY, +  BS_FILLING, +  BS_FULL, +  BS_EMPTYING, +} buffer_state_t; + +static buffer_state_t buffer_state[NBUFFERS]; +static uint32_t last_send_ctrl[NBUFFERS]; +static int8_t  buffer_target[NBUFFERS];	    // -1, 0 or 1. +static uint8_t buffer_dst[NBUFFERS];	    // 0 or 1. Valid only when BF_EMPTYING + +#define ST_IDLE (-1) + +void +bsm12_init(bsm12_t *sm, int buf0, +	   const buf_cmd_args_t *recv, +	   const buf_cmd_args_t *send0, +	   const buf_cmd_args_t *send1, +	   bsm12_inspector_t inspect) +{ +  if (buf0 & 0x3)	// precondition: buf0 % 4 == 0 +    abort(); + +  sm->buf0 = buf0; +  sm->running = false; +  sm->recv_args = *recv; +  sm->send_args[0] = *send0; +  sm->send_args[1] = *send1; + +  sm->rx_state = ST_IDLE; +  sm->tx_state[0] = ST_IDLE; +  sm->tx_state[1] = ST_IDLE; + +  sm->inspect = inspect; + +  sm->bps_error = BPS_ERROR(buf0 + 0) | BPS_ERROR(buf0 + 1) | BPS_ERROR(buf0 + 2); +  sm->bps_done  = BPS_DONE(buf0 + 0)  | BPS_DONE(buf0 + 1)  | BPS_DONE(buf0 + 2); +  sm->bps_error_or_done = sm->bps_error | sm->bps_done; + +  // How much to adjust the last_line register. +  // It's 1 for everything but the ethernet. +  sm->last_line_adj = recv->port == PORT_ETH ? 3 : 1; + +  buffer_state[sm->buf0 + 0] = BS_EMPTY; +  buffer_state[sm->buf0 + 1] = BS_EMPTY; +  buffer_state[sm->buf0 + 2] = BS_EMPTY; + +  buffer_target[sm->buf0 + 0] = -1; +  buffer_target[sm->buf0 + 1] = -1; +  buffer_target[sm->buf0 + 2] = -1; + +  for (int i = 0; i < NBUFFERS; i++) +    sm->next_buf[i] = buf0; + +  sm->next_buf[buf0 + 0] = buf0 + 1; +  sm->next_buf[buf0 + 1] = buf0 + 2; +  sm->next_buf[buf0 + 2] = buf0 + 0; + +  for (int i = 0; i < 3; i++){ +    sm->precomputed_receive_to_buf_ctrl_word[i] = +      (BPC_READ +       | BPC_BUFFER(sm->buf0 + i) +       | BPC_PORT(sm->recv_args.port) +       | BPC_STEP(1) +       | BPC_FIRST_LINE(sm->recv_args.first_line) +       | BPC_LAST_LINE(sm->recv_args.last_line)); +     +    for (int j = 0; j < 2; j++){ +      sm->precomputed_send_from_buf_ctrl_word[i][j] = +	(BPC_WRITE +	 | BPC_BUFFER(sm->buf0 + i) +	 | BPC_PORT(sm->send_args[j].port) +	 | BPC_STEP(1) +	 | BPC_FIRST_LINE(sm->send_args[j].first_line) +	 | BPC_LAST_LINE(0));		// last line filled in at runtime +    } +  } +} + +static inline void +bsm12_receive_to_buf(bsm12_t *sm, int bufno) +{ +  buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 0x3]; +} + +static inline void +bsm12_send_from_buf(bsm12_t *sm, int bufno, int dst_idx) +{ +  dst_idx &= 0x1; + +  uint32_t t =  +    (sm->precomputed_send_from_buf_ctrl_word[bufno & 0x3][dst_idx] +     | BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj)); + +  buffer_pool_ctrl->ctrl = t; +  last_send_ctrl[bufno] = t; +  buffer_dst[bufno] = dst_idx; +} + +static inline void +bsm12_resend_from_buf(bsm12_t *sm, int bufno) +{ +  buffer_pool_ctrl->ctrl = last_send_ctrl[bufno]; +} + +void +bsm12_start(bsm12_t *sm) +{ +  sm->running = true; + +  buffer_state[sm->buf0 + 0] = BS_EMPTY; +  buffer_state[sm->buf0 + 1] = BS_EMPTY; +  buffer_state[sm->buf0 + 2] = BS_EMPTY; + +  buffer_target[sm->buf0 + 0] = -1; +  buffer_target[sm->buf0 + 1] = -1; +  buffer_target[sm->buf0 + 2] = -1; + +  bp_clear_buf(sm->buf0 + 0); +  bp_clear_buf(sm->buf0 + 1); +  bp_clear_buf(sm->buf0 + 2); + +  sm->rx_state = 0; +  sm->tx_state[0] = ST_IDLE; +  sm->tx_state[1] = ST_IDLE; +  bsm12_receive_to_buf(sm, sm->buf0); +  buffer_state[sm->buf0] = BS_FILLING; +} + +void +bsm12_stop(bsm12_t *sm) +{ +  sm->running = false; +  bp_clear_buf(sm->buf0 + 0); +  bp_clear_buf(sm->buf0 + 1); +  bp_clear_buf(sm->buf0 + 2); +  buffer_state[sm->buf0 + 0] = BS_EMPTY; +  buffer_state[sm->buf0 + 1] = BS_EMPTY; +  buffer_state[sm->buf0 + 2] = BS_EMPTY; +} + +static void bsm12_process_helper(bsm12_t *sm, int buf_this); +static void bsm12_error_helper(bsm12_t *sm, int buf_this); + +void +bsm12_process_status(bsm12_t *sm, uint32_t status) +{ +  // anything for us? +  if ((status & sm->bps_error_or_done) == 0 || !sm->running) +    return; + +  if (status & sm->bps_error){ +    // Most likely an ethernet Rx error.  We just restart the transfer. +    if (status & (BPS_ERROR(sm->buf0 + 0))) +      bsm12_error_helper(sm, sm->buf0 + 0); + +    if (status & (BPS_ERROR(sm->buf0 + 1))) +      bsm12_error_helper(sm, sm->buf0 + 1); + +    if (status & (BPS_ERROR(sm->buf0 + 2))) +      bsm12_error_helper(sm, sm->buf0 + 2); +  } + +  if (status & BPS_DONE(sm->buf0 + 0)) +    bsm12_process_helper(sm, sm->buf0 + 0); + +  if (status & BPS_DONE(sm->buf0 + 1)) +    bsm12_process_helper(sm, sm->buf0 + 1); + +  if (status & BPS_DONE(sm->buf0 + 2)) +    bsm12_process_helper(sm, sm->buf0 + 2); +} + +static void  +bsm12_process_helper(bsm12_t *sm, int buf_this) +{ +  bp_clear_buf(buf_this); + +  if (buffer_state[buf_this] == BS_FILLING){ + +    buffer_state[buf_this] = BS_FULL; +    buffer_target[buf_this] = -1; + +    // +    // where does this packet go? +    // +    int dst = sm->inspect(sm, buf_this); +    if (dst == -1){ +      // +      // f/w handled the packet; refill the buffer +      // +      bsm12_receive_to_buf(sm, buf_this); +      buffer_state[buf_this] = BS_FILLING; +      buffer_target[buf_this] = -1; +      sm->rx_state = buf_this & 0x3; +    } +    else {	// goes to dst 0 or 1 +      // +      // If the next buffer is empty, start a receive on it +      // +      int t = sm->next_buf[buf_this]; +      if (buffer_state[t] == BS_EMPTY){ +	bsm12_receive_to_buf(sm, t); +	buffer_state[t] = BS_FILLING; +	buffer_target[t] = -1; +	sm->rx_state = t & 0x3; +      } +      else +	sm->rx_state = ST_IDLE; + +      // +      // If the destination is idle, start the xfer, othewise remember it +      // +      if (sm->tx_state[dst] == ST_IDLE){ +	bsm12_send_from_buf(sm, buf_this, dst); +	sm->tx_state[dst] = buf_this & 0x3; +	buffer_state[buf_this] = BS_EMPTYING; +	buffer_target[buf_this] = -1; +      } +      else { +	buffer_target[buf_this] = dst; +      } +    } +  } + +  else {    // BS_EMPTYING + +    buffer_state[buf_this] = BS_EMPTY; +    buffer_target[buf_this] = -1; + +    if (sm->rx_state == ST_IDLE){	// fire off another receive +      sm->rx_state = buf_this & 0x3; +      bsm12_receive_to_buf(sm, buf_this); +      buffer_state[buf_this] = BS_FILLING; +      buffer_target[buf_this] = -1; +    } + +    int dst = buffer_dst[buf_this];	// the dst we were emptying into +    // is the next buffer full and for us? +    int t = sm->next_buf[buf_this]; +    if (buffer_target[t] == dst){		// yes, +      bsm12_send_from_buf(sm, t, dst);		// send it +      buffer_state[t] = BS_EMPTYING; +      buffer_target[t] = -1; +      sm->tx_state[dst] = t & 0x3; +    } +    // how about the one after that? +    else if (buffer_target[t=sm->next_buf[t]] == dst){	// yes, +      bsm12_send_from_buf(sm, t, dst);			// send it +      buffer_state[t] = BS_EMPTYING; +      buffer_target[t] = -1; +      sm->tx_state[dst] = t & 0x3; +    } +    else { +      sm->tx_state[dst] = ST_IDLE; +    } +  } +} + +static void +bsm12_error_helper(bsm12_t *sm, int buf_this) +{ +  bp_clear_buf(buf_this);		  // clears ERROR flag + +  if (buffer_state[buf_this] == BS_FILLING){ +    bsm12_receive_to_buf(sm, buf_this);	  // restart the xfer +  } +  else { // buffer was emptying +    bsm12_resend_from_buf(sm, buf_this);  // restart the xfer +  } +} + + +void +bsm12_handle_tx_underrun(bsm12_t *sm) +{ +} + +void +bsm12_handle_rx_overrun(bsm12_t *sm) +{ +} diff --git a/firmware/microblaze/lib/bsm12.h b/firmware/microblaze/lib/bsm12.h new file mode 100644 index 000000000..b8e576b79 --- /dev/null +++ b/firmware/microblaze/lib/bsm12.h @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_BSM12_H +#define INCLUDED_BSM12_H + +#include "dbsm.h" +#include "memory_map.h" + +/*! + * buffer state machine: 1 input to two outputs + * + * Typically used to read packets from the ethernet and then after inspecting, + * handle the packet in firmware or pass it on to 1 of the 2 buffer destinations. + */ + +struct _bsm12; +typedef struct _bsm12 bsm12_t; + +/*! + * Pointer to function that does packet inspection. + * + * \param sm		the state machine + * \param buf_this	the index of the buffer to inspect and/or pass on + * + * Returns -1, 0 or 1.  If it returns -1, it means that the s/w + * handled that packet, and that it should NOT be passed on to one of + * the buffer endpoints.  0 indicates the first endpoint, 1 the second endpoint. + */ +typedef int (*bsm12_inspector_t)(bsm12_t *sm, int buf_this); + + +/*! + * buffer state machine: 1 input to two outputs + */ +struct _bsm12 +{ +  uint8_t	  buf0;	 // This machine uses buf0, buf0+1 and buf0+2.  buf0 % 4 == 0. +  uint8_t	  running; +  int8_t	  rx_state;	// -1, 0, 1, 2  which buffer we're receiving into +  int8_t	  tx_state[2];	// -1, 0, 1, 2  which buffer we're sending from +  buf_cmd_args_t  recv_args; +  buf_cmd_args_t  send_args[2]; +  bsm12_inspector_t inspect; +  int		  last_line_adj; +  uint32_t	  bps_error; +  uint32_t	  bps_done; +  uint32_t	  bps_error_or_done; +  uint8_t	  next_buf[NBUFFERS]; +  uint32_t	  precomputed_receive_to_buf_ctrl_word[3]; +  uint32_t	  precomputed_send_from_buf_ctrl_word[4][2];  // really only 3, not 4  +                                                              //   (easier addr comp) +}; + +void bsm12_init(bsm12_t *sm, int buf0, +		const buf_cmd_args_t *recv, +		const buf_cmd_args_t *send0, +		const buf_cmd_args_t *send1, +		bsm12_inspector_t inspect); + +void bsm12_start(bsm12_t *sm); +void bsm12_stop(bsm12_t *sm); +void bsm12_process_status(bsm12_t *sm, uint32_t status); +void bsm12_handle_tx_underrun(bsm12_t *sm); +void bsm12_handle_rx_overrun(bsm12_t *sm); + + +#endif /* INCLUDED_BSM12_H */ diff --git a/firmware/microblaze/lib/buffer_pool.c b/firmware/microblaze/lib/buffer_pool.c new file mode 100644 index 000000000..77e7c5213 --- /dev/null +++ b/firmware/microblaze/lib/buffer_pool.c @@ -0,0 +1,72 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "memory_map.h" +#include "buffer_pool.h" +#include "hal_io.h"  + +void +bp_init(void) +{ +  int i; +  bp_disable_port(PORT_SERDES); +  bp_disable_port(PORT_DSP); +  bp_disable_port(PORT_ETH); +  bp_disable_port(PORT_RAM); + +  for (i = 0; i < NBUFFERS; i++) +    bp_clear_buf(i); +} + +#ifndef INLINE_BUFFER_POOL + +void +bp_clear_buf(int bufnum) +{ +  buffer_pool_ctrl->ctrl = BPC_BUFFER(bufnum) | BPC_PORT_NIL | BPC_CLR; +} + +void +bp_disable_port(int portnum)  +{ +  // disable buffer connections to this port +  buffer_pool_ctrl->ctrl = BPC_BUFFER_NIL | BPC_PORT(portnum); +} + +void +bp_receive_to_buf(int bufnum, int port, int step, int fl, int ll) +{ +  buffer_pool_ctrl->ctrl = (BPC_READ +			    | BPC_BUFFER(bufnum) +			    | BPC_PORT(port) +			    | BPC_STEP(step) +			    | BPC_FIRST_LINE(fl) +			    | BPC_LAST_LINE(ll)); +} + +void +bp_send_from_buf(int bufnum, int port, int step, int fl, int ll) +{ +  buffer_pool_ctrl->ctrl = (BPC_WRITE +			    | BPC_BUFFER(bufnum) +			    | BPC_PORT(port) +			    | BPC_STEP(step) +			    | BPC_FIRST_LINE(fl) +			    | BPC_LAST_LINE(ll)); +} + +#endif diff --git a/firmware/microblaze/lib/buffer_pool.h b/firmware/microblaze/lib/buffer_pool.h new file mode 100644 index 000000000..145b20f8d --- /dev/null +++ b/firmware/microblaze/lib/buffer_pool.h @@ -0,0 +1,75 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_BUFFER_POOL_H +#define INCLUDED_BUFFER_POOL_H + +#include "memory_map.h" + +// Buffer Pool Management + + +// define to have common buffer operations inlined +#define INLINE_BUFFER_POOL 1 + +void bp_init(void); + +#ifndef INLINE_BUFFER_POOL + +void bp_clear_buf(int bufnum); +void bp_disable_port(int portnum); +void bp_receive_to_buf(int bufnum, int port, int step, int fl, int ll); +void bp_send_from_buf(int bufnum, int port, int step, int fl, int ll); + +#else + +static inline void +bp_clear_buf(int bufnum) +{ +  buffer_pool_ctrl->ctrl = BPC_BUFFER(bufnum) | BPC_PORT_NIL | BPC_CLR; +} + +static inline void +bp_disable_port(int portnum)  +{ +  // disable buffer connections to this port +  buffer_pool_ctrl->ctrl = BPC_BUFFER_NIL | BPC_PORT(portnum); +} + +static inline void +bp_receive_to_buf(int bufnum, int port, int step, int fl, int ll) +{ +  buffer_pool_ctrl->ctrl = (BPC_READ +			    | BPC_BUFFER(bufnum) +			    | BPC_PORT(port) +			    | BPC_STEP(step) +			    | BPC_FIRST_LINE(fl) +			    | BPC_LAST_LINE(ll)); +} + +static inline void +bp_send_from_buf(int bufnum, int port, int step, int fl, int ll) +{ +  buffer_pool_ctrl->ctrl = (BPC_WRITE +			    | BPC_BUFFER(bufnum) +			    | BPC_PORT(port) +			    | BPC_STEP(step) +			    | BPC_FIRST_LINE(fl) +			    | BPC_LAST_LINE(ll)); +} +#endif +#endif diff --git a/firmware/microblaze/lib/clock_bits.h b/firmware/microblaze/lib/clock_bits.h new file mode 100644 index 000000000..d2052e941 --- /dev/null +++ b/firmware/microblaze/lib/clock_bits.h @@ -0,0 +1,55 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2008 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef INCLUDED_USRP2_CLOCK_BITS_H +#define INCLUDED_USRP2_CLOCK_BITS_H + +#define	_MC_WE_LOCK			0x0001 +#define	_MC_MIMO_CLK_INPUT		0x0002		// else SMA input + +/* + * Derived masks (use these): + * + * We get our input from 1 of three places: + *  Our free running oscilator, our SMA connector, or from the MIMO connector + */ +#define	MC_WE_DONT_LOCK			0x0000 +#define	MC_WE_LOCK_TO_SMA		(_MC_WE_LOCK | 0) +#define	MC_WE_LOCK_TO_MIMO		(_MC_WE_LOCK | _MC_MIMO_CLK_INPUT) + +/* + * Independent of the source of the clock, we may or may not drive our + * clock onto the mimo connector.  Note that there are dedicated clock + * signals in each direction, so disaster doesn't occurs if we're + * unnecessarily providing clock. + */ +#define	MC_PROVIDE_CLK_TO_MIMO		0x0004 + +#define MC_REF_CLK_MASK          0x0f + +#define MC_PPS_SOURCE_SMA        (0x00 << 4) +#define MC_PPS_SOURCE_MIMO       (0x01 << 4) + +#define MC_PPS_POLARITY_NEG      (0x00 << 5) +#define MC_PPS_POLARITY_POS      (0x01 << 5) + +#endif /* INCLUDED_USRP2_CLOCK_BITS_H */ diff --git a/firmware/microblaze/lib/clocks.c b/firmware/microblaze/lib/clocks.c new file mode 100644 index 000000000..2b352a385 --- /dev/null +++ b/firmware/microblaze/lib/clocks.c @@ -0,0 +1,266 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <clocks.h> + +#include "memory_map.h" +#include "ad9510.h" +#include "spi.h" +#include "u2_init.h" + +//USRP2PLUS clocks: +//Clock 0: testclk +//Clock 1: FPGA clk +//Clock 2: ADC clk +//Clock 3: DAC clk +//Clock 4: SER clk +//Clock 5: TX dboard clk +//Clock 6: EXP clk +//Clock 7: RX dboard clk + +//TODO: should have enough brains to init the FPGA clock for USRP2+. all others are suspect. +//note that without EEPROM support u2_hw_rev_major is going to be incorrect. + +void  +clocks_init(void) +{ +  // Set up basic clocking functions in AD9510 +  ad9510_write_reg(0x45, 0x01); // CLK2 drives distribution + +  //enable the 100MHz clock output to the FPGA for 50MHz CPU clock +  clocks_enable_fpga_clk(true, 1); + +  spi_wait(); + +  // Set up PLL for 10 MHz reference +  // Reg 4, A counter, Don't Care +//  ad9510_write_reg(0x05, 0x00);  // Reg 5, B counter MSBs, 0 +//  ad9510_write_reg(0x06, 0x05);  // Reg 6, B counter LSBs, 5 +  // Reg 7, Loss of reference detect, doesn't work yet, 0 +//  ad9510_write_reg(0x5A, 0x01); // Update Regs + +  // Primary clock configuration +//  clocks_mimo_config(MC_WE_DONT_LOCK); + + +  //wait for the clock to stabilize +  while(!clocks_lock_detect()); + +  //issue a reset to the DCM so it locks up to the new freq +  output_regs->clk_ctrl |= CLK_RESET; + +  // Set up other clocks +  //clocks_enable_test_clk(false, 0); +  //clocks_enable_tx_dboard(false, 0); +  //clocks_enable_rx_dboard(false, 0); +//  clocks_enable_eth_phyclk(false, 0); //PHY clk is separate now (u2r4, u2p) + +  // Enable clock to ADCs and DACs +  //clocks_enable_dac_clk(true, 1); +  //clocks_enable_adc_clk(true, 1); +} + +/* +void +clocks_mimo_config(int flags) +{ +  if (flags & _MC_WE_LOCK){ +    // Reg 8, Charge pump on, dig lock det, positive PFD, 47 +    ad9510_write_reg(0x08, 0x47); +  } +  else { +    // Reg 8, Charge pump off, dig lock det, positive PFD +    ad9510_write_reg(0x08, 0x00); +  } +   +  // Reg 9, Charge pump current, 0x40=3mA, 0x00=650uA +  ad9510_write_reg(0x09, 0x00); +  // Reg A, Prescaler of 2, everything normal 04 +  ad9510_write_reg(0x0A, 0x04); +  // Reg B, R Div MSBs, 0 +  ad9510_write_reg(0x0B, 0x00); +  // Reg C, R Div LSBs, 1 +  ad9510_write_reg(0x0C, 0x01); +  // Reg D, Antibacklash, Digital lock det, 0 + +  ad9510_write_reg(0x5A, 0x01); // Update Regs + +  spi_wait(); +   +  // Allow for clock switchover +  // The below masks include 0x10, which issues a reset to the DCM.   +  if (flags & _MC_WE_LOCK){		// WE LOCK +    if (flags & _MC_MIMO_CLK_INPUT) { +      // Turn on ref output and choose the MIMO connector +      output_regs->clk_ctrl = 0x15;   +    } +    else { +      // turn on ref output and choose the SMA +      output_regs->clk_ctrl = 0x1C;  +    } +  } +  else {				// WE DONT LOCK +    // Disable both ext clk inputs +    output_regs->clk_ctrl = 0x10; +  } + +  // Do we drive a clock onto the MIMO connector? +//  if (flags & MC_PROVIDE_CLK_TO_MIMO) +//    clocks_enable_clkexp_out(true,10); +//  else +//    clocks_enable_clkexp_out(false,0);  +} +*/ + +bool  +clocks_lock_detect() +{ +    return (pic_regs->pending & PIC_CLKSTATUS); +} + +int inline +clocks_gen_div(int divisor) +{ +  int L,H; +  L = (divisor>>1)-1; +  H = divisor-L-2; +  return (L<<4)|H; +} + +#define CLOCK_OUT_EN 0x08 +#define CLOCK_OUT_DIS_CMOS 0x01 +#define CLOCK_OUT_DIS_PECL 0x02 +#define CLOCK_DIV_DIS 0x80 +#define CLOCK_DIV_EN 0x00 + +#define CLOCK_MODE_PECL 1 +#define CLOCK_MODE_LVDS 2 +#define CLOCK_MODE_CMOS 3 + +//CHANGED: set to PECL for default behavior +void  +clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode) +{ +  int enable_word, div_word, div_en_word; + +  switch(mode) { +  case CLOCK_MODE_LVDS : +    enable_word = enable ? 0x02 : 0x03; +    break; +  case CLOCK_MODE_CMOS : +    enable_word = enable ? 0x08 : 0x09; +    break; +  case CLOCK_MODE_PECL : +	default: +    enable_word = enable ? 0x08 : 0x0A; +    break; +  } +  if(enable && (divisor>1)) { +    div_word = clocks_gen_div(divisor); +    div_en_word = CLOCK_DIV_EN; +  } +  else { +    div_word = 0; +    div_en_word = CLOCK_DIV_DIS; +  } + +  ad9510_write_reg(reg_en,enable_word); // Output en/dis +  ad9510_write_reg(reg_div,div_word); // Set divisor +  ad9510_write_reg(reg_div+1,div_en_word); // Enable or Bypass Divider +  ad9510_write_reg(0x5A, 0x01);  // Update Regs +} + +// Clock 0 +/*void +clocks_enable_test_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL); +}*/ + +// Clock 1 +void +clocks_enable_fpga_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL); +} +/* +// Clock 2 on Rev 3, Clock 5 on Rev 4, Clock 6 on USRP2+ +void +clocks_enable_clkexp_out(bool enable, int divisor) +{ +  if(u2_hw_rev_major == 3) +    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); +  else if(u2_hw_rev_major == 4) { +    ad9510_write_reg(0x34,0x00);  // Turn on fine delay +    ad9510_write_reg(0x35,0x00);  // Set Full Scale to nearly 10ns +    ad9510_write_reg(0x36,0x1c);  // Set fine delay.  0x20 is midscale +    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); +  } +	else if(u2_hw_rev_major == 10) { +		ad9510_write_reg(0x34, 0x00); +		ad9510_write_reg(0x35, 0x00); +		ad9510_write_reg(0x36, 0x1C); +		clocks_enable_XXX_clk(enable, divisor, 0x42, 0x52, CLOCK_MODE_LVDS); +	} +  else +    putstr("ERR (clocks_enable_clkexp_out): Invalid hw rev, don't know what to do!\n"); +} +*/ +/* +// Clock 5 on Rev 3, none (was 2) on Rev 4, none on USRP2+ +void +clocks_enable_eth_phyclk(bool enable, int divisor) +{ +  if(u2_hw_rev_major == 3) +    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS); +  else if(u2_hw_rev_major == 4) +    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL); +  else +    putstr("(clocks_enable_eth_phyclk): no eth PHY clock or invalid hw rev\n"); //not really an error +} +*/ +// Clock 3 +/*void +clocks_enable_dac_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL); +}*/ + +// Clock 4 +/*void +clocks_enable_adc_clk(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS); +}*/ + +// Clock 6 +/*void +clocks_enable_tx_dboard(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS); +}*/ + +// Clock 7 +/*void +clocks_enable_rx_dboard(bool enable, int divisor) +{ +  clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS); +}*/ diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h new file mode 100644 index 000000000..28d1d542f --- /dev/null +++ b/firmware/microblaze/lib/clocks.h @@ -0,0 +1,95 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_CLOCKS_H +#define INCLUDED_CLOCKS_H + +/* + * Routines to configure our multitude of clocks + */ + +#include <stdbool.h> +#include "clock_bits.h" + + +/*! + * One time call to initialize all clocks to a reasonable state.  We + * come out of here using our free running 100MHz oscilator and not + * providing a clock to the MIMO connector (CMC_WE_DONT_LOCK) + */ +void clocks_init(void); + + +/*! + * \brief MIMO clock configuration. + * + * Configure our master clock source, and whether or not we drive a + * clock onto the mimo connector.  See MC_flags in usrp2_mimo_config.h. + */ +//void clocks_mimo_config(int flags); + +/*! + * \brief Lock Detect -- Return True if our PLL is locked + */ +bool clocks_lock_detect(); + +/*! + * \brief Enable or disable test clock (extra clock signal) + */ +//void clocks_enable_test_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable fpga clock.  Disabling would wedge and require a power cycle. + */ +void clocks_enable_fpga_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock output sent to MIMO connector + */ +//void clocks_enable_clkexp_out(bool enable, int divisor); + +/*! + * \brief Enable or disable ethernet phyclk, should always be disabled + */ +//void clocks_enable_eth_phyclk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock to DAC + */ +//void clocks_enable_dac_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock to ADC + */ +//void clocks_enable_adc_clk(bool enable, int divisor); + +/*! + * \brief Enable or disable clock to Rx daughterboard + */ +//void clocks_enable_rx_dboard(bool enable, int divisor); + + +/*! + * \brief Enable or disable clock to Tx daughterboard + */ +//void clocks_enable_tx_dboard(bool enable, int divisor); + + +#endif /* INCLUDED_CLOCKS_H */ diff --git a/firmware/microblaze/lib/compiler.h b/firmware/microblaze/lib/compiler.h new file mode 100644 index 000000000..4fa9b49f8 --- /dev/null +++ b/firmware/microblaze/lib/compiler.h @@ -0,0 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_COMPILER_H +#define INCLUDED_COMPILER_H + +// FIXME gcc specific. +#define _AL4   __attribute__((aligned (4))) + + +#endif /* INCLUDED_COMPILER_H */ diff --git a/firmware/microblaze/lib/dbsm.c b/firmware/microblaze/lib/dbsm.c new file mode 100644 index 000000000..cee343eaa --- /dev/null +++ b/firmware/microblaze/lib/dbsm.c @@ -0,0 +1,299 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Double Buffering State Machine + */ + +#include "dbsm.h" +#include "memory_map.h" +#include "buffer_pool.h" +#include <stdbool.h> +#include "nonstdio.h" +#include <stdlib.h> + +typedef enum { +  BS_EMPTY, +  BS_FILLING, +  BS_FULL, +  BS_EMPTYING, +} buffer_state_t; + +static buffer_state_t buffer_state[NBUFFERS]; + +bool +dbsm_nop_inspector(dbsm_t *sm, int buf_this) +{ +  return false; +} + +void +dbsm_init(dbsm_t *sm, int buf0, +	  const buf_cmd_args_t *recv, const buf_cmd_args_t *send, +	  inspector_t inspect) +{ +  if (buf0 & 0x1)	// must be even +    abort(); + +  sm->buf0 = buf0; +  sm->running = false; +  sm->recv_args = *recv; +  sm->send_args = *send; + +  sm->rx_idle = true; +  sm->tx_idle = true; + +  sm->inspect = inspect; + +  // How much to adjust the last_line register. +  // It's 1 for everything but the ethernet. +  //sm->last_line_adj = recv->port == PORT_ETH ? 3 : 1; +  sm->last_line_adj = 1; + +  buffer_state[sm->buf0] = BS_EMPTY; +  buffer_state[sm->buf0 ^ 1] = BS_EMPTY; + +  sm->precomputed_receive_to_buf_ctrl_word[0] = +    (BPC_READ +     | BPC_BUFFER(sm->buf0) +     | BPC_PORT(sm->recv_args.port) +     | BPC_STEP(1) +     | BPC_FIRST_LINE(sm->recv_args.first_line) +     | BPC_LAST_LINE(sm->recv_args.last_line)); +     +  sm->precomputed_receive_to_buf_ctrl_word[1] = +    (BPC_READ +     | BPC_BUFFER(sm->buf0 ^ 1) +     | BPC_PORT(sm->recv_args.port) +     | BPC_STEP(1) +     | BPC_FIRST_LINE(sm->recv_args.first_line) +     | BPC_LAST_LINE(sm->recv_args.last_line)); +     +  sm->precomputed_send_from_buf_ctrl_word[0] = +    (BPC_WRITE +     | BPC_BUFFER(sm->buf0) +     | BPC_PORT(sm->send_args.port) +     | BPC_STEP(1) +     | BPC_FIRST_LINE(sm->send_args.first_line) +     | BPC_LAST_LINE(0));		// last line filled in at runtime +     +  sm->precomputed_send_from_buf_ctrl_word[1] = +    (BPC_WRITE +     | BPC_BUFFER(sm->buf0 ^ 1) +     | BPC_PORT(sm->send_args.port) +     | BPC_STEP(1) +     | BPC_FIRST_LINE(sm->send_args.first_line) +     | BPC_LAST_LINE(0));		// last line filled in at runtime +     +} + +static inline void +dbsm_receive_to_buf(dbsm_t *sm, int bufno) +{ +  buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 1]; +} + +static inline void +dbsm_send_from_buf(dbsm_t *sm, int bufno) +{ +  buffer_pool_ctrl->ctrl = +    (sm->precomputed_send_from_buf_ctrl_word[bufno & 1] +     | BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj)); +} + +void +dbsm_start(dbsm_t *sm) +{ +  // printf("dbsm_start: buf0 = %d, recv_port = %d\n", sm->buf0, sm->recv_args.port); + +  sm->running = true; + +  buffer_state[sm->buf0] = BS_EMPTY; +  buffer_state[sm->buf0 ^ 1] = BS_EMPTY; + +  bp_clear_buf(sm->buf0); +  bp_clear_buf(sm->buf0 ^ 1); + +  sm->tx_idle = true; +  sm->rx_idle = false; +  dbsm_receive_to_buf(sm, sm->buf0); +  buffer_state[sm->buf0] = BS_FILLING; + +} + + +void +dbsm_stop(dbsm_t *sm) +{ +  sm->running = false; +  bp_clear_buf(sm->buf0); +  bp_clear_buf(sm->buf0 ^ 1); +  buffer_state[sm->buf0] = BS_EMPTY; +  buffer_state[sm->buf0 ^ 1] = BS_EMPTY; +} + +static void dbsm_process_helper(dbsm_t *sm, int buf_this); +static void dbsm_error_helper(dbsm_t *sm, int buf_this); + +void +dbsm_process_status(dbsm_t *sm, uint32_t status) +{ +  if (!sm->running) +    return; + +  if (status & (BPS_ERROR(sm->buf0) | BPS_ERROR(sm->buf0 ^ 1))){ +    putchar('E'); +    // Most likely an ethernet Rx error.  We just restart the transfer. +    if (status & (BPS_ERROR(sm->buf0))) +      dbsm_error_helper(sm, sm->buf0); +      //dbsm_process_helper(sm, sm->buf0); //forward errors + +    if (status & (BPS_ERROR(sm->buf0 ^ 1))) +      dbsm_error_helper(sm, sm->buf0 ^ 1); +      //dbsm_process_helper(sm, sm->buf0 ^ 1); //forward errors +  } + +  if (status & BPS_DONE(sm->buf0)) +    dbsm_process_helper(sm, sm->buf0); + +  if (status & BPS_DONE(sm->buf0 ^ 1)) +    dbsm_process_helper(sm, sm->buf0 ^ 1); +} + +static void +dbsm_process_helper(dbsm_t *sm, int buf_this) +{ +  int buf_other = buf_this ^ 1; + +  bp_clear_buf(buf_this); + +  if (buffer_state[buf_this] == BS_FILLING){ +    buffer_state[buf_this] = BS_FULL; +    // +    // does s/w handle this packet? +    // +    if (sm->inspect(sm, buf_this)){ +      // s/w handled the packet; refill the buffer +      dbsm_receive_to_buf(sm, buf_this); +      buffer_state[buf_this] = BS_FILLING; +    } + +    else {	// s/w didn't handle this; pass it on + +      if(buffer_state[buf_other] == BS_EMPTY){ +	dbsm_receive_to_buf(sm, buf_other); +	buffer_state[buf_other] = BS_FILLING; +      } +      else +	sm->rx_idle = true; + +      if (sm->tx_idle){ +	sm->tx_idle = false; +	dbsm_send_from_buf(sm, buf_this); +	buffer_state[buf_this] = BS_EMPTYING; +      } +    } +  } +  else {  // buffer was emptying +    buffer_state[buf_this] = BS_EMPTY; +    if (sm->rx_idle){ +      sm->rx_idle = false; +      dbsm_receive_to_buf(sm, buf_this); +      buffer_state[buf_this] = BS_FILLING; +    } +    if (buffer_state[buf_other] == BS_FULL){ +      dbsm_send_from_buf(sm, buf_other); +      buffer_state[buf_other] = BS_EMPTYING; +    } +    else +      sm->tx_idle = true; +  } +} + +static void +dbsm_error_helper(dbsm_t *sm, int buf_this) +{ +  bp_clear_buf(buf_this);		// clears ERROR flag + +  if (buffer_state[buf_this] == BS_FILLING){ +    dbsm_receive_to_buf(sm, buf_this);	  // restart the xfer +  } +  else { // buffer was emptying +    dbsm_send_from_buf(sm, buf_this);	  // restart the xfer +  } +} + +/* + * Handle DSP Tx underrun + */ +void +dbsm_handle_tx_underrun(dbsm_t *sm) +{ +  // clear the DSP Tx state machine +  sr_tx_ctrl->clear_state = 1; + +  // If there's a buffer that's empyting, clear it & flush xfer + +  if (buffer_state[sm->buf0] == BS_EMPTYING){ +    bp_clear_buf(sm->buf0); +    sr_tx_ctrl->clear_state = 1;	// flush partial packet +    // drop frame in progress on ground.  Pretend it finished +    dbsm_process_helper(sm, sm->buf0); +  } +  else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){ +    bp_clear_buf(sm->buf0 ^ 1); +    sr_tx_ctrl->clear_state = 1;	// flush partial packet +    // drop frame in progress on ground.  Pretend it finished +    dbsm_process_helper(sm, sm->buf0 ^ 1); +  } +} + +/* + * Handle DSP Rx overrun + */ +void +dbsm_handle_rx_overrun(dbsm_t *sm) +{ +  sr_rx_ctrl->clear_overrun = 1; + +  // If there's a buffer that's filling, clear it. +  // Any restart will be the job of the caller. +   +  if (buffer_state[sm->buf0] == BS_FILLING) +    bp_clear_buf(sm->buf0); + +  if (buffer_state[sm->buf0 ^1] == BS_FILLING) +    bp_clear_buf(sm->buf0 ^ 1); +} + +void  +dbsm_wait_for_opening(dbsm_t *sm) +{ +  if (buffer_state[sm->buf0] == BS_EMPTYING){ +    // wait for xfer to complete +    int mask = BPS_DONE(sm->buf0) | BPS_ERROR(sm->buf0) | BPS_IDLE(sm->buf0); +    while ((buffer_pool_status->status & mask) == 0) +      ; +  } +  else if (buffer_state[sm->buf0 ^ 1] == BS_EMPTYING){ +    // wait for xfer to complete +    int mask = BPS_DONE(sm->buf0 ^ 1) | BPS_ERROR(sm->buf0 ^ 1) | BPS_IDLE(sm->buf0 ^ 1); +    while ((buffer_pool_status->status & mask) == 0) +      ; +  } +} diff --git a/firmware/microblaze/lib/dbsm.h b/firmware/microblaze/lib/dbsm.h new file mode 100644 index 000000000..cb7e12fc3 --- /dev/null +++ b/firmware/microblaze/lib/dbsm.h @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_DBSM_H +#define INCLUDED_DBSM_H + +/* + * Double Buffering State Machine + */ + +#include <stdint.h> +#include <stdbool.h> + +struct _dbsm; +typedef struct _dbsm dbsm_t; + +/* + * pointer to function that does packet inspection. + * + * If one of these returns true, it means that the s/w + * handled that packet, and that it should NOT be passed + * on to the normal destination port. + */ +typedef bool (*inspector_t)(dbsm_t *sm, int buf_this); + +bool dbsm_nop_inspector(dbsm_t *sm, int buf_this);	// returns false + + +typedef struct +{ +  uint16_t	port; +  uint16_t	first_line; +  uint16_t	last_line; +} buf_cmd_args_t; + +/*! + * double buffer state machine + */ +struct _dbsm +{ +  uint8_t	  buf0;	     // Must be even. This machine uses buf0 and buf0+1 +  uint8_t	  running; +  uint8_t	  rx_idle; +  uint8_t	  tx_idle; +  buf_cmd_args_t  recv_args; +  buf_cmd_args_t  send_args; +  inspector_t	  inspect; +  uint32_t	  precomputed_receive_to_buf_ctrl_word[2]; +  uint32_t	  precomputed_send_from_buf_ctrl_word[2]; +  int		  last_line_adj; +}; + +void dbsm_init(dbsm_t *sm, int buf0, +	       const buf_cmd_args_t *recv, const buf_cmd_args_t *send, +	       inspector_t inspect); + +void dbsm_start(dbsm_t *sm); +void dbsm_stop(dbsm_t *sm); +void dbsm_process_status(dbsm_t *sm, uint32_t status); +void dbsm_handle_tx_underrun(dbsm_t *sm); +void dbsm_handle_rx_overrun(dbsm_t *sm); + +/* + * The cpu calls this when it want to ensure that it can send a buffer + * to the same destination being used by this state machine. + * + * If neither buffer is EMPTYING it returns immediately.  If a buffer + * is EMPYTING, it waits for the h/w to transition to the DONE or + * ERROR state. + * + * When this function returns, the caller queues it's buffer and busy + * waits for it to complete. + */ +void dbsm_wait_for_opening(dbsm_t *sm); + +#endif /* INCLUDED_DBSM_H */ diff --git a/firmware/microblaze/lib/eeprom.c b/firmware/microblaze/lib/eeprom.c new file mode 100644 index 000000000..d4e170046 --- /dev/null +++ b/firmware/microblaze/lib/eeprom.c @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "i2c.h" +#include "mdelay.h" +#include "usrp2/fw_common.h" + +static const int EEPROM_PAGESIZE = 16; + +bool find_safe_booted_flag(void) { +	unsigned char flag_byte; +	eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1); +	return (flag_byte == 0x5E); +} + +void set_safe_booted_flag(bool flag) { +	unsigned char flag_byte = flag ? 0x5E : 0xDC; +	eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1); +} + +bool +eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len) +{ +  unsigned char cmd[2]; +  const unsigned char *p = (unsigned char *) buf; +   +  // The simplest thing that could possibly work: +  //   all writes are single byte writes. +  // +  // We could speed this up using the page write feature, +  // but we write so infrequently, why bother... + +  while (len-- > 0){ +    cmd[0] = eeprom_offset++; +    cmd[1] = *p++; +    bool r = i2c_write (i2c_addr, cmd, sizeof (cmd)); +    mdelay (10);	// delay 10ms worst case write time +    if (!r) +      return false; +  } +  return true; +} + +bool +eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len) +{ +  unsigned char *p = (unsigned char *) buf; + +  // We setup a random read by first doing a "zero byte write". +  // Writes carry an address.  Reads use an implicit address. + +  unsigned char cmd[1]; +  cmd[0] = eeprom_offset; +  if (!i2c_write (i2c_addr, cmd, sizeof (cmd))) +    return false; + +  while (len > 0){ +    // int n = std::min (len, MAX_EP0_PKTSIZE); +    int n = len; +    if (!i2c_read (i2c_addr, p, n)) +      return false; +    len -= n; +    p += n; +  } +  return true; +} +  diff --git a/firmware/microblaze/lib/eth_addrs.c b/firmware/microblaze/lib/eth_addrs.c new file mode 100644 index 000000000..ff5d04f4d --- /dev/null +++ b/firmware/microblaze/lib/eth_addrs.c @@ -0,0 +1,146 @@ +/* + * Copyright 2010 Ettus Research LLC + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ethernet.h" +#include "memory_map.h" +#include "nonstdio.h" +#include <stdbool.h> +#include "i2c.h" +#include "usrp2/fw_common.h" + +//////////////////////////////////////////////////////////////////////// +// EEPROM Layout +//////////////////////////////////////////////////////////////////////// +#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define USRP2_EE_MBOARD_IP_ADDR  0x0C //uint32, big-endian + +static bool +unprogrammed(const void *t, size_t len) +{ +  int i; +  uint8_t *p = (uint8_t *)t; +  bool all_zeros = true; +  bool all_ones =  true; +  for (i = 0; i < len; i++){ +    all_zeros &= p[i] == 0x00; +    all_ones  &= p[i] == 0xff; +  } +  return all_ones | all_zeros; +} + +//////////////////// MAC Addr Stuff /////////////////////// + +static int8_t src_mac_addr_initialized = false; + +static const eth_mac_addr_t default_mac_addr = {{ +    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff +  }}; + +static eth_mac_addr_t src_mac_addr = {{ +    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff +  }}; +   +void set_default_mac_addr(void) +{ +    src_mac_addr_initialized = true; +    src_mac_addr = default_mac_addr; +} + +const eth_mac_addr_t * +ethernet_mac_addr(void) +{ +  if (!src_mac_addr_initialized){    // fetch from eeprom +    src_mac_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_mac_addr; + +    eth_mac_addr_t tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_mac_addr = tmp; +  } + +  return &src_mac_addr; +} + +bool +ethernet_set_mac_addr(const eth_mac_addr_t *t) +{ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); +  if (ok){ +    src_mac_addr = *t; +    src_mac_addr_initialized = true; +    //eth_mac_set_addr(t); //this breaks the link +  } + +  return ok; +} + +//////////////////// IP Addr Stuff /////////////////////// + +static int8_t src_ip_addr_initialized = false; + +static const struct ip_addr default_ip_addr = { +    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + +static struct ip_addr src_ip_addr = { +    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + +void set_default_ip_addr(void) +{ +    src_ip_addr_initialized = true; +    src_ip_addr = default_ip_addr; +} + +const struct ip_addr *get_ip_addr(void) +{ +  if (!src_ip_addr_initialized){    // fetch from eeprom +    src_ip_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_ip_addr; + +    struct ip_addr tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_ip_addr = tmp; +  } + +  return &src_ip_addr; +} + +bool set_ip_addr(const struct ip_addr *t){ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); +  if (ok){ +    src_ip_addr = *t; +    src_ip_addr_initialized = true; +  } + +  return ok; +} diff --git a/firmware/microblaze/lib/eth_mac.c b/firmware/microblaze/lib/eth_mac.c new file mode 100644 index 000000000..034a4d494 --- /dev/null +++ b/firmware/microblaze/lib/eth_mac.c @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "eth_mac.h" +#include "memory_map.h" +#include <stdbool.h> +#include "eth_phy.h"	// for simulation constants +#include "mdelay.h" +#include "stdio.h" + +#define PHY_ADDR 1 + +void +eth_mac_set_addr(const eth_mac_addr_t *src) +{ +  eth_mac->ucast_hi =  +    (((unsigned int)src->addr[0])<<8) +  +    ((unsigned int)src->addr[1]); +  eth_mac->ucast_lo =  +    (((unsigned int)src->addr[2])<<24) +  +    (((unsigned int)src->addr[3])<<16) + +    (((unsigned int)src->addr[4])<<8) + +    (((unsigned int)src->addr[5])); +} + + +void  +eth_mac_init(const eth_mac_addr_t *src) +{ +  eth_mac->miimoder = 25;	// divider from CPU clock (50MHz/25 = 2MHz) + +  eth_mac_set_addr(src); +  eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST | MAC_SET_PAUSE_SEND_EN;  + +  eth_mac->pause_time = 38; +  eth_mac->pause_thresh = 1200; + +  // set rx flow control high and low water marks +  // unsigned int lwmark = (2*2048 + 64)/4; // 2 * 2048-byte frames + 1 * 64-byte pause frame +  // eth_mac->fc_hwmark = lwmark + 2048/4;  // plus a 2048-byte frame + +  //  eth_mac->fc_lwmark = 600;		// there are currently 2047 lines in the fifo +  // eth_mac->fc_hwmark = 1200; +  //eth_mac->fc_padtime = 1700;           // how long before flow control runs out do we  +                                        // request a re-pause.  Units of 8ns (bytes) + +  //eth_mac->tx_pause_en = 0;		// pay attn to pause frames sent to us +  //eth_mac->pause_quanta_set = 38;	// a bit more than 1 max frame 16kb/512 + fudge +  //eth_mac->pause_frame_send_en = 0;	// enable sending pause frames +} + +int +eth_mac_read_rmon(int addr) +{ +  int t = 0; +  /*   +  eth_mac->rmon_rd_addr = addr; +  eth_mac->rmon_rd_apply = 1; +  while(eth_mac->rmon_rd_grant == 0) +    ; + +  t = eth_mac->rmon_rd_dout; +  eth_mac->rmon_rd_apply = 0; +  */ +  return t; +} + +int +eth_mac_miim_read(int addr) +{ + +  int phy_addr = PHY_ADDR; +  eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr; +  eth_mac->miicommand = MIIC_RSTAT; + +  while((eth_mac->miistatus & MIIS_BUSY) != 0) +    ; + +  int r = eth_mac->miirx_data; +  //printf("MIIM-READ ADDR 0x%x DATA 0x%x\n",addr, r); +  return r; +} + +void +eth_mac_miim_write(int addr, int value) +{ +  int phy_addr = PHY_ADDR; +  eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr; +  eth_mac->miitx_data = value; +  eth_mac->miicommand = MIIC_WCTRLDATA; + +//  printf("MIIM-WRITE ADDR 0x%x VAL 0x%x\n",addr,value); +  while((eth_mac->miistatus & MIIS_BUSY) != 0) +    ; +} + +int +eth_mac_miim_read_status(void) +{ +  if (hwconfig_simulation_p()) +    return 0; + +  return eth_mac->miistatus; +} diff --git a/firmware/microblaze/lib/eth_mac.h b/firmware/microblaze/lib/eth_mac.h new file mode 100644 index 000000000..73feec955 --- /dev/null +++ b/firmware/microblaze/lib/eth_mac.h @@ -0,0 +1,32 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETH_MAC_H +#define INCLUDED_ETH_MAC_H + +#include <net/eth_mac_addr.h> + +void eth_mac_init(const eth_mac_addr_t *src); + +void eth_mac_set_addr(const eth_mac_addr_t *src); +int  eth_mac_read_rmon(int addr); +int  eth_mac_miim_read(int addr); +void eth_mac_miim_write(int addr, int value); +int  eth_mac_miim_read_status(void); + +#endif /* INCLUDED_ETH_MAC_H */ diff --git a/firmware/microblaze/lib/eth_mac_regs.h b/firmware/microblaze/lib/eth_mac_regs.h new file mode 100644 index 000000000..d680f8de0 --- /dev/null +++ b/firmware/microblaze/lib/eth_mac_regs.h @@ -0,0 +1,62 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETH_MAC_REGS_H +#define INCLUDED_ETH_MAC_REGS_H + +/* + * Simple GEMAC + * + */ +typedef struct { +  volatile int settings; +  volatile int ucast_hi; +  volatile int ucast_lo; +  volatile int mcast_hi; +  volatile int mcast_lo; +  volatile int miimoder; +  volatile int miiaddress; +  volatile int miitx_data; +  volatile int miicommand; +  volatile int miistatus; +  volatile int miirx_data; +  volatile int pause_time; +  volatile int pause_thresh; +} eth_mac_regs_t; + +// settings register +#define MAC_SET_PAUSE_EN  (1 << 0)   // Makes us respect received pause frames (normally on) +#define MAC_SET_PASS_ALL  (1 << 1)   // Enables promiscuous mode, currently broken +#define MAC_SET_PASS_PAUSE (1 << 2)  // Sends pause frames through (normally off) +#define MAC_SET_PASS_BCAST (1 << 3)  // Sends broadcast frames through (normally on) +#define MAC_SET_PASS_MCAST (1 << 4)  // Sends multicast frames that match mcast addr (normally off) +#define MAC_SET_PASS_UCAST (1 << 5)  // Sends unicast (normal) frames through if they hit in address filter (normally on) +#define MAC_SET_PAUSE_SEND_EN (1 << 6) // Enables sending pause frames + +// miicommand register +#define MIIC_SCANSSTAT	(1 << 0)	// Scan status +#define MIIC_RSTAT      (1 << 1)	// Read status +#define	MIIC_WCTRLDATA	(1 << 2)	// Write control data + +// miistatus register +#define MIIS_LINKFAIL	(1 << 0)	// The link failed +#define	MIIS_BUSY	(1 << 1)	// The MII is busy (operation in progress) +#define	MIIS_NVALID	(1 << 2)	// The data in the status register is invalid +					//   This it is only valid when the scan status is active. + +#endif /* INCLUDED_ETH_MAC_REGS_H */ diff --git a/firmware/microblaze/lib/ethernet.h b/firmware/microblaze/lib/ethernet.h new file mode 100644 index 000000000..52b297349 --- /dev/null +++ b/firmware/microblaze/lib/ethernet.h @@ -0,0 +1,99 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETHERNET_H +#define INCLUDED_ETHERNET_H + +#include <net/eth_mac_addr.h> +#include <lwip/ip_addr.h> +#include <stdbool.h> + +typedef void (*ethernet_link_changed_callback_t)(int speed); + + +/*! + * \brief one time call to initialize ethernet + */ +void ethernet_init(void); + +/*! + * \brief Specify the function to call on link state changes. + *  + * When the link comes up, speed is the link speed in Mbit/s. + * When the link goes down, speed is 0. + */ +void ethernet_register_link_changed_callback(ethernet_link_changed_callback_t cb); + +/*! + * \returns ethernet MAC address + */ +const eth_mac_addr_t *ethernet_mac_addr(void); + +/*!set mac addr to default*/ +void set_default_mac_addr(void); + +/*! + * \brief write mac address to eeprom and begin using it + */ +bool ethernet_set_mac_addr(const eth_mac_addr_t *t); + +/*! + * \returns IP address + */ +const struct ip_addr *get_ip_addr(void); + +/*!set ip addr to default*/ +void set_default_ip_addr(void); + +/*! + * \brief write ip address to eeprom and begin using it + */ +bool set_ip_addr(const struct ip_addr *t); + + +/* + * \brief read RMON regs and return error mask + */ +int ethernet_check_errors(void); + +#define	RME_RX_CRC	     0x0001 +#define	RME_RX_FIFO_FULL     0x0002 +#define RME_RX_2SHORT_2LONG  0x0004 + +#define	RME_TX_JAM_DROP	     0x0010 +#define	RME_TX_FIFO_UNDER    0x0020 +#define	RME_TX_FIFO_OVER     0x0040 + + +typedef enum { LS_UNKNOWN, LS_DOWN, LS_UP } eth_link_state_t; + +// flow control bitmasks +#define	FC_NONE		0x0 +#define	FC_WE_TX	0x1			// we send PAUSE frames +#define	FC_WE_RX 	0x2			// we honor received PAUSE frames +#define	FC_SYMM		(FC_WE_TX | FC_WE_RX) + +#define S_UNKNOWN (-1)			// unknown link speed + +typedef struct { +  eth_link_state_t	link_state; +  int			link_speed;	// in Mb/s +  int			flow_control; +} ethernet_t; + +#endif /* INCLUDED_ETHERNET_H */ diff --git a/firmware/microblaze/lib/ethertype.h b/firmware/microblaze/lib/ethertype.h new file mode 100644 index 000000000..11f4bafec --- /dev/null +++ b/firmware/microblaze/lib/ethertype.h @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_ETHERTYPE_H +#define INCLUDED_ETHERTYPE_H + +// all we care about + +#define	ETHERTYPE_IPV4	0x0800 +#define	ETHERTYPE_ARP	0x0806 + + +#endif /* INCLUDED_ETHERTYPE_H */ diff --git a/firmware/microblaze/lib/exit.c b/firmware/microblaze/lib/exit.c new file mode 100644 index 000000000..95a3bf4de --- /dev/null +++ b/firmware/microblaze/lib/exit.c @@ -0,0 +1,28 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +extern void _exit(int status); + +void  +exit(int status) +{ +  _exit(status); +} diff --git a/firmware/microblaze/lib/gdbstub2.c b/firmware/microblaze/lib/gdbstub2.c new file mode 100644 index 000000000..4c63dfce2 --- /dev/null +++ b/firmware/microblaze/lib/gdbstub2.c @@ -0,0 +1,506 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Implement a eensy weensy part of the GDB Remote Serial Protocol + * + * See Appendix D of the GDB manual + * + *   m<addr>,<length> 		-- read <length> bytes of memory starting at <addr> + *     Reply: + *     XX...		XX... is memory contents in hex + *     ENN		ENN   NN is a hex error number + * + *   M<addr>,<length>:XX...     -- write memory, data in hex + *     Reply: + *     OK		for success + *     ENN		for an error.  NN is a hex error number + * + *   X<addr>,<length>:XX...     -- write memory, data in binary + *     Reply: + *     OK		for success + *     ENN		for an error.  NN is a hex error number + * + *   c<addr>			-- continue.  <addr> is the address to resume (goto). + *     Reply: <none> + * + *   \x80 New Format... + */ + +#include "gdbstub2.h" +#include "loader_parser.h" +#include "hal_uart.h" +#include <stdbool.h> +#include <stddef.h> + +#define MAX_PACKET	1024 + +/* + * Get raw character from serial port, no echo. + */ +static inline int  +gdb_getc(void) +{ +  return hal_uart_getc(); +} + +/* + * Put character to serial port.  Raw output. + */ +static inline void +gdb_putc(int ch) +{ +  hal_uart_putc(ch); +} + +// ------------------------------------------------------------------------ + +#define	GDB_ESCAPE 0x7d + +static unsigned char hex_table[16] = {  +  '0', '1', '2', '3', '4', '5', '6', '7', +  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +static int +put_hex8_checksum(int ch, int checksum) +{ +  unsigned char t = hex_table[(ch >> 4) & 0xf]; +  checksum += t; +  gdb_putc(t); + +  t = hex_table[ch & 0xf]; +  checksum += t; +  gdb_putc(t); +  return checksum; +} + +static void +put_hex8(int ch) +{ +  put_hex8_checksum(ch, 0); +} + +static bool +hex4_to_bin(int ch, int *value) +{ +  if ('0' <= ch && ch <= '9'){ +    *value = ch - '0'; +    return true; +  } +  if ('a' <= ch && ch <= 'f'){ +    *value = ch - 'a' + 10; +    return true; +  } +  if ('A' <= ch && ch <= 'F'){ +    *value = ch - 'A' + 10; +    return true; +  } +  *value = 0; +  return false; +} + +static bool +hex8_to_bin(const unsigned char *s, int *value) +{ +  int v0, v1; +  if (hex4_to_bin(s[0], &v0) && hex4_to_bin(s[1], &v1)){ +    *value = (v0 << 4) | v1; +    return true; +  } +  return false; +} + +static bool +hex_to_bin_array(unsigned char *binary_data, const unsigned char *hex_data, size_t nbytes) +{ +  for (size_t i = 0; i < nbytes; i++){ +    int t; +    if (!hex8_to_bin(&hex_data[2*i], &t)) +      return false; +    binary_data[i] = t; +  } +  return true; +} + +static bool +needs_escaping(int ch) +{ +  return ch == '$' || ch == '#' || ch == GDB_ESCAPE; +} + +/* + * \brief Wait for a packet.   + * \param[out] pkt_buf gets the received packet payload. + * \param[in]  max_size is the maximum number of bytes to write into \p pkt_buf. + * \param[out] actual_size is the number of bytes written to \p pkt_buf. + * + * \returns true iff the payload fits and the checksum is OK. + * + * Packets have this format: + * + *  $<packet-data>#<checksum> + * + * Where <packet-data> is anything and <checksum> is a two byte hex + * checksum.  In <packet-data> '$', '#' and 0x7d are escaped with 0x7d. + * The checksum is computed as the modulo 256 sum of all characters + * btween the leading '$' and the trailing '#' (an 8-bit unsigned + * checksum). + */ +static bool +get_packet(unsigned char *pkt_buf, size_t max_size, size_t *actual_size) +{ +  typedef enum states { +    LOOKING_FOR_DOLLAR, +    LOOKING_FOR_HASH, +    CSUM1, +    CSUM2, +  } state_t; + +  *actual_size = 0; +  unsigned char csum[2] = {0, 0}; +  state_t state = LOOKING_FOR_DOLLAR; +  size_t  pi = 0; + +  while (1){ +    int ch = gdb_getc(); + +    switch (state){ +    case LOOKING_FOR_DOLLAR: +      if (ch == '$'){ +	pi = 0; +	state = LOOKING_FOR_HASH; +      } +      else if (ch == '#'){	// most likely missed the $ +	return false; +      } +      break; +	 +    case LOOKING_FOR_HASH: +      if (ch == '$'){ +	return false; +      } +      else if (ch == '#'){ +	state = CSUM1; +      } +      else { +	if (pi >= max_size)	// payload too big +	  return false; + +	if (ch == GDB_ESCAPE) +	  ch = gdb_getc(); + +	pkt_buf[pi++] = ch; +      } +      break; +       +    case CSUM1: +      csum[0] = ch; +      state = CSUM2; +      break; + +    case CSUM2: +      csum[1] = ch; +      *actual_size = pi; + +      // accept .. as a correct checksum +      if (csum[0] == '.' && csum[1] == '.') +	return true; + +      int expected_checksum; +      if (!hex8_to_bin(csum, &expected_checksum)) +	return false; + +      int checksum = 0; +      for (size_t i = 0; i < pi; i++) +	checksum += pkt_buf[i]; + +      checksum &= 0xff; +      return checksum == expected_checksum; +    } +  } +} + +static void +put_packet_trailer(int checksum) +{ +  gdb_putc('#'); +  put_hex8(checksum & 0xff); +  gdb_putc('\r'); +  gdb_putc('\n'); +} + +static void +put_packet(const unsigned char *pkt_buf, size_t size) +{ +  gdb_putc('$'); + +  int checksum = 0; +  for (size_t i = 0; i < size; i++){ +    int ch = pkt_buf[i]; +    if (needs_escaping(ch)) +      gdb_putc(GDB_ESCAPE); +    gdb_putc(ch); +    checksum += ch; +  } +  put_packet_trailer(checksum); +} + +/*! + * Read a hex number + * + * \param[inout] bufptr - pointer to pointer to buffer (updated on return) + * \param[in] end - one past end of valid data in buf + * \param[out] value - the parsed value + * + * \returns true iff a valid hex number was read from bufptr + */ +static bool +parse_number(const unsigned char **bufptr, const unsigned char *end, unsigned int *value) +{ +  const unsigned char *buf = *bufptr; +  unsigned int v = 0; +  bool valid = false; +  int nibble; + +  while (buf < end && hex4_to_bin(*buf, &nibble)){ +    valid = true; +    v = (v << 4) | nibble; +    buf++; +  } +   +  *value = v; +  *bufptr = buf; +  return valid; +} + +static bool +parse_char(const unsigned char **bufptr, const unsigned char *end, unsigned char *ch) +{ +  const unsigned char *buf = *bufptr; +  if (buf < end){ +    *ch = *buf++; +    *bufptr = buf; +    return true; +  } +  return false; +} + +static bool +expect_char(const unsigned char **bufptr, const unsigned char *end, unsigned char expected) +{ +  unsigned char ch; +  return parse_char(bufptr, end, &ch) && ch == expected; +} + +static bool +expect_end(const unsigned char **bufptr, const unsigned char *end) +{ +  return *bufptr == end; +} + +static bool +parse_addr_length(const unsigned char **bufptr, const unsigned char *end, +		  unsigned int *addr, unsigned int *length) +{ +  return (parse_number(bufptr, end, addr) +	  && expect_char(bufptr, end, ',') +	  && parse_number(bufptr, end, length)); +} + +static void +put_error(int error) +{ +  unsigned char buf[3]; +  buf[0] = 'E'; +  buf[1] = hex_table[(error >> 4) & 0xf]; +  buf[2] = hex_table[error & 0xf]; +   +  put_packet(buf, sizeof(buf)); +} + +static void +put_ok(void) +{ +  const unsigned char buf[2] = "OK"; +  put_packet(buf, sizeof(buf)); +} + +/* + * Read memory and send the reply. + * We do it on the fly so that our packet size is effectively unlimited + */ +static void +read_memory(unsigned int addr, unsigned int nbytes) +{ +  int checksum = 0; +  gdb_putc('$'); + +  if ((addr & 0x3) == 0 && (nbytes & 0x3) == 0){	// word aligned +    union { +      unsigned int	i; +      unsigned char	c[4]; +    } u; + +    unsigned int *p = (unsigned int *) addr; +    unsigned int length = nbytes / 4; + +    for (unsigned int i = 0; i < length; i++){ +      u.i = p[i];	// do a word read +      checksum = put_hex8_checksum(u.c[0], checksum); +      checksum = put_hex8_checksum(u.c[1], checksum); +      checksum = put_hex8_checksum(u.c[2], checksum); +      checksum = put_hex8_checksum(u.c[3], checksum); +    } +  } +  else {						// byte aligned +    unsigned char *p = (unsigned char *) addr; +    for (unsigned int i = 0; i < nbytes; i++) +      checksum = put_hex8_checksum(p[i], checksum); +  } + +  put_packet_trailer(checksum); +} + +static unsigned int +get_unaligned_int(const unsigned char *p) +{ +  // we're bigendian +  return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); +} + +static bool +write_memory(unsigned int addr, size_t nbytes, +	     const unsigned char *data) +{ +  if ((addr & 0x3) == 0 && (nbytes & 0x3) == 0){	// word-aligned dst +    unsigned int *dst = (unsigned int *) addr; +    size_t length = nbytes / 4; +    for (size_t i = 0; i < length; i++){ +      unsigned int t = get_unaligned_int(&data[4*i]); +      dst[i] = t;					// word writes +    } +  } +  else {						// non-word-aligned dst +    unsigned char *dst = (unsigned char *) addr; +    for (size_t i = 0; i < nbytes; i++){ +      dst[i] = data[i]; +    } +  } +  return true; +} + +void +gdbstub2_main_loop(void) +{ +  unsigned char inpkt[MAX_PACKET + 24]; +  unsigned char binary_data[MAX_PACKET/2] __attribute__((aligned (4))); + +  hal_uart_set_mode(UART_MODE_RAW); //tell UART HAL not to map \n to \r\n + +  while (1){ +    size_t	inpkt_len; +    bool ok = get_packet(inpkt, sizeof(inpkt), &inpkt_len); +    if (!ok){ +      gdb_putc('-'); +      continue; +    } +    gdb_putc('+'); + +    const unsigned char *buf = inpkt; +    const unsigned char *end = inpkt + inpkt_len; +    unsigned char ch; + +    if (!parse_char(&buf, end, &ch)){	// empty packet +      put_packet(0, 0); +      continue; +    } + +    unsigned int addr; +    unsigned int length; + +    switch(ch){ +    case 'm':		// m<addr>,<length>  -- read <length> bytes starting at <addr> +      if (!(parse_addr_length(&buf, end, &addr, &length) && expect_end(&buf, end))){ +	put_error(1); +      } +      else { +	read_memory(addr, length); +      } +      break; + +    case 'M':		// M<addr>,<length>:XX...  -- write <length> bytes starting at <addr> +			//   XX... is the data in hex +      if (!(parse_addr_length(&buf, end, &addr, &length) +	    && expect_char(&buf, end, ':') +	    && (end - buf) == 2 * length)){ +	put_error(1); +      } +      else { +	if (!hex_to_bin_array(binary_data, buf, length)) +	  put_error(2); +	else if (!write_memory(addr, length, binary_data)) +	  put_error(3); +	else +	  put_ok(); +      } +      break; + +    case 'X':		// X<addr>,<length>:XX...  -- write <length> bytes starting at <addr> +			//   XX... is the data in binary +      if (!(parse_addr_length(&buf, end, &addr, &length) +	    && expect_char(&buf, end, ':') +	    && (end - buf) == length)){ +	put_error(1); +      } +      else { +	if (!write_memory(addr, length, buf)) +	  put_error(3); +	else +	  put_ok(); +      } +      break; + +    case 'c':		// c<addr>	-- continue.  <addr> is the address to resume (goto). +      if (!(parse_number(&buf, end, &addr) +	    && expect_end(&buf, end))){ +	put_error(1); +      } +      else { +	typedef void (*fptr_t)(void); +	(*(fptr_t) addr)();	// most likely no return +      } +      break; +/* +    case 0x80: +      { +	unsigned char *output = binary_data;  // reuse +	size_t sizeof_output = sizeof(binary_data); +	size_t actual_olen; +	loader_parser(buf, end-buf, +		      output, sizeof_output, &actual_olen); +	put_packet(output, actual_olen); +      } +      break; +*/ +    default:		// unknown packet type +      put_packet(0, 0); +      break; +    } +  } +} diff --git a/firmware/microblaze/lib/gdbstub2.h b/firmware/microblaze/lib/gdbstub2.h new file mode 100644 index 000000000..15cdde939 --- /dev/null +++ b/firmware/microblaze/lib/gdbstub2.h @@ -0,0 +1,25 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_GDBSTUB_H +#define INCLUDED_GDBSTUB_H + +void gdbstub2_main_loop(void); + +#endif /* INCLUDED_GDBSTUB_H */ + diff --git a/firmware/microblaze/lib/hal_io.c b/firmware/microblaze/lib/hal_io.c new file mode 100644 index 000000000..be4c570c7 --- /dev/null +++ b/firmware/microblaze/lib/hal_io.c @@ -0,0 +1,271 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +// conditionalized on HAL_IO_USES_DBOARD_PINS && HAL_IO_USES_UART + +#include "memory_map.h" +#include "hal_uart.h" +#include "hal_io.h" +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +/* + * ======================================================================== + *				leds + * ======================================================================== + */ + +static unsigned long leds_shadow = 0; +static unsigned long led_src_shadow = 0; + +void  +hal_set_leds(int value, int mask) +{ +  int ei = hal_disable_ints(); +  leds_shadow = (leds_shadow & ~mask) | (value & mask); +  output_regs->leds = leds_shadow; +  hal_restore_ints(ei); +} + +// Allow hardware control over leds.  1 = hardware, 0 = software +void  +hal_set_led_src(int value, int mask) +{ +  int ei = hal_disable_ints(); +  led_src_shadow = (led_src_shadow & ~mask) | (value & mask); +  output_regs->led_src = led_src_shadow; +  hal_restore_ints(ei); +} + +void  +hal_toggle_leds(int mask) +{ +  int ei = hal_disable_ints(); +  leds_shadow ^= mask; +  output_regs->leds = leds_shadow; +  hal_restore_ints(ei); +} + + +// ================================================================ +//		    		primitives +// ================================================================ + +#if defined(HAL_IO_USES_DBOARD_PINS) +// +// Does i/o using high 9-bits of rx daughterboard pins. +// +//  1 1 1 1 1 1 +//  5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |      char     |W|             | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +//  +// Asserts W when writing char +// + +#define W 	0x0080 + +void +hal_io_init(void) +{ +  // make high 9 bits of tx daughterboard outputs +  hal_gpio_set_rx_mode(15, 7, GPIOM_OUTPUT); + +  // and set them to zero +  hal_gpio_set_rx(0x0000, 0xff80); +} + +void +hal_finish(void) +{ +  volatile unsigned long *p = (unsigned long *) 0xC2F0; +  *p = 0; +} + +// %c +inline int +putchar(int ch) +{ +  hal_gpio_set_rx((s << 8) | W, 0xff80); +  hal_gpio_set_rx(0, 0xff80); +  return ch; +} + +#elif defined(HAL_IO_USES_UART) + +void +hal_io_init(void) +{ +  hal_uart_init(); +} + +void +hal_finish(void) +{ +} + +// %c +inline int +fputchar(hal_uart_name_t u, int ch) +{ +  hal_uart_putc(u, ch); +  return ch; +} + +inline int +putchar(int ch) +{ +  hal_uart_putc(DEFAULT_UART, ch); +  return ch; +} + +int +fgetchar(hal_uart_name_t u) +{ +  return hal_uart_getc(u); +} + +int +getchar(void) +{ +  return fgetchar(DEFAULT_UART); +} + +#else	// nop all i/o + +void +hal_io_init(void) +{ +} + +void +hal_finish(void) +{ +} + +// %c +inline int +putchar(int ch) +{ +  return ch; +} + +int +getchar(void) +{ +  return EOF; +} + +#endif + +// ================================================================ +//             (slightly) higher level functions +// +// These are here so we can inline the calls to putchar. +// The rest of the stuff was moved to nonstdio.c +// ================================================================ + +// \n +inline void  +fnewline(hal_uart_name_t u) +{ +  fputchar(u, '\n'); +} + +inline void +newline(void) +{ +  fnewline(DEFAULT_UART); +} + +int +fputstr(hal_uart_name_t u, const char *s) +{ +  while (*s) +    fputchar(u, *s++); + +  return 0; +} + +int +fnputstr(hal_uart_name_t u, const char *s, int len) +{ +  int x = 0; +  while (*s && (len > x++)) +    fputchar(u, *s++); + +  return x; +} + +int +putstr(const char *s) +{ +  return fputstr(DEFAULT_UART, s); +} + +int +fputs(hal_uart_name_t u, const char *s) +{ +  fputstr(u, s); +  fputchar(u, '\n'); +  return 0; +} + +int puts(const char *s) +{ +  return fputs(DEFAULT_UART, s); +} + +char * +fgets(hal_uart_name_t u, char * const s) +{ +  char *x = s; +  while((*x=(char)hal_uart_getc(u)) != '\n') x++; +  *x = 0; +  return s; +} + +int +fngets(hal_uart_name_t u, char * const s, int len) +{ +  char *x = s; +  while(((*x=(char)hal_uart_getc(u)) != '\n') && ((x-s) < len)) x++; +  *x = 0; +  return (x-s); +} + +int +fngets_timeout(hal_uart_name_t u, char * const s, int len) +{ +  char *x = s; + +  while(((*x=(char)hal_uart_getc_timeout(u)) != '\n') && (*x != -1) && ((x-s) < len)) x++; +  *x = 0; +  //printf("Returning from fngets() with string %d of length %d\n", s[0], x-s); +  return (x-s); +} + +char * +gets(char * const s) +{ +  return fgets(DEFAULT_UART, s); +} + diff --git a/firmware/microblaze/lib/hal_io.h b/firmware/microblaze/lib/hal_io.h new file mode 100644 index 000000000..950f8d591 --- /dev/null +++ b/firmware/microblaze/lib/hal_io.h @@ -0,0 +1,114 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_HAL_IO_H +#define INCLUDED_HAL_IO_H + +#include "memory_map.h" +#include "hal_uart.h" + +void hal_io_init(void); +void hal_finish(); +char *gets(char * const s); +int fputstr(hal_uart_name_t u, const char *s); +int fnputstr(hal_uart_name_t u, const char *s, int len); +int fngets(hal_uart_name_t u, char * const s, int len); +int fngets_timeout(hal_uart_name_t u, char * const s, int len); + +/* + * ------------------------------------------------------------------------ + *			   control the leds + * + * Low 4-bits are the general purpose leds on the board + * The next bit is the led on the ethernet connector + * ------------------------------------------------------------------------ + */ + +void hal_set_leds(int value, int mask); +void hal_set_led_src(int value, int mask); +void hal_toggle_leds(int mask); + +/* + * ------------------------------------------------------------------------ + *			   simple timeouts + * ------------------------------------------------------------------------ + */ + + + +static inline void +hal_set_timeout(int delta_ticks) +{ +  sr_simple_timer->onetime = delta_ticks; +} + +/* + * ------------------------------------------------------------------------ + *			interrupt enable/disable + * ------------------------------------------------------------------------ + */ + +/*! + * \brief Disable interrupts and return previous interrupt enable state. + * [Microblaze specific] + */ +static inline int +hal_disable_ints(void) +{ +  int result, t0; + +  asm volatile("mfs   %0, rmsr       \n\ +		andni %1, %0, 0x2    \n\ +		mts   rmsr, %1" +	       : "=r" (result), "=r" (t0)); +  return result; +} + +/*! + * \brief Enable interrupts and return previous interrupt enable state. + * [Microblaze specific] + */ +static inline int +hal_enable_ints(void) +{ +  int result, t0; + +  asm volatile("mfs  %0, rmsr	      \n\ +		ori  %1, %0, 0x2      \n\ +		mts  rmsr, %1" +	       : "=r" (result), "=r" (t0)); +  return result; +} + +/*! + * \brief Set interrupt enable state to \p prev_state. + * [Microblaze specific] + */ +static inline void +hal_restore_ints(int prev_state) +{ +  int t0, t1; +  asm volatile("andi  %0, %2, 0x2	\n\ +		mfs   %1, rmsr          \n\ +		andni %1, %1, 0x2	\n\ +		or    %1, %1, %0	\n\ +		mts   rmsr, %1" +	       : "=r" (t0), "=r"(t1) : "r" (prev_state)); +} + +#endif /* INCLUDED_HAL_IO_H */ diff --git a/firmware/microblaze/lib/hal_uart.c b/firmware/microblaze/lib/hal_uart.c new file mode 100644 index 000000000..7836240fe --- /dev/null +++ b/firmware/microblaze/lib/hal_uart.c @@ -0,0 +1,120 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "memory_map.h" +#include "hal_uart.h" +#include "hal_io.h" +#include "mdelay.h" + +//just to save you from going insane, note that firmware/FPGA UARTs [0-2] correspond to serial ports [1-3]. +//so in software, we refer to UART_DEBUG as UART0, but it transmits on pin TXD<1>. see the UART assignments in hal_uart.h. + +#define NSPEEDS 6 +#define	MAX_WB_DIV 4 + +//if you're going to recalculate the divisors, it's just uart_clock_rate / baud_rate. +//uart_clock_rate is 50MHz for USRP2. +static const uint16_t +divisor_table[NSPEEDS] = { +  5208,	//    9600 +  2604,	//   19200 +  1302,	//   38400 +  868,	//   57600 +  434,	//  115200 +  217	//  230400 +}; + +static char uart_mode[4] = { +  [UART_DEBUG] = UART_MODE_ONLCR,  +  [UART_EXP] = UART_MODE_ONLCR,  +  [UART_GPS] = UART_MODE_ONLCR +}; + +static char uart_speeds[4] = { +  [UART_DEBUG] = US_230400, +  [UART_EXP] = US_230400, +  [UART_GPS] = US_115200 +}; + +void +hal_uart_set_mode(hal_uart_name_t uart, int mode) +{ +  uart_mode[uart] = mode; +} + +void hal_uart_set_speed(hal_uart_name_t uart, hal_uart_speed_t speed) +{ +  uart_regs[uart].clkdiv = divisor_table[speed]; +} + +void +hal_uart_init(void) +{ +  for(int i = 0; i < 3; i++) { +  	hal_uart_set_mode(i, uart_mode[i]); +    hal_uart_set_speed(i, uart_speeds[i]); +  } +} + +void +hal_uart_putc(hal_uart_name_t u, int ch) +{ +  if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR))		//map \n->\r\n if necessary +    hal_uart_putc(u, '\r'); + +  while (uart_regs[u].txlevel == 0)	 // wait for fifo to have space +    ; + +  uart_regs[u].txchar = ch; +} + +void +hal_uart_putc_nowait(hal_uart_name_t u, int ch) +{ +  if ((ch == '\n') && (uart_mode[u] == UART_MODE_ONLCR))		//map \n->\r\n if necessary +    hal_uart_putc(u, '\r'); + +  if(uart_regs[u].txlevel)   // If fifo has space +    uart_regs[u].txchar = ch; +} + +int +hal_uart_getc(hal_uart_name_t u) +{ +  while ((uart_regs[u].rxlevel) == 0)  // wait for data to be ready +    ; + +  return uart_regs[u].rxchar; +} + +int  +hal_uart_getc_timeout(hal_uart_name_t u) +{ +  int timeout = 0; +  while (((uart_regs[u].rxlevel) == 0) && (timeout++ < HAL_UART_TIMEOUT_MS)) +    mdelay(1); +  return (timeout >= HAL_UART_TIMEOUT_MS) ? -1 : uart_regs[u].rxchar; //return -1 if nothing there, cause fngets to quit +} + +int hal_uart_rx_flush(hal_uart_name_t u) +{ +  char x; +  while(uart_regs[u].rxlevel) x = uart_regs[u].rxchar; +  return x; +} + diff --git a/firmware/microblaze/lib/hal_uart.h b/firmware/microblaze/lib/hal_uart.h new file mode 100644 index 000000000..758c8cb5e --- /dev/null +++ b/firmware/microblaze/lib/hal_uart.h @@ -0,0 +1,94 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_HAL_UART_H +#define INCLUDED_HAL_UART_H + +/*! + * \brief uart mode flags + */ +#define	UART_MODE_RAW		0x0000	// no mapping on input or output +#define	UART_MODE_ONLCR	0x0001	// map \n to \r\n on output (default) + +#define DEFAULT_UART UART_DEBUG //which UART printf, gets, etc. use + +#define HAL_UART_TIMEOUT_MS 300 + +typedef enum { +  US_9600   = 0, +  US_19200  = 1, +  US_38400  = 2, +  US_57600  = 3, +  US_115200 = 4, +  US_230400 = 5 +} hal_uart_speed_t; + +typedef struct { +  hal_uart_speed_t	speed; +} hal_uart_config_t; + +typedef enum { +  UART_DEBUG = 0, +  UART_EXP   = 1, +  UART_GPS   = 2 +} hal_uart_name_t; + +/* + * \brief Set uart mode + */ +void hal_uart_set_mode(hal_uart_name_t uart, int flags); + +/*! + * \brief one-time call to init + */ +void hal_uart_init(void); + +/*! + * \brief Set uart parameters + *  Default is 115,200 bps, 8N1. + */ +void hal_uart_set_config(const hal_uart_config_t *c); + +/*! + * \brief Get uart configuation. + */ +void hal_uart_get_config(hal_uart_config_t *c); + +/*! + * \brief Enqueue \p ch for output over serial port + */ +void hal_uart_putc(hal_uart_name_t u, int ch); + +/*! + * \brief Enqueue \p ch for output over serial port, silent fail if queue is full + */ +void hal_uart_putc_nowait(hal_uart_name_t u, int ch); + +/* + * \brief Blocking read of next char from serial port + */ +int hal_uart_getc(hal_uart_name_t u); + +/* + * \brief Blocking read of next char from serial port with timeout + */ +int hal_uart_getc_timeout(hal_uart_name_t u); + +int hal_uart_rx_flush(hal_uart_name_t u); + +#endif /* INCLUDED_HAL_UART_H */ diff --git a/firmware/microblaze/lib/i2c.c b/firmware/microblaze/lib/i2c.c new file mode 100644 index 000000000..d230f462c --- /dev/null +++ b/firmware/microblaze/lib/i2c.c @@ -0,0 +1,129 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "i2c.h" +#include "memory_map.h" +#include "stdint.h" +#include <string.h> +#include "nonstdio.h" + +#define MAX_WB_DIV 4	// maximum wishbone divisor (from 100 MHz MASTER_CLK) + +// prescaler divisor values for 100 kHz I2C [uses 5 * SCLK internally] + +#define PRESCALER(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 400000)) - 1) + +static uint16_t prescaler_values[MAX_WB_DIV+1] = { +  0xffff,	// 0: can't happen +  PRESCALER(1),	// 1: 100 MHz +  PRESCALER(2), // 2:  50 MHz +  PRESCALER(3), // 3:  33.333 MHz +  PRESCALER(4), // 4:  25 MHz +}; + +void +i2c_init(void) +{ +  i2c_regs->ctrl = 0;		// disable core +   +  // setup prescaler depending on wishbone divisor +  int wb_div = hwconfig_wishbone_divisor(); +  if (wb_div > MAX_WB_DIV) +    wb_div = MAX_WB_DIV; + +  i2c_regs->prescaler_lo = prescaler_values[wb_div] & 0xff; +  i2c_regs->prescaler_hi = (prescaler_values[wb_div] >> 8) & 0xff; + +  i2c_regs->ctrl = I2C_CTRL_EN; //| I2C_CTRL_IE;	// enable core + +  //now this is done separately to maintain common code for async and sync +  //pic_register_handler(IRQ_I2C, i2c_irq_handler); +} + +static inline void +wait_for_xfer(void) +{ +  while (i2c_regs->cmd_status & I2C_ST_TIP)	// wait for xfer to complete +    ; +} + +static inline bool +wait_chk_ack(void) +{ +  wait_for_xfer(); + +  if ((i2c_regs->cmd_status & I2C_ST_RXACK) != 0){	// target NAK'd +    return false; +  } +  return true; +} + +bool  +i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len) +{ +  if (len == 0)			// reading zero bytes always works +    return true; + +  while (i2c_regs->cmd_status & I2C_ST_BUSY) +    ; + +  i2c_regs->data = (i2c_addr << 1) | 1;	 // 7 bit address and read bit (1) +  // generate START and write addr +  i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; +  if (!wait_chk_ack()) +    goto fail; + +  for (; len > 0; buf++, len--){ +    i2c_regs->cmd_status = I2C_CMD_RD | (len == 1 ? (I2C_CMD_NACK | I2C_CMD_STOP) : 0); +    wait_for_xfer(); +    *buf = i2c_regs->data; +  } +  return true; + + fail: +  i2c_regs->cmd_status = I2C_CMD_STOP;  // generate STOP +  return false; +} + + +bool  +i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len) +{ +  while (i2c_regs->cmd_status & I2C_ST_BUSY) +    ; + +  i2c_regs->data = (i2c_addr << 1) | 0;	 // 7 bit address and write bit (0) + +  // generate START and write addr (and maybe STOP) +  i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0); +  if (!wait_chk_ack()) +    goto fail; + +  for (; len > 0; buf++, len--){ +    i2c_regs->data = *buf; +    i2c_regs->cmd_status = I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0); +    if (!wait_chk_ack()) +      goto fail; +  } +  return true; + + fail: +  i2c_regs->cmd_status = I2C_CMD_STOP;  // generate STOP +  return false; +} + diff --git a/firmware/microblaze/lib/i2c.h b/firmware/microblaze/lib/i2c.h new file mode 100644 index 000000000..1af4d72df --- /dev/null +++ b/firmware/microblaze/lib/i2c.h @@ -0,0 +1,39 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_I2C_H +#define INCLUDED_I2C_H + +#include <stdbool.h> +#include "stdint.h" + +void i2c_init(void); +bool i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len); +bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len); + +bool eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len); + +// Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. +// Which EEPROM is determined by i2c_addr.  See i2c_addr.h + +bool eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len); + +bool find_safe_booted_flag(void); +void set_safe_booted_flag(bool flag); + +#endif /* INCLUDED_I2C_H */ diff --git a/firmware/microblaze/lib/i2c_async.c b/firmware/microblaze/lib/i2c_async.c new file mode 100644 index 000000000..05c4c3a09 --- /dev/null +++ b/firmware/microblaze/lib/i2c_async.c @@ -0,0 +1,206 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +  + //i2c_async.c: asynchronous (interrupt-driven) routines for I2C. + //separated out here so we can have a small I2C lib for bootloader and + //retain interrupt-driven I2C for the main app. + +#include "memory_map.h" +#include "stdint.h" +#include <string.h> +#include "pic.h" +#include "nonstdio.h" +#include "i2c_async.h" +  + //asynchronous (interrupt-driven) i2c state variables +volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer +volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position +volatile uint8_t i2c_len = 0; //length remaining in current transfer +volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state +i2c_dir_t i2c_dir; //I2C transfer direction + +void  (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete +static void i2c_irq_handler(unsigned irq); +inline void i2c_async_err(void); + +void i2c_register_handler(void) { +    pic_register_handler(IRQ_I2C, i2c_irq_handler); +} + + +static void i2c_irq_handler(unsigned irq) { +//i2c state machine. + +  //printf("I2C irq handler\n"); +  //first let's make sure nothing is f'ed up +  //TODO: uncomment this error checking when we have some way to handle errors +//  if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it +//    printf("\tNACK received\n"); +//    i2c_async_err(); +//    return; +//  }// else printf("\tACK received, proceeding\n"); + +  if(i2c_regs->cmd_status & I2C_ST_AL) {  +    printf("\tArbitration lost!\n"); +    i2c_async_err(); +    return; +  } + +  if(i2c_regs->cmd_status & I2C_ST_TIP) { +    //printf("\tI2C still busy in interrupt\n"); +    return; +  } + +  //now decide what to do +  switch(i2c_state) { + +  case I2C_STATE_IDLE: +    //this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad. +    printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n"); +    i2c_async_err(); +    break; + +  case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet. +  case I2C_STATE_DATA:      //here we're sending/receiving data and if we're receiving there's data in the data reg + +    //if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len); +    //else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len); + +    if(i2c_dir == I2C_DIR_READ) { +      if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data; +      //printf("\tRead %x\n", *(i2c_bufptr-1)); +      //set up another data byte +      if(i2c_len > 1) //only one more byte to transfer +        i2c_regs->cmd_status = I2C_CMD_RD; +      else +        i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP; +    } +    else if(i2c_dir == I2C_DIR_WRITE) { +      //write a byte +      //printf("\tWriting %x\n", *i2c_bufptr); +      i2c_regs->data = *(i2c_bufptr++); +      if(i2c_len > 1) +        i2c_regs->cmd_status = I2C_CMD_WR; +      else { +        //printf("\tGenerating STOP\n"); +        i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP; +      } +    }; +    i2c_len--; +    if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE; +    else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition +    break; + + +  case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us. +    //printf("\tI2C in state LAST BYTE\n"); + +    if(i2c_dir == I2C_DIR_READ) { +      *(i2c_bufptr++) = i2c_regs->data; +      //printf("\tRead %x\n", *(i2c_bufptr-1)); +      i2c_state = I2C_STATE_DATA_READY; +    } else { +      i2c_state = I2C_STATE_IDLE; +    } +    i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time + +    if(i2c_callback) { +      i2c_callback(); //if we registered a callback, call it! +    } + +    break; + + +  default: //terrible things have happened. +    break; +  } + +} + +void i2c_register_callback(void (*volatile callback)(void)) { +  i2c_callback = callback; +} + +inline void i2c_async_err(void) { +  i2c_state = I2C_STATE_IDLE; +  i2c_regs->ctrl &= ~I2C_CTRL_IE; +  printf("I2C error\n"); +//TODO: set an error flag instead of just dropping things on the floor +  i2c_regs->cmd_status = I2C_CMD_STOP; +} + +bool i2c_async_read(uint8_t addr, unsigned int len) { +  //printf("Starting async read\n"); +  if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle +  if(len == 0) return true; //just idiot-proofing +  if(len > sizeof(i2c_buf)) return false; + +  //disable I2C interrupts and clear pending interrupts on the I2C device +  i2c_regs->ctrl &= ~I2C_CTRL_IE; +  i2c_regs->cmd_status |= I2C_CMD_IACK; + +  i2c_len = len; +  i2c_dir = I2C_DIR_READ; +  i2c_bufptr = i2c_buf; +  //then set up the transfer by issuing the control byte +  i2c_regs->ctrl |= I2C_CTRL_IE; +  i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit +  i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr +  //update the state so the irq handler knows what's going on +  i2c_state = I2C_STATE_CONTROL_BYTE_SENT; +  return true; +} + +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { +  //printf("Starting async write\n"); +  if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle +  if(len > sizeof(i2c_buf)) return false; + +  //disable I2C interrupts and clear pending interrupts on the I2C device +  i2c_regs->ctrl &= ~I2C_CTRL_IE; +  i2c_regs->cmd_status |= I2C_CMD_IACK; + +  //copy the buffer into our own if writing +  memcpy((void *)i2c_buf, buf, len); + +  i2c_len = len; +  i2c_dir = I2C_DIR_WRITE; +  i2c_bufptr = i2c_buf; +  //then set up the transfer by issuing the control byte +  i2c_regs->ctrl |= I2C_CTRL_IE; +  i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit +  i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr +  //update the state so the irq handler knows what's going on +  i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + +  return true; +} + +//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request. +bool i2c_async_data_ready(void *buf) { +  if(i2c_state == I2C_STATE_DATA_READY) { +    i2c_state = I2C_STATE_IDLE; +    memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this +    //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf); +    return true; +  } +  return false; +} + diff --git a/firmware/microblaze/lib/i2c_async.h b/firmware/microblaze/lib/i2c_async.h new file mode 100644 index 000000000..e6095fca6 --- /dev/null +++ b/firmware/microblaze/lib/i2c_async.h @@ -0,0 +1,50 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_I2C_ASYNC_H +#define INCLUDED_I2C_ASYNC_H + +#include <stdbool.h> +#include "stdint.h" + +typedef enum { I2C_STATE_IDLE,  +               I2C_STATE_CONTROL_BYTE_SENT,  +               I2C_STATE_DATA,  +               I2C_STATE_LAST_BYTE,  +               I2C_STATE_DATA_READY,  +               I2C_STATE_ERROR  +             } i2c_state_t; + +typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t; + +bool i2c_async_read(uint8_t addr, unsigned int len); +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len); +bool i2c_async_data_ready(void *); +//static void i2c_irq_handler(unsigned irq); +void i2c_register_callback(void (*callback)(void)); +void i2c_register_handler(void); + +// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. +// Which EEPROM is determined by i2c_addr.  See i2c_addr.h + +bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void)); +bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void)); + +#endif /* INCLUDED_I2C_ASYNC_H */ diff --git a/firmware/microblaze/lib/if_arp.h b/firmware/microblaze/lib/if_arp.h new file mode 100644 index 000000000..63519c4be --- /dev/null +++ b/firmware/microblaze/lib/if_arp.h @@ -0,0 +1,153 @@ +/* + * INET		An implementation of the TCP/IP protocol suite for the LINUX + *		operating system.  INET is implemented using the  BSD Socket + *		interface as the means of communication with the user level. + * + *		Global definitions for the ARP (RFC 826) protocol. + * + * Version:	@(#)if_arp.h	1.0.1	04/16/93 + * + * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + *		Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. + *		Ross Biro + *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + *		Florian La Roche, + *		Jonathan Layes <layes@loran.com> + *		Arnaldo Carvalho de Melo <acme@conectiva.com.br> ARPHRD_HWX25 + * + *		This program 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. + */ +#ifndef _LINUX_IF_ARP_H +#define _LINUX_IF_ARP_H + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM	0		/* from KA9Q: NET/ROM pseudo	*/ +#define ARPHRD_ETHER 	1		/* Ethernet 10Mbps		*/ +#define	ARPHRD_EETHER	2		/* Experimental Ethernet	*/ +#define	ARPHRD_AX25	3		/* AX.25 Level 2		*/ +#define	ARPHRD_PRONET	4		/* PROnet token ring		*/ +#define	ARPHRD_CHAOS	5		/* Chaosnet			*/ +#define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/ +#define	ARPHRD_ARCNET	7		/* ARCnet			*/ +#define	ARPHRD_APPLETLK	8		/* APPLEtalk			*/ +#define ARPHRD_DLCI	15		/* Frame Relay DLCI		*/ +#define ARPHRD_ATM	19		/* ATM 				*/ +#define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/ +#define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/ +#define ARPHRD_EUI64	27		/* EUI-64                       */ +#define ARPHRD_INFINIBAND 32		/* InfiniBand			*/ + +/* Dummy types for non ARP hardware */ +#define ARPHRD_SLIP	256 +#define ARPHRD_CSLIP	257 +#define ARPHRD_SLIP6	258 +#define ARPHRD_CSLIP6	259 +#define ARPHRD_RSRVD	260		/* Notional KISS type 		*/ +#define ARPHRD_ADAPT	264 +#define ARPHRD_ROSE	270 +#define ARPHRD_X25	271		/* CCITT X.25			*/ +#define ARPHRD_HWX25	272		/* Boards with X.25 in firmware	*/ +#define ARPHRD_CAN	280		/* Controller Area Network      */ +#define ARPHRD_PPP	512 +#define ARPHRD_CISCO	513		/* Cisco HDLC	 		*/ +#define ARPHRD_HDLC	ARPHRD_CISCO +#define ARPHRD_LAPB	516		/* LAPB				*/ +#define ARPHRD_DDCMP    517		/* Digital's DDCMP protocol     */ +#define ARPHRD_RAWHDLC	518		/* Raw HDLC			*/ + +#define ARPHRD_TUNNEL	768		/* IPIP tunnel			*/ +#define ARPHRD_TUNNEL6	769		/* IP6IP6 tunnel       		*/ +#define ARPHRD_FRAD	770             /* Frame Relay Access Device    */ +#define ARPHRD_SKIP	771		/* SKIP vif			*/ +#define ARPHRD_LOOPBACK	772		/* Loopback device		*/ +#define ARPHRD_LOCALTLK 773		/* Localtalk device		*/ +#define ARPHRD_FDDI	774		/* Fiber Distributed Data Interface */ +#define ARPHRD_BIF      775             /* AP1000 BIF                   */ +#define ARPHRD_SIT	776		/* sit0 device - IPv6-in-IPv4	*/ +#define ARPHRD_IPDDP	777		/* IP over DDP tunneller	*/ +#define ARPHRD_IPGRE	778		/* GRE over IP			*/ +#define ARPHRD_PIMREG	779		/* PIMSM register interface	*/ +#define ARPHRD_HIPPI	780		/* High Performance Parallel Interface */ +#define ARPHRD_ASH	781		/* Nexus 64Mbps Ash		*/ +#define ARPHRD_ECONET	782		/* Acorn Econet			*/ +#define ARPHRD_IRDA 	783		/* Linux-IrDA			*/ +/* ARP works differently on different FC media .. so  */ +#define ARPHRD_FCPP	784		/* Point to point fibrechannel	*/ +#define ARPHRD_FCAL	785		/* Fibrechannel arbitrated loop */ +#define ARPHRD_FCPL	786		/* Fibrechannel public loop	*/ +#define ARPHRD_FCFABRIC	787		/* Fibrechannel fabric		*/ +	/* 787->799 reserved for fibrechannel media types */ +#define ARPHRD_IEEE802_TR 800		/* Magic type ident for TR	*/ +#define ARPHRD_IEEE80211 801		/* IEEE 802.11			*/ +#define ARPHRD_IEEE80211_PRISM 802	/* IEEE 802.11 + Prism2 header  */ +#define ARPHRD_IEEE80211_RADIOTAP 803	/* IEEE 802.11 + radiotap header */ + +#define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */ +#define ARPHRD_NONE	  0xFFFE	/* zero header length */ + +/* ARP protocol opcodes. */ +#define	ARPOP_REQUEST	1		/* ARP request			*/ +#define	ARPOP_REPLY	2		/* ARP reply			*/ +#define	ARPOP_RREQUEST	3		/* RARP request			*/ +#define	ARPOP_RREPLY	4		/* RARP reply			*/ +#define	ARPOP_InREQUEST	8		/* InARP request		*/ +#define	ARPOP_InREPLY	9		/* InARP reply			*/ +#define	ARPOP_NAK	10		/* (ATM)ARP NAK			*/ + + +/* ARP Flag values. */ +#define ATF_COM		0x02		/* completed entry (ha valid)	*/ +#define	ATF_PERM	0x04		/* permanent entry		*/ +#define	ATF_PUBL	0x08		/* publish entry		*/ +#define	ATF_USETRAILERS	0x10		/* has requested trailers	*/ +#define ATF_NETMASK     0x20            /* want to use a netmask (only +					   for proxy entries) */ +#define ATF_DONTPUB	0x40		/* don't answer this addresses	*/ + +typedef unsigned short  __be16; + +/* + *	This structure defines an ethernet arp header. + */ +struct arphdr +{ +	__be16		ar_hrd;		/* format of hardware address	*/ +	__be16		ar_pro;		/* format of protocol address	*/ +	unsigned char	ar_hln;		/* length of hardware address	*/ +	unsigned char	ar_pln;		/* length of protocol address	*/ +	__be16		ar_op;		/* ARP opcode (command)		*/ + +#if 0 +	 /* +	  *	 Ethernet looks like this : This bit is variable sized however... +	  */ +	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/ +	unsigned char		ar_sip[4];		/* sender IP address		*/ +	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/ +	unsigned char		ar_tip[4];		/* target IP address		*/ +#endif + +}; + +/* + *	This structure defines an ethernet arp header. + */ +struct arp_eth_ipv4 +{ +	__be16		ar_hrd;		/* format of hardware address	*/ +	__be16		ar_pro;		/* format of protocol address	*/ +	unsigned char	ar_hln;		/* length of hardware address	*/ +	unsigned char	ar_pln;		/* length of protocol address	*/ +	__be16		ar_op;		/* ARP opcode (command)		*/ + +	unsigned char	ar_sha[6];	/* sender hardware address	*/ +	unsigned char	ar_sip[4];	/* sender IP address		*/ +	unsigned char	ar_tha[6];	/* target hardware address	*/ +	unsigned char	ar_tip[4];	/* target IP address		*/ +}; + + +#endif	/* _LINUX_IF_ARP_H */ diff --git a/firmware/microblaze/lib/ihex.c b/firmware/microblaze/lib/ihex.c new file mode 100644 index 000000000..97ecf73b6 --- /dev/null +++ b/firmware/microblaze/lib/ihex.c @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include "ihex.h" +#include <ctype.h> //man that pulls in a lot of shit + +//this is not safe and you should run isxdigit beforehand +uint8_t asc2nibble(char input) { +	if(input > 'Z') return input - 'W'; +	else if(input > '9') return input - '7'; +	else return input - '0'; +} + +int ihex_parse(char input[], ihex_record_t *record) { +	//given a NULL-TERMINATED input string (use gets()) in I16HEX format, write the binary record in record. return 0 on success. + +	uint8_t inputlen; +	uint8_t t, i, checksum_calc=0, checksum_read; + +	//first check for ":" leading character +	if(input[0] != ':') return -1; + +	//then check the string for only valid ASCII ['0'-'F'] +	inputlen=1; +	while(input[inputlen]) { +		if( !isxdigit(input[inputlen++]) ) return -2; +	} + +	//then read the length. +	record->length = (asc2nibble(input[1]) << 4) + asc2nibble(input[2]); +	if(input[(record->length<<1) + 11] != 0) return -3; //if we're missing a null terminator in the right place + +	//then read the address. +	record->addr = (asc2nibble(input[3]) << 12) + (asc2nibble(input[4]) << 8) + (asc2nibble(input[5]) << 4) + asc2nibble(input[6]); + +	//then read the record type. +	record->type = (asc2nibble(input[7]) << 4) + asc2nibble(input[8]); +//	if(record->type > 4) return -4; + +	//then read the data, which goes from input[9] to input[9+length*2]. +	for(i=0; i < record->length; i++) { +		t = 9 + (i<<1); +		record->data[i] = (asc2nibble(input[t]) << 4) + (asc2nibble(input[t + 1])); +		checksum_calc += record->data[i]; //might as well keep a running checksum as we read +	} +	checksum_calc += record->length + record->type + (record->addr >> 8) + (record->addr & 0xFF); //get the rest of the data into that checksum +	checksum_calc = ~checksum_calc + 1;	//checksum is 2's complement + +	//now read the checksum of the record +	checksum_read = (asc2nibble(input[9 + (record->length<<1)]) << 4) + asc2nibble(input[10 + (record->length<<1)]); +	if(checksum_calc != checksum_read) return -5; //compare 'em + +	return 0; +} diff --git a/firmware/microblaze/lib/ihex.h b/firmware/microblaze/lib/ihex.h new file mode 100644 index 000000000..9f471fbe2 --- /dev/null +++ b/firmware/microblaze/lib/ihex.h @@ -0,0 +1,18 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <stdint.h> +#include <stddef.h> + +typedef struct { +	uint8_t type; +	size_t length; +	uint32_t addr; +	uint8_t *data; +} ihex_record_t; + + +int ihex_parse(char input[], ihex_record_t *record); diff --git a/firmware/microblaze/lib/mdelay.c b/firmware/microblaze/lib/mdelay.c new file mode 100644 index 000000000..c8c119b1a --- /dev/null +++ b/firmware/microblaze/lib/mdelay.c @@ -0,0 +1,73 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "mdelay.h" +#include "memory_map.h" + +// Delay about one millisecond. +// +// Need 33,333 cycles at 33 MHz. +// Each time around the loop is 10 cycles +// + +#define LOOPCNT(wb_div) (MASTER_CLK_RATE/(wb_div) / 10000) + +inline static void +delay_1ms(int loop_count) +{ +  int	i; +  for (i = 0; i < loop_count; i++){ +    asm volatile ("or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n\ +		   or  r0, r0, r0\n"); +  } +} + +// delay about ms milliseconds +void +mdelay(int ms) +{ +  static int loop_count = -1; + +  if (hwconfig_simulation_p()) +    return; + +  if (loop_count < 0){ +    // set correct loop_count +    static unsigned short lc[8] = { +      0, +      LOOPCNT(1), +      LOOPCNT(2), +      LOOPCNT(3), +      LOOPCNT(4), +      LOOPCNT(5), +      LOOPCNT(6), +      LOOPCNT(7) +    }; + +    loop_count = lc[hwconfig_wishbone_divisor() & 0x7]; +  } + +  int i; +  for (i = 0; i < ms; i++) +    delay_1ms(loop_count); +} diff --git a/firmware/microblaze/lib/mdelay.h b/firmware/microblaze/lib/mdelay.h new file mode 100644 index 000000000..226bbb3f7 --- /dev/null +++ b/firmware/microblaze/lib/mdelay.h @@ -0,0 +1,29 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MDELAY_H +#define INCLUDED_MDELAY_H + +/*! + * \brief Delay about ms milliseconds + * + * If simulating, _very_ short delay + */ +void mdelay(int ms); + +#endif /* INCLUDED_MDELAY_H */ diff --git a/firmware/microblaze/lib/memcpy_wa.c b/firmware/microblaze/lib/memcpy_wa.c new file mode 100644 index 000000000..ef20efaa9 --- /dev/null +++ b/firmware/microblaze/lib/memcpy_wa.c @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "memcpy_wa.h" +#include <stdint.h> +#include <stdlib.h> + +/* + * For copying to/from non-byte-adressable memory, such as + * the buffers.  dst, src, and nbytes must all satisfy (x % 4 == 0) + */ +void +memcpy_wa(void *dst, const void *src, size_t nbytes) +{ +  if (((intptr_t) dst & 0x3) +      || ((intptr_t) src & 0x3) +      || (nbytes & 0x3)) +    exit(1);			/* die! */ + +  int *dp = (int *) dst; +  int *sp = (int *) src; +  unsigned  nw = nbytes/4; + +  unsigned i; +  for (i = 0; i < nw; i++) +    dp[i] = sp[i]; +} diff --git a/firmware/microblaze/lib/memcpy_wa.h b/firmware/microblaze/lib/memcpy_wa.h new file mode 100644 index 000000000..072fc148f --- /dev/null +++ b/firmware/microblaze/lib/memcpy_wa.h @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MEMCPY_WA_H +#define INCLUDED_MEMCPY_WA_H + +#include <stddef.h> + +/* + * For copying to/from non-byte-adressable memory, such as + * the buffers.  dst, src, and nbytes must all satisfy (x % 4 == 0) + */ +void memcpy_wa(void *dst, const void *src, size_t nbytes); + +#endif /* INCLUDED_MEMCPY_WA_H */ + + diff --git a/firmware/microblaze/lib/memset_wa.c b/firmware/microblaze/lib/memset_wa.c new file mode 100644 index 000000000..da5da21ab --- /dev/null +++ b/firmware/microblaze/lib/memset_wa.c @@ -0,0 +1,45 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "memset_wa.h" +#include <stdint.h> +#include <stdlib.h> + +/* + * For setting non-byte-adressable memory, such as + * the buffers.  dst and nbytes must all satisfy (x % 4 == 0) + */ +void * +memset_wa(void *dst, int c, size_t nbytes) +{ +  if (((intptr_t) dst & 0x3) +      || (nbytes & 0x3)) +    exit(1);			/* die! */ + +  int *dp = (int *) dst; + +  c &= 0xff; +  int v = (c << 24) | (c << 16) | (c << 8) | c; +  unsigned  nw = nbytes/4; + +  unsigned i; +  for (i = 0; i < nw; i++) +    dp[i] = v; + +  return dst; +} diff --git a/firmware/microblaze/lib/memset_wa.h b/firmware/microblaze/lib/memset_wa.h new file mode 100644 index 000000000..46d903d53 --- /dev/null +++ b/firmware/microblaze/lib/memset_wa.h @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MEMSET_WA_H +#define INCLUDED_MEMSET_WA_H + +#include <stdlib.h> + +void *memset_wa(void *s, int c, size_t n); + + +#endif /* INCLUDED_MEMSET_WA_H */ diff --git a/firmware/microblaze/lib/net/.gitignore b/firmware/microblaze/lib/net/.gitignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/firmware/microblaze/lib/net/.gitignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/firmware/microblaze/lib/net/eth_mac_addr.h b/firmware/microblaze/lib/net/eth_mac_addr.h new file mode 100644 index 000000000..b44fb68f7 --- /dev/null +++ b/firmware/microblaze/lib/net/eth_mac_addr.h @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETH_MAC_ADDR_H +#define INCLUDED_ETH_MAC_ADDR_H + +#include <stdint.h> + +// Ethernet MAC address + +typedef struct { +  uint8_t	addr[6]; +} eth_mac_addr_t; + +#endif /* INCLUDED_ETH_MAC_ADDR_H */ diff --git a/firmware/microblaze/lib/net/padded_eth_hdr.h b/firmware/microblaze/lib/net/padded_eth_hdr.h new file mode 100644 index 000000000..df816734f --- /dev/null +++ b/firmware/microblaze/lib/net/padded_eth_hdr.h @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_PADDED_ETH_HDR_H +#define INCLUDED_PADDED_ETH_HDR_H + +#include <compiler.h> +#include <net/eth_mac_addr.h> + +/*! + * \brief Standard 14-byte ethernet header plus two leading bytes of padding. + * + * This is what a buffer contains in line 1 when using the "slow mode" + */ +typedef struct { +  uint16_t	 pad; +  eth_mac_addr_t dst; +  eth_mac_addr_t src; +  uint16_t 	 ethertype; +} _AL4 padded_eth_hdr_t; + + +#endif /* INCLUDED_PADDED_ETH_HDR_H */ diff --git a/firmware/microblaze/lib/net/socket_address.h b/firmware/microblaze/lib/net/socket_address.h new file mode 100644 index 000000000..336f30a0c --- /dev/null +++ b/firmware/microblaze/lib/net/socket_address.h @@ -0,0 +1,41 @@ +/* -*- c -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_SOCKET_ADDRESS_H +#define INCLUDED_SOCKET_ADDRESS_H + +#include <lwip/ip_addr.h> + +// port and address are in network byte order + +typedef struct socket_address { +  unsigned short   port; +  struct ip_addr   addr; +} socket_address_t; + +static inline struct socket_address  +make_socket_address(struct ip_addr addr, int port) +{ +  struct socket_address r; +  r.port = port; +  r.addr = addr; +  return r; +} + + + +#endif /* INCLUDED_SOCKET_ADDRESS_H */ diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c new file mode 100644 index 000000000..6305408d6 --- /dev/null +++ b/firmware/microblaze/lib/net_common.c @@ -0,0 +1,474 @@ +/* -*- c -*- */ +/* + * Copyright 2009,2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "net_common.h" +#include "banal.h" +#include <hal_io.h> +#include <buffer_pool.h> +#include <memory_map.h> +#include <memcpy_wa.h> +#include <ethernet.h> +#include <net/padded_eth_hdr.h> +#include <lwip/ip.h> +#include <lwip/udp.h> +#include <lwip/icmp.h> +#include <stdlib.h> +#include <nonstdio.h> +#include "arp_cache.h" +#include "if_arp.h" +#include <ethertype.h> +#include <string.h> + + +int cpu_tx_buf_dest_port = PORT_ETH; + +// If this is non-zero, this dbsm could be writing to the ethernet +dbsm_t *ac_could_be_sending_to_eth; + +static inline bool +ip_addr_eq(const struct ip_addr a, const struct ip_addr b) +{ +  return a.addr == b.addr; +} + +// ------------------------------------------------------------------------ + +static eth_mac_addr_t _local_mac_addr; +void register_mac_addr(const eth_mac_addr_t *mac_addr){ +    _local_mac_addr = *mac_addr; +} + +static struct ip_addr _local_ip_addr; +void register_ip_addr(const struct ip_addr *ip_addr){ +    _local_ip_addr = *ip_addr; +} + +//------------------------------------------------------------------------- + +#define	MAX_UDP_LISTENERS	6 + +struct listener_entry { +  unsigned short	port; +  udp_receiver_t	rcvr; +}; + +static struct listener_entry listeners[MAX_UDP_LISTENERS]; + +static struct listener_entry * +find_listener_by_port(unsigned short port) +{ +  for (int i = 0; i < MAX_UDP_LISTENERS; i++){ +    if (port == listeners[i].port) +      return &listeners[i]; +  } +  return 0; +} + +static struct listener_entry * +find_free_listener(void) +{ +  for (int i = 0; i < MAX_UDP_LISTENERS; i++){ +    if (listeners[i].rcvr == 0) +      return &listeners[i]; +  } +  abort(); +} + +void +register_udp_listener(int port, udp_receiver_t rcvr) +{ +  struct listener_entry *lx = find_listener_by_port(port); +  if (lx) +    lx->rcvr = rcvr; +  else { +    lx = find_free_listener(); +    lx->port = port; +    lx->rcvr = rcvr; +  } +} + +// ------------------------------------------------------------------------ + + +/*! + * low level routine to assembly an ethernet frame and send it. + * + * \param dst destination mac address + * \param ethertype ethertype field + * \param buf0 first part of data + * \param len0 length of first part of data + * \param buf1 second part of data + * \param len1 length of second part of data + * \param buf2 third part of data + * \param len2 length of third part of data + */ +static void +send_pkt(eth_mac_addr_t dst, int ethertype, +	 const void *buf0, size_t len0, +	 const void *buf1, size_t len1, +	 const void *buf2, size_t len2) +{ +  // Wait for buffer to become idle +  // FIXME can this ever not be ready? + +  //hal_set_leds(LED_BUF_BUSY, LED_BUF_BUSY); +  while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0) +    ; +  //hal_set_leds(0, LED_BUF_BUSY); + +  // Assemble the header +  padded_eth_hdr_t	ehdr; +  ehdr.pad = 0; +  ehdr.dst = dst; +  ehdr.src = _local_mac_addr; +  ehdr.ethertype = ethertype; + +  uint32_t *p = buffer_ram(CPU_TX_BUF); + +  // Copy the pieces into the buffer +  *p++ = 0x0;  				  // slow path +  memcpy_wa(p, &ehdr, sizeof(ehdr));      // 4 lines +  p += sizeof(ehdr)/sizeof(uint32_t); + + +  // FIXME modify memcpy_wa to do read/modify/write if reqd + +  if (len0 && ((len0 & 0x3) || (intptr_t) buf0 & 0x3)) +    printf("send_pkt: bad alignment of len0 and/or buf0\n"); + +  if (len1 && ((len1 & 0x3) || (intptr_t) buf1 & 0x3)) +    printf("send_pkt: bad alignment of len1 and/or buf1\n"); + +  if (len2 && ((len2 & 0x3) || (intptr_t) buf2 & 0x3)) +    printf("send_pkt: bad alignment of len2 and/or buf2\n"); + +  if (len0){ +    memcpy_wa(p, buf0, len0); +    p += len0/sizeof(uint32_t); +  } +  if (len1){ +    memcpy_wa(p, buf1, len1); +    p += len1/sizeof(uint32_t); +  } +  if (len2){ +    memcpy_wa(p, buf2, len2); +    p += len2/sizeof(uint32_t); +  } + +  size_t total_len = (p - buffer_ram(CPU_TX_BUF)) * sizeof(uint32_t); +  if (total_len < 60)		// ensure that we don't try to send a short packet +    total_len = 60; +   +  // wait until nobody else is sending to the ethernet +  if (ac_could_be_sending_to_eth){ +    //hal_set_leds(LED_ETH_BUSY, LED_ETH_BUSY); +    dbsm_wait_for_opening(ac_could_be_sending_to_eth); +    //hal_set_leds(0x0, LED_ETH_BUSY); +  } + +  if (0){ +    printf("send_pkt to port %d, len = %d\n", +	   cpu_tx_buf_dest_port, (int) total_len); +    print_buffer(buffer_ram(CPU_TX_BUF), total_len/4); +  } + +  // fire it off +  bp_send_from_buf(CPU_TX_BUF, cpu_tx_buf_dest_port, 1, 0, total_len/4); + +  // wait for it to complete (not long, it's a small pkt) +  while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0) +    ; + +  bp_clear_buf(CPU_TX_BUF); +} + +unsigned int  +chksum_buffer(unsigned short *buf, int nshorts, unsigned int initial_chksum) +{ +  unsigned int chksum = initial_chksum; +  for (int i = 0; i < nshorts; i++) +    CHKSUM(buf[i], &chksum); + +  return chksum; +} + + +void +send_ip_pkt(struct ip_addr dst, int protocol, +	    const void *buf0, size_t len0, +	    const void *buf1, size_t len1) +{ +  int ttl = 32; + +  struct ip_hdr ip; +  IPH_VHLTOS_SET(&ip, 4, 5, 0); +  IPH_LEN_SET(&ip, IP_HLEN + len0 + len1); +  IPH_ID_SET(&ip, 0); +  IPH_OFFSET_SET(&ip, IP_DF);	/* don't fragment */ +  ip._ttl_proto = (ttl << 8) | (protocol & 0xff); +  ip._chksum = 0; +  ip.src = _local_ip_addr; +  ip.dest = dst; + +  ip._chksum = ~chksum_buffer((unsigned short *) &ip, +			      sizeof(ip)/sizeof(short), 0); + +  eth_mac_addr_t dst_mac; +  bool found = arp_cache_lookup_mac(&ip.dest, &dst_mac); +  if (!found){ +    printf("net_common: failed to hit cache looking for "); +    print_ip(ip.dest); +    newline(); +    return; +  } + +  send_pkt(dst_mac, ETHERTYPE_IPV4, +	   &ip, sizeof(ip), buf0, len0, buf1, len1); +} + +void  +send_udp_pkt(int src_port, struct socket_address dst, +	     const void *buf, size_t len) +{ +  struct udp_hdr udp _AL4; +  udp.src = src_port; +  udp.dest = dst.port; +  udp.len = UDP_HLEN + len; +  udp.chksum = 0; + +  send_ip_pkt(dst.addr, IP_PROTO_UDP, +	      &udp, sizeof(udp), buf, len); +} + +static void +handle_udp_packet(struct ip_addr src_ip, struct ip_addr dst_ip, +		  struct udp_hdr *udp, size_t len) +{ +  if (len != udp->len){ +    printf("UDP inconsistent lengths: %d %d\n", (int)len, udp->len); +    return; +  } + +  unsigned char *payload = ((unsigned char *) udp) + UDP_HLEN; +  int payload_len = len - UDP_HLEN; + +  if (0){ +    printf("\nUDP: src = %d  dst = %d  len = %d\n", +	   udp->src, udp->dest, udp->len); + +    //print_bytes(0, payload, payload_len); +  } + +  struct listener_entry *lx = find_listener_by_port(udp->dest); +  if (lx){ +    struct socket_address src = make_socket_address(src_ip, udp->src); +    struct socket_address dst = make_socket_address(dst_ip, udp->dest); +    lx->rcvr(src, dst, payload, payload_len); +  } +} + +static void +handle_icmp_packet(struct ip_addr src, struct ip_addr dst, +		   struct icmp_echo_hdr *icmp, size_t len) +{ +  switch (icmp->type){ +  case ICMP_DUR:	// Destinatino Unreachable +    if (icmp->code == ICMP_DUR_PORT){	// port unreachable +      //handle destination port unreachable (the host ctrl+c'd the app): + +      //end async update packets per second +      sr_tx_ctrl->cyc_per_up = 0; + +      //the end continuous streaming command +      sr_rx_ctrl->cmd = 1 << 31; //no samples now +      sr_rx_ctrl->time_secs = 0; +      sr_rx_ctrl->time_ticks = 0; //latch the command + +      //struct udp_hdr *udp = (struct udp_hdr *)((char *)icmp + 28); +      //printf("icmp port unr %d\n", udp->dest); +      putchar('i'); +    } +    else { +      //printf("icmp dst unr (code: %d)", icmp->code); +      putchar('i'); +    } +    break; + +  case ICMP_ECHO:{ +    struct icmp_echo_hdr echo_reply; +    echo_reply.type = 0; +    echo_reply.code = 0; +    echo_reply.chksum = 0; +    echo_reply.id = icmp->id; +    echo_reply.seqno = icmp->seqno; +    echo_reply.chksum = ~chksum_buffer( +        (unsigned short *)&echo_reply, +        sizeof(echo_reply)/sizeof(short), +    0); +    send_ip_pkt( +        src, IP_PROTO_ICMP, &echo_reply, sizeof(echo_reply), +        ((uint8_t*)icmp) + sizeof(struct icmp_echo_hdr), +        len - sizeof(struct icmp_echo_hdr) +    ); +    break; +  } +  default: +    break; +  } +} + +static void __attribute__((unused)) +print_arp_ip(const unsigned char ip[4]) +{ +  printf("%d.%d.%d.%d", ip[0], ip[1], ip[2],ip[3]); +} + +static void +send_arp_reply(struct arp_eth_ipv4 *req, eth_mac_addr_t our_mac) +{ +  struct arp_eth_ipv4 reply _AL4; +  reply.ar_hrd = req->ar_hrd; +  reply.ar_pro = req->ar_pro; +  reply.ar_hln = req->ar_hln; +  reply.ar_pln = req->ar_pln; +  reply.ar_op = ARPOP_REPLY; +  memcpy(reply.ar_sha, &our_mac, 6); +  memcpy(reply.ar_sip, req->ar_tip, 4); +  memcpy(reply.ar_tha, req->ar_sha, 6); +  memcpy(reply.ar_tip, req->ar_sip, 4); + +  eth_mac_addr_t t; +  memcpy(t.addr, reply.ar_tha, 6); +  send_pkt(t, ETHERTYPE_ARP, &reply, sizeof(reply), 0, 0, 0, 0); +} + +void send_gratuitous_arp(void){ +  struct arp_eth_ipv4 req _AL4; +  req.ar_hrd = ARPHRD_ETHER; +  req.ar_pro = ETHERTYPE_IPV4; +  req.ar_hln = sizeof(eth_mac_addr_t); +  req.ar_pln = sizeof(struct ip_addr); +  req.ar_op = ARPOP_REQUEST; +  memcpy(req.ar_sha, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); +  memcpy(req.ar_sip, get_ip_addr(),       sizeof(struct ip_addr)); +  memset(req.ar_tha, 0x00,                sizeof(eth_mac_addr_t)); +  memcpy(req.ar_tip, get_ip_addr(),       sizeof(struct ip_addr)); + +  //send the request with a broadcast ethernet mac address +  eth_mac_addr_t t; memset(&t, 0xff, sizeof(t)); +  send_pkt(t, ETHERTYPE_ARP, &req, sizeof(req), 0, 0, 0, 0); +} + +static void +handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) +{ +  if (size < sizeof(struct arp_eth_ipv4)){ +    printf("\nhandle_arp: weird size = %d\n", (int)size); +    return; +  } + +  if (0){ +    printf("ar_hrd = %d\n", p->ar_hrd); +    printf("ar_pro = %d\n", p->ar_pro); +    printf("ar_hln = %d\n", p->ar_hln); +    printf("ar_pln = %d\n", p->ar_pln); +    printf("ar_op  = %d\n", p->ar_op); +    printf("ar_sha = "); print_mac_addr(p->ar_sha); newline(); +    printf("ar_sip = "); print_arp_ip(p->ar_sip);    newline(); +    printf("ar_tha = "); print_mac_addr(p->ar_tha); newline(); +    printf("ar_tip = "); print_arp_ip(p->ar_tip);    newline(); +  } + +  if (p->ar_hrd != ARPHRD_ETHER +      || p->ar_pro != ETHERTYPE_IPV4 +      || p->ar_hln != 6 +      || p->ar_pln != 4) +    return; +   +  if (p->ar_op != ARPOP_REQUEST) +    return; + +  struct ip_addr sip; +  struct ip_addr tip; + +  sip.addr = get_int32(p->ar_sip); +  tip.addr = get_int32(p->ar_tip); + +  if (ip_addr_eq(tip, _local_ip_addr)){	// They're looking for us... +    send_arp_reply(p, _local_mac_addr); +  } +} + +void +handle_eth_packet(uint32_t *p, size_t nlines) +{ +  //print_buffer(p, nlines); + +  int ethertype = p[3] & 0xffff; + +  if (ethertype == ETHERTYPE_ARP){ +    struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(p + 4); +    handle_arp_packet(arp, nlines*sizeof(uint32_t) - 14); +  } +  else if (ethertype == ETHERTYPE_IPV4){ +    struct ip_hdr *ip = (struct ip_hdr *)(p + 4); +    if (IPH_V(ip) != 4 || IPH_HL(ip) != 5)	// ignore pkts w/ bad version or options +      return; + +    if (IPH_OFFSET(ip) & (IP_MF | IP_OFFMASK))	// ignore fragmented packets +      return; + +    // FIXME filter on dest ip addr (should be broadcast or for us) + +    arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)p)+8)); + +    int protocol = IPH_PROTO(ip); +    int len = IPH_LEN(ip) - IP_HLEN; + +    switch (protocol){ +    case IP_PROTO_UDP: +      handle_udp_packet(ip->src, ip->dest, (struct udp_hdr *)(((char *)ip) + IP_HLEN), len); +      break; + +    case IP_PROTO_ICMP: +      handle_icmp_packet(ip->src, ip->dest, (struct icmp_echo_hdr *)(((char *)ip) + IP_HLEN), len); +      break; + +    default:	// ignore +      break; +    } +  } +  else +    return;	// Not ARP or IPV4, ignore +} + +// ------------------------------------------------------------------------ + +void +print_ip(struct ip_addr ip) +{ +  unsigned int t = ntohl(ip.addr); +  printf("%d.%d.%d.%d", +	 (t >> 24) & 0xff, +	 (t >> 16) & 0xff, +	 (t >>  8) & 0xff, +	 t & 0xff); +} diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h new file mode 100644 index 000000000..3040e5ef3 --- /dev/null +++ b/firmware/microblaze/lib/net_common.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_NET_COMMON_H +#define INCLUDED_NET_COMMON_H + +#include <stdint.h> +#include <stddef.h> +#include <dbsm.h> +#include <net/socket_address.h> +#include <net/eth_mac_addr.h> + +#define CPU_TX_BUF 	7	// cpu -> eth + +extern int cpu_tx_buf_dest_port; + +// If this is non-zero, this dbsm could be writing to the ethernet +extern dbsm_t *ac_could_be_sending_to_eth; + +void stop_streaming(void); + +typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst, +			       unsigned char *payload, int payload_len); + +void register_mac_addr(const eth_mac_addr_t *mac_addr); + +void register_ip_addr(const struct ip_addr *ip_addr); + +void register_udp_listener(int port, udp_receiver_t rcvr); + +void send_udp_pkt(int src_port, struct socket_address dst, +		  const void *buf, size_t len); + +void handle_eth_packet(uint32_t *p, size_t nlines); + +void send_gratuitous_arp(void); + +#endif /* INCLUDED_NET_COMMON_H */ diff --git a/firmware/microblaze/lib/nonstdio.c b/firmware/microblaze/lib/nonstdio.c new file mode 100644 index 000000000..4b5fa4123 --- /dev/null +++ b/firmware/microblaze/lib/nonstdio.c @@ -0,0 +1,123 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <nonstdio.h> + +static const char hex[16] = "0123456789ABCDEF"; + +// %x +void +puthex4(unsigned long x) +{ +  putchar(hex[x & 0xf]); +} + +// %02x +void  +puthex8(unsigned long x) +{ +  putchar(hex[(x >> 4) & 0xf]); +  putchar(hex[x & 0xf]); +} + +// %04x +void  +puthex16(unsigned long x) +{ +  puthex8(x >> 8); +  puthex8(x); +} + +// %08x +void  +puthex32(unsigned long x) +{ +  puthex16(x >> 16); +  puthex16(x); +} + +void  +puthex4_nl(unsigned long x) +{ +  puthex4(x); +  newline(); +} + +void  +puthex8_nl(unsigned long x) +{ +  puthex8(x); +  newline(); +} + +void  +puthex16_nl(unsigned long x) +{ +  puthex16(x); +  newline(); +} + +void  +puthex32_nl(unsigned long x) +{ +  puthex32(x); +  newline(); +} +/* +void reverse(char s[]) +{ +    int c, i, j; + +    for (i = 0, j = strlen(s)-1; i<j; i++, j--) { +        c = s[i]; +        s[i] = s[j]; +        s[j] = c; +    } +} + +int abs(signed long value) { +	return (value >= 0) ? value : 0-value; +} + +//we'll keep the puthex functions above because they're way more lightweight. but sometimes you just want to print in decimal, you know? +char *itoa(signed long value, char *result, int base) +{ +	// check that the base if valid +	if (base < 2 || base > 16) { *result = 0; return result; } + +	char* out = result; +	signed long quotient = value; + +	do { +		*out = hex[ abs(quotient % base) ]; +		++out; +		quotient /= base; +	} while ( quotient ); + +	// Only apply negative sign for base 10 +	if ( value < 0 && base == 10) *out++ = '-'; + +	*out = 0; +	reverse( result ); + +	return result; + +} +*/ + + diff --git a/firmware/microblaze/lib/nonstdio.h b/firmware/microblaze/lib/nonstdio.h new file mode 100644 index 000000000..62ebfa46d --- /dev/null +++ b/firmware/microblaze/lib/nonstdio.h @@ -0,0 +1,48 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_NONSTDIO_H +#define INCLUDED_NONSTDIO_H + +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> + +void putstr(const char *s);		// cf puts, no added newline +void puthex4(unsigned long x);		// output 1 hex digit +void puthex8(unsigned long x);		// output 2 hex digits +void puthex16(unsigned long x);		// output 4 hex digits +void puthex32(unsigned long x);		// output 8 hex digits +void puthex4_nl(unsigned long x);	// ... followed by newline +void puthex8_nl(unsigned long x); +void puthex16_nl(unsigned long x); +void puthex32_nl(unsigned long x); +#define puthex puthex32 +#define puthex_nl puthex32_nl +void newline();				// putchar('\n') + +void print_mac_addr(const unsigned char addr[6]); +void print_uint64(uint64_t v); + +void print_buffer(uint32_t *buf, size_t n); +//char *itoa(signed long value, char *result, int base); +//void reverse(char s[]); + +#endif /* INCLUDED_NONSTDIO_H */ diff --git a/firmware/microblaze/lib/pic.c b/firmware/microblaze/lib/pic.c new file mode 100644 index 000000000..226da5f85 --- /dev/null +++ b/firmware/microblaze/lib/pic.c @@ -0,0 +1,94 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "pic.h" +#include "hal_io.h" +#include "memory_map.h" + + +#define NVECTORS 8 + +/* + * Our secondary interrupt vector. + */ +irq_handler_t pic_vector[NVECTORS] = { +  nop_handler, +  nop_handler, +  nop_handler, +  nop_handler, +  nop_handler, +  nop_handler, +  nop_handler, +  nop_handler +}; + + +void +pic_init(void) +{ +  // uP is level triggered + +  pic_regs->mask = ~0;				       // mask all interrupts +  pic_regs->edge_enable = PIC_ONETIME_INT | PIC_UNDERRUN_INT | PIC_OVERRUN_INT | PIC_PPS_INT; +  pic_regs->polarity = ~0 & ~PIC_PHY_INT;	       // rising edge +  pic_regs->pending = ~0;			       // clear all pending ints +} + +/* + * This magic gets pic_interrupt_handler wired into the + * system interrupt handler with the appropriate prologue and + * epilogue. + */ +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ +  // pending and not masked interrupts +  int live = pic_regs->pending & ~pic_regs->mask; + +  // FIXME loop while there are interrupts to service. +  //   That will reduce our overhead. + +  // handle the first one set +  int i; +  int mask; +  for (i=0, mask=1; i < NVECTORS; i++, mask <<= 1){ +    if (mask & live){		// handle this one +      // puthex_nl(i); +      (*pic_vector[i])(i); +      pic_regs->pending = mask;	// clear pending interrupt +      return; +    } +  } +} + +void +pic_register_handler(unsigned irq, irq_handler_t handler) +{ +  if (irq >= NVECTORS) +    return; +  pic_vector[irq] = handler; + +  pic_regs->mask &= ~IRQ_TO_MASK(irq); +} + +void +nop_handler(unsigned irq) +{ +  // nop +} diff --git a/firmware/microblaze/lib/pic.h b/firmware/microblaze/lib/pic.h new file mode 100644 index 000000000..68918f9ad --- /dev/null +++ b/firmware/microblaze/lib/pic.h @@ -0,0 +1,35 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_PIC_H +#define INCLUDED_PIC_H + +typedef void (*irq_handler_t)(unsigned irq); + +void pic_init(void); +void pic_register_handler(unsigned irq, irq_handler_t handler); + +void nop_handler(unsigned irq);	// default handler does nothing + +// FIXME inline assembler +int  pic_disable_interrupts(); +int  pic_enable_interrupts(); +void pic_restore_interrupts(int prev_status); + + +#endif /* INCLUDED_PIC_H */ diff --git a/firmware/microblaze/lib/print_buffer.c b/firmware/microblaze/lib/print_buffer.c new file mode 100644 index 000000000..9f9104bb5 --- /dev/null +++ b/firmware/microblaze/lib/print_buffer.c @@ -0,0 +1,36 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#include <nonstdio.h> + +void +print_buffer(uint32_t *buf, size_t n) +{ +  size_t i; +  for (i = 0; i < n; i++){ +    if (i % 4 == 0) +      puthex16(i * 4); + +    putchar(' '); +    puthex32(buf[i]); +    if (i % 4 == 3) +      newline(); +  } + +  newline(); +} + diff --git a/firmware/microblaze/lib/print_mac_addr.c b/firmware/microblaze/lib/print_mac_addr.c new file mode 100644 index 000000000..475082325 --- /dev/null +++ b/firmware/microblaze/lib/print_mac_addr.c @@ -0,0 +1,28 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#include "nonstdio.h" + +void +print_mac_addr(const unsigned char addr[6]) +{ +  for(size_t i = 0; i < 6; i++){ +    if(i) putchar(':'); +    puthex8(addr[i]); +  } +} + diff --git a/firmware/microblaze/lib/print_rmon_regs.c b/firmware/microblaze/lib/print_rmon_regs.c new file mode 100644 index 000000000..6d9986909 --- /dev/null +++ b/firmware/microblaze/lib/print_rmon_regs.c @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "print_rmon_regs.h" +#include "eth_mac.h" +#include "nonstdio.h" + +void +print_rmon_regs(void) +{ +  int i; +  for (i=0; i <= 0x10; i++){ +    putstr("RMON[0x"); +    puthex8(i); +    putstr("] = "); +    printf("%d\n", eth_mac_read_rmon(i)); +  } + +  for (i=0x20; i <= 0x30; i++){ +    putstr("RMON[0x"); +    puthex8(i); +    putstr("] = "); +    printf("%d\n", eth_mac_read_rmon(i)); +  } +} diff --git a/firmware/microblaze/lib/print_rmon_regs.h b/firmware/microblaze/lib/print_rmon_regs.h new file mode 100644 index 000000000..44e52da84 --- /dev/null +++ b/firmware/microblaze/lib/print_rmon_regs.h @@ -0,0 +1,24 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_PRINT_RMON_REGS_H +#define INCLUDED_PRINT_RMON_REGS_H + +void print_rmon_regs(void); + +#endif /* INCLUDED_PRINT_RMON_REGS_H */ diff --git a/firmware/microblaze/lib/printf.c b/firmware/microblaze/lib/printf.c new file mode 100644 index 000000000..45bd57cb9 --- /dev/null +++ b/firmware/microblaze/lib/printf.c @@ -0,0 +1,134 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Based on code from the SDCC z80 library ;) + */ + +#include <stdarg.h> +#include <stdio.h> + +static void  +_printn(unsigned u, unsigned base, char issigned, +	void (*emitter)(char, void *), void *pData) +{ +  const char *_hex = "0123456789ABCDEF"; +  if (issigned && ((int)u < 0)) { +    (*emitter)('-', pData); +    u = (unsigned)-((int)u); +  } +  if (u >= base) +    _printn(u/base, base, 0, emitter, pData); +  (*emitter)(_hex[u%base], pData); +} + +static void  +_printf(const char *format, void (*emitter)(char, void *), +	void *pData, va_list va) +{ +  while (*format) { +    if (*format != '%') +      (*emitter)(*format, pData); +    else { +      switch (*++format) { +      case 0:			/* hit end of format string */ +	return; +      case 'c': +	{ +	  char c = (char)va_arg(va, int); +	  (*emitter)(c, pData); +	  break; +	} +      case 'u': +	{ +	  unsigned u = va_arg(va, unsigned); +	  _printn(u, 10, 0, emitter, pData); +	  break; +	} +      case 'd': +	{ +	  unsigned u = va_arg(va, unsigned); +	  _printn(u, 10, 1, emitter, pData); +	  break; +	} +      case 'x': +      case 'p': +	{ +	  unsigned u = va_arg(va, unsigned); +	  _printn(u, 16, 0, emitter, pData); +	  break; +	} +      case 's': +	{ +	  char *s = va_arg(va, char *); +	  while (*s) { +	    (*emitter)(*s, pData); +	    s++; +	  } +	  break; +	} +      } +    } +    format++; +  } +} + +static void  +_char_emitter(char c, void *pData __attribute__((unused))) +{ +  putchar(c); +} + +int  +printf(const char *format, ...) +{ +  va_list va; +  va_start(va, format); + +  _printf(format, _char_emitter, NULL, va); + +  va_end(va); + +  // wrong return value... +  return 0; +} + + +#if 0 + +// Totally dangerous.  Don't use +static void  +_buf_emitter(char c, void *pData) +{ +  *((*((char **)pData)))++ = c; +} + +int sprintf(char *pInto, const char *format, ...) +{ +  va_list va; +  va_start(va, format); + +  _printf(format, _buf_emitter, &pInto, va); +  *pInto++ = '\0'; + +  va_end(va); + +  // FIXME wrong return value +  return 0; +} +#endif diff --git a/firmware/microblaze/lib/printf.c.smaller b/firmware/microblaze/lib/printf.c.smaller new file mode 100644 index 000000000..4d858648d --- /dev/null +++ b/firmware/microblaze/lib/printf.c.smaller @@ -0,0 +1,134 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Based on code from the SDCC z80 library ;) + */ + +#include <stdarg.h> +#include <stdio.h> +#include <hal_io.h>		/* FIXME refactor into stdio */ + +#define PUTCHAR(x) hal_putc(x) + + +static void  +_printn(unsigned u, unsigned base, char issigned) +{ +  const char *_hex = "0123456789ABCDEF"; +  if (issigned && ((int)u < 0)) { +    PUTCHAR('-'); +    u = (unsigned)-((int)u); +  } +  if (u >= base) +    _printn(u/base, base, 0); +  PUTCHAR(_hex[u%base]); +} + +static void  +_printf(const char *format, va_list va) +{ +  while (*format) { +    if (*format != '%') +      PUTCHAR(*format); +    else { +      switch (*++format) { +      case 0:			/* hit end of format string */ +	return; +      case 'c': +	{ +	  char c = (char)va_arg(va, int); +	  PUTCHAR(c); +	  break; +	} +      case 'u': +	{ +	  unsigned u = va_arg(va, unsigned); +	  _printn(u, 10, 0); +	  break; +	} +      case 'd': +	{ +	  unsigned u = va_arg(va, unsigned); +	  _printn(u, 10, 1); +	  break; +	} +      case 'x': +      case 'p': +	{ +	  unsigned u = va_arg(va, unsigned); +	  _printn(u, 16, 0); +	  break; +	} +      case 's': +	{ +	  char *s = va_arg(va, char *); +	  while (*s) { +	    PUTCHAR(*s); +	    s++; +	  } +	  break; +	} +      } +    } +    format++; +  } +} + +#if 0 +static void  +_char_emitter(char c, void *pData __attribute__((unused))) +{ +  hal_putc(c); +} +#endif + +int  +printf(const char *format, ...) +{ +  va_list va; +  va_start(va, format); + +  _printf(format, va); + +  // wrong return value... +  return 0; +} + + +#if 0 + +// Totally dangerous.  Don't use +static void  +_buf_emitter(char c, void *pData) +{ +  *((*((char **)pData)))++ = c; +} + +int sprintf(char *pInto, const char *format, ...) +{ +  va_list va; +  va_start(va, format); + +  _printf(format, _buf_emitter, &pInto, va); +  *pInto++ = '\0'; + +  // FIXME wrong return value +  return 0; +} +#endif diff --git a/firmware/microblaze/lib/spi.c b/firmware/microblaze/lib/spi.c new file mode 100644 index 000000000..2a41a1bfa --- /dev/null +++ b/firmware/microblaze/lib/spi.c @@ -0,0 +1,108 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "spi.h" +#include "memory_map.h" +#include "pic.h" +#include "nonstdio.h" + +void (*volatile spi_callback)(void); //SPI callback when xfer complete. + +static void spi_irq_handler(unsigned irq); + +void +spi_init(void)  +{ +  /* +   * f_sclk = f_wb / ((div + 1) * 2) +   */ +  spi_regs->div = 1;  // 0 = Div by 2 (25 MHz); 1 = Div-by-4 (12.5 MHz) +} + +void +spi_wait(void)  +{ +  while (spi_regs->ctrl & SPI_CTRL_GO_BSY) +    ; +} + +uint32_t +spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags)  +{ +  flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); +  int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + +  spi_wait(); + +  // Tell it which SPI slave device to access +  spi_regs->ss = slave & 0xffff; + +  // Data we will send +  spi_regs->txrx0 = data; + +  // Run it -- write once and rewrite with GO set +  spi_regs->ctrl = ctrl; +  spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + +  if(readback) { +    spi_wait(); +    return spi_regs->txrx0; +  } +  else +    return 0; +} + +void spi_register_callback(void (*volatile callback)(void)) { +  spi_callback = callback; +} + +static void spi_irq_handler(unsigned irq) { +//  printf("SPI IRQ handler\n"); +//  uint32_t wat = spi_regs->ctrl; //read a register just to clear the interrupt +  //spi_regs->ctrl &= ~SPI_CTRL_IE; +  if(spi_callback) spi_callback(); //we could just use the PIC to register the user's callback, but this provides the ability to do other things later +} + +uint32_t spi_get_data(void) { +  return spi_regs->txrx0; +} + +bool  +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)) { +  flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); +  int ctrl = SPI_CTRL_ASS | SPI_CTRL_IE | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + +  if(spi_regs->ctrl & SPI_CTRL_GO_BSY) { +    printf("Async SPI busy!\n"); +    return false; //we don't wait on busy, we just return failure. we count on the host to not set up another transaction before the last one finishes. +  } + +  // Tell it which SPI slave device to access +  spi_regs->ss = slave & 0xffff; + +  // Data we will send +  spi_regs->txrx0 = data; + +  spi_register_callback(callback); +  pic_register_handler(IRQ_SPI, spi_irq_handler); + +  // Run it -- write once and rewrite with GO set +  spi_regs->ctrl = ctrl; +  spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + +  return true; +} diff --git a/firmware/microblaze/lib/spi.h b/firmware/microblaze/lib/spi.h new file mode 100644 index 000000000..54618cedd --- /dev/null +++ b/firmware/microblaze/lib/spi.h @@ -0,0 +1,77 @@ +/* -*- c -*- */ +/* + * Copyright 2006,2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_SPI_H +#define INCLUDED_SPI_H + +#include <memory_map.h> +#include <stdbool.h> + +/*! + * \brief One time call to initialize SPI + */ +void spi_init(void); + +/*!  + * \brief Wait for last SPI transaction to complete. + * Unless you need to know it completed, it's not necessary to call this. + */ +void spi_wait(void); + +#define SPI_TXONLY false	// readback: no +#define SPI_TXRX   true		// readback: yes + +/* + * Flags for spi_transact + */ +#define SPIF_PUSH_RISE   0		// push tx data on rising edge of SCLK +#define SPIF_PUSH_FALL   SPI_CTRL_TXNEG	// push tx data on falling edge of SCLK +#define SPIF_LATCH_RISE  0		// latch rx data on rising edge of SCLK +#define SPIF_LATCH_FALL  SPI_CTRL_RXNEG	// latch rx data on falling edge of SCLK + + +uint32_t +spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); + +uint32_t spi_get_data(void); +//static void spi_irq_handler(unsigned irq); +void spi_register_callback(void (*volatile callback)(void)); + +bool  +spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)); + +// ---------------------------------------------------------------- +// Routines that manipulate the FLASH SPI BUS +// ---------------------------------------------------------------- + +/*! + * \brief One time call to initialize SPI + */ +void spif_init(void); + +/*!  + * \brief Wait for last SPI transaction to complete. + * Unless you need to know it completed, it's not necessary to call this. + */ +void spif_wait(void); + +uint32_t +spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags); + + +#endif /* INCLUDED_SPI_H */ diff --git a/firmware/microblaze/lib/stdint.h b/firmware/microblaze/lib/stdint.h new file mode 100644 index 000000000..b5a8611a9 --- /dev/null +++ b/firmware/microblaze/lib/stdint.h @@ -0,0 +1,34 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_STDINT_H +#define INCLUDED_STDINT_H + +typedef signed char	int8_t; +typedef unsigned char	uint8_t; +typedef short		int16_t; +typedef unsigned short	uint16_t; +typedef int		int32_t; +typedef unsigned int	uint32_t; +typedef long long int		int64_t; +typedef unsigned long long int	uint64_t; + +typedef int		intptr_t; +typedef unsigned int	uintptr_t; + +#endif /* INCLUDED_STDINT_H */ diff --git a/firmware/microblaze/lib/stdio.h b/firmware/microblaze/lib/stdio.h new file mode 100644 index 000000000..12a7ed0bb --- /dev/null +++ b/firmware/microblaze/lib/stdio.h @@ -0,0 +1,38 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_STDIO_H +#define INCLUDED_STDIO_H + +// very trimmed down stdio.h  See also nonstdio.h + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef EOF +#define EOF (-1) +#endif + +int putchar(int c); +int puts(const char *s); +int printf(const char *format, ...); + +int getchar(void); + +#endif /* INCLUDED_STDIO_H */ diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c new file mode 100644 index 000000000..4a553a713 --- /dev/null +++ b/firmware/microblaze/lib/u2_init.c @@ -0,0 +1,90 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "pic.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "hal_uart.h" +#include "i2c.h" +#include "i2c_async.h" +#include "mdelay.h" +#include "clocks.h" +#include "usrp2/fw_common.h" +#include "nonstdio.h" + +unsigned char u2_hw_rev_major; +unsigned char u2_hw_rev_minor; + +static inline void +get_hw_rev(void) +{ +  bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV, &u2_hw_rev_minor, 1); +  ok &= eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV+1, &u2_hw_rev_major, 1); +} + +/* + * We ought to arrange for this to be called before main, but for now, + * we require that the user's main call u2_init as the first thing... + */ +bool +u2_init(void) +{ +  hal_disable_ints(); +  hal_io_init(); + +  // init spi, so that we can switch over to the high-speed clock +  spi_init(); + +  // set up the default clocks +  clocks_init(); + +  hal_uart_init(); + +  // init i2c so we can read our rev +  pic_init();	// progammable interrupt controller +  i2c_init(); +  i2c_register_handler(); //for using async I2C +  hal_enable_ints(); + +  bp_init();	// buffer pool +   + + +  // flash all leds to let us know board is alive +  hal_set_leds(0x0, 0x1f); +  mdelay(100); +  hal_set_leds(0x1f, 0x1f); +  mdelay(100); +  hal_set_leds(LED_D, 0x1f);  // Leave one on + +#if 0 +  // test register readback +  int rr, vv; +  vv = ad9777_read_reg(0); +  printf("ad9777 reg[0] = 0x%x\n", vv); +   +  for (rr = 0x04; rr <= 0x0d; rr++){ +    vv = ad9510_read_reg(rr); +    printf("ad9510 reg[0x%x] = 0x%x\n", rr, vv); +  } +#endif +   +  return true; +} diff --git a/firmware/microblaze/lib/u2_init.h b/firmware/microblaze/lib/u2_init.h new file mode 100644 index 000000000..848bd88de --- /dev/null +++ b/firmware/microblaze/lib/u2_init.h @@ -0,0 +1,28 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_U2_INIT_H +#define INCLUDED_U2_INIT_H + +#include <stdbool.h> + +/*! + * one-time init + */ +bool u2_init(void); + +#endif /* INCLUDED_U2_INIT_H */ diff --git a/firmware/microblaze/lib/udp_fw_update.h b/firmware/microblaze/lib/udp_fw_update.h new file mode 100644 index 000000000..d25525bd2 --- /dev/null +++ b/firmware/microblaze/lib/udp_fw_update.h @@ -0,0 +1,71 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "net_common.h" + +#define USRP2_UDP_UPDATE_PORT 49154 + +typedef enum { +  USRP2_FW_UPDATE_ID_WAT = ' ', + +  USRP2_FW_UPDATE_ID_OHAI_LOL = 'a', +  USRP2_FW_UPDATE_ID_OHAI_OMG = 'A', + +  USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = 'f', +  USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = 'F', + +  USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = 'e', +  USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = 'E', + +  USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = 'd', +  USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = 'D', +  USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = 'B', + +  USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = 'w', +  USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = 'W', + +  USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = 'r', +  USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = 'R', + +  USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = 's', +  USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = 'S', + +  USRP2_FW_UPDATE_ID_KTHXBAI = '~' + +} usrp2_fw_update_id_t; + +typedef struct { +  uint32_t proto_ver; +  uint32_t id; +  uint32_t seq; +  union { +      uint32_t ip_addr; +    struct { +      uint32_t flash_addr; +      uint32_t length; +      uint8_t  data[256]; +    } flash_args; +    struct { +      uint32_t sector_size_bytes; +      uint32_t memory_size_bytes; +    } flash_info_args; +  } data; +} usrp2_fw_update_data_t; + +void handle_udp_fw_update_packet(struct socket_address src, struct socket_address dst, +                                 unsigned char *payload, int payload_len); diff --git a/firmware/microblaze/lib/usrp2_bytesex.h b/firmware/microblaze/lib/usrp2_bytesex.h new file mode 100644 index 000000000..2b74f2a0b --- /dev/null +++ b/firmware/microblaze/lib/usrp2_bytesex.h @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_USRP2_BYTESEX_H +#define INCLUDED_USRP2_BYTESEX_H + +// The USRP2 speaks big-endian... +// Use the standard include files or provide substitutions for +// htons and friends + +#if defined(HAVE_ARPA_INET_H) +#include <arpa/inet.h> +#elif defined(HAVE_NETINET_IN_H) +#include <netinet/in.h> +#else +#include <stdint.h> + +#ifdef WORDS_BIGENDIAN  // nothing to do... + +static inline uint32_t htonl(uint32_t x){ return x; } +static inline uint16_t htons(uint16_t x){ return x; } +static inline uint32_t ntohl(uint32_t x){ return x; } +static inline uint16_t ntohs(uint16_t x){ return x; } + +#else + +#ifdef HAVE_BYTESWAP_H +#include <byteswap.h> +#else + +static inline uint16_t +bswap_16 (uint16_t x) +{ +  return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)); +} + +static inline uint32_t +bswap_32 (uint32_t x) +{ +  return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) \ +        | (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24)); +} +#endif + +static inline uint32_t htonl(uint32_t x){ return bswap_32(x); } +static inline uint16_t htons(uint16_t x){ return bswap_16(x); } +static inline uint32_t ntohl(uint32_t x){ return bswap_32(x); } +static inline uint16_t ntohs(uint16_t x){ return bswap_16(x); } + +#endif +#endif +#endif /* INCLUDED_USRP2_BYTESEX_H */ diff --git a/firmware/microblaze/lib/wb16550.h b/firmware/microblaze/lib/wb16550.h new file mode 100644 index 000000000..7522f4438 --- /dev/null +++ b/firmware/microblaze/lib/wb16550.h @@ -0,0 +1,98 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + + +// Wishbone National Semiconductor 16550A compatible UART  + +#ifndef INCLUDED_WB16550_H +#define INCLUDED_WB16550_H + +#include <stdint.h> + +typedef struct { +  volatile uint8_t data;     // 0 r/w: r: rx fifo, w: tx fifo (if DLAB: LSB of divisor) +  volatile uint8_t ier;      // 1 r/w: Interrupt Enable Register (if DLAB: MSB of divisor) +  volatile uint8_t iir_fcr;  // 2 r/w: r: Interrupt ID Register, +                             //        w: Fifo Control Register +  volatile uint8_t lcr;      // 3 r/w: Line Control Register +  volatile uint8_t mcr;      // 4 w:   Modem Control Register +  volatile uint8_t lsr;      // 5 r:   Line Status Register +  volatile uint8_t msr;      // 6 r:   Modem Status Register + +} wb16550_reg_t; + +#define UART_IER_RDI		0x01  // Enable received data interrupt +#define UART_IER_THRI		0x02  // Enable transmitter holding reg empty int. +#define	UART_IER_RLSI		0x04  // Enable receiver line status interrupt +#define UART_IER_MSI		0x08  // Enable modem status interrupt + +#define	UART_IIR_NO_INT		0x01  // No interrupts pending +#define UART_IIR_ID_MASK	0x06  // Mask for interrupt ID +#define	UART_IIR_MSI		0x00  // Modem status interrupt +#define	UART_IIR_THRI		0x02  // Tx holding register empty int +#define	UART_IIR_RDI		0x04  // Rx data available int +#define UART_IIR_RLSI		0x06  // Receiver line status int + +#define	UART_FCR_ENABLE_FIFO	0x01  // ignore, always enabled +#define UART_FCR_CLEAR_RCVR	0x02  // Clear the RCVR FIFO +#define UART_FCR_CLEAR_XMIT	0x04  // Clear the XMIT FIFO +#define UART_FCR_TRIGGER_MASK	0xC0  // Mask for FIFO trigger range +#define	UART_FCR_TRIGGER_1	0x00  // Rx fifo trigger level:  1 byte +#define	UART_FCR_TRIGGER_4	0x40  // Rx fifo trigger level:  4 bytes +#define	UART_FCR_TRIGGER_8	0x80  // Rx fifo trigger level:  8 bytes +#define	UART_FCR_TRIGGER_14	0xC0  // Rx fifo trigger level: 14 bytes + +#define UART_LCR_DLAB		0x80  // Divisor latch access bit  +#define UART_LCR_SBC		0x40  // Set break control  +#define UART_LCR_SPAR		0x20  // Stick parity +#define UART_LCR_EPAR		0x10  // Even parity select  +#define UART_LCR_PARITY		0x08  // Parity Enable  +#define UART_LCR_STOP		0x04  // Stop bits: 0=1 bit, 1=2 bits  +#define UART_LCR_WLEN5		0x00  // Wordlength: 5 bits  +#define UART_LCR_WLEN6		0x01  // Wordlength: 6 bits  +#define UART_LCR_WLEN7		0x02  // Wordlength: 7 bits  +#define UART_LCR_WLEN8		0x03  // Wordlength: 8 bits  + +#define UART_MCR_LOOP		0x10  // Enable loopback test mode  +#define UART_MCR_OUT2n		0x08  // Out2 complement (loopback mode) +#define UART_MCR_OUT1n		0x04  // Out1 complement (loopback mode) +#define UART_MCR_RTSn		0x02  // RTS complement  +#define UART_MCR_DTRn		0x01  // DTR complement  + +#define UART_LSR_TEMT		0x40  // Transmitter empty  +#define UART_LSR_THRE		0x20  // Transmit-hold-register empty  +#define UART_LSR_BI		0x10  // Break interrupt indicator  +#define UART_LSR_FE		0x08  // Frame error indicator  +#define UART_LSR_PE		0x04  // Parity error indicator  +#define UART_LSR_OE		0x02  // Overrun error indicator  +#define UART_LSR_DR		0x01  // Receiver data ready  +#define UART_LSR_BRK_ERROR_BITS	0x1E  // BI, FE, PE, OE bits  +#define UART_LSR_ERROR		0x80  // At least 1 PE, FE or BI are in the fifo + +#define UART_MSR_DCD		0x80  // Data Carrier Detect  +#define UART_MSR_RI		0x40  // Ring Indicator  +#define UART_MSR_DSR		0x20  // Data Set Ready  +#define UART_MSR_CTS		0x10  // Clear to Send  +#define UART_MSR_DDCD		0x08  // Delta DCD  +#define UART_MSR_TERI		0x04  // Trailing edge ring indicator  +#define UART_MSR_DDSR		0x02  // Delta DSR  +#define UART_MSR_DCTS		0x01  // Delta CTS  +#define UART_MSR_ANY_DELTA	0x0F  // Any of the delta bits!  + + +#endif  // INCLUDED_WB16550_H  diff --git a/firmware/microblaze/lwip/lwip-1.3.1/CHANGELOG b/firmware/microblaze/lwip/lwip-1.3.1/CHANGELOG new file mode 100644 index 000000000..a45765010 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/CHANGELOG @@ -0,0 +1,2248 @@ +FUTURE + +  * TODO: The lwIP source code makes some invalid assumptions on processor +    word-length, storage sizes and alignment. See the mailing lists for +    problems with exoteric (/DSP) architectures showing these problems. +    We still have to fix some of these issues neatly. + +  * TODO: the PPP code is broken in a few ways. There are namespace +    collisions on BSD systems and many assumptions on word-length +    (sizeof(int)). In ppp.c an assumption is made on the availability of +    a thread subsystem. Either PPP needs to be moved to contrib/ports/??? +    or rearranged to be more generic. + +HISTORY + +(CVS HEAD) + +  * [Enter new changes just after this line - do not remove this line] + +  ++ New features: + +  ++ Bugfixes: + + +(STABLE-1.3.1) + +  ++ New features: + +  2009-05-10 Simon Goldschmidt +  * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option +    LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only +    one pbuf to help MACs that don't support scatter-gather DMA. + +  2009-05-09 Simon Goldschmidt +  * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming +    ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN + +  2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen +  * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive +    extended info about the currently received packet. + +  2009-04-27 Simon Goldschmidt +  * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 + +  2009-04-25 Simon Goldschmidt +  * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next +    bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). + +  2009-04-21 Simon Goldschmidt +  * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static +    hosts table. New configuration options DNS_LOCAL_HOSTLIST and +    DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined +    as an external function for lookup. + +  2009-04-15 Simon Goldschmidt +  * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique + +  2009-03-31 Kieran Mansley +  * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for +    TCP timestamp options, off by default.  Rework tcp_enqueue() to +    take option flags rather than specified option data + +  2009-02-18 Simon Goldschmidt +  * cc.h: Added printf formatter for size_t: SZT_F + +  2009-02-16 Simon Goldschmidt (patch by Rishi Khan) +  * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast +    pings + +  2009-02-12 Simon Goldschmidt +  * init.h: Added LWIP_VERSION to get the current version of the stack + +  2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler) +  * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead +    of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc +    is otherwise used) + +  2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach) +  * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial() +  is only used by UDPLITE at present, so conditionalise it. + +  2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli) +  * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP +    "seed" address. This should reduce AUTOIP conflicts if +    LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. + +  2008-10-02 Jonathan Larmour and Rishi Khan +  * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking +    socket. + +  2008-06-30 Simon Goldschmidt +  * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from +    interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows +    mem_free to run between mem_malloc iterations. Added illegal counter for +    mem stats. + +  2008-06-27 Simon Goldschmidt +  * stats.h/.c, some other files: patch #6483: stats module improvement: +    Added defines to display each module's statistic individually, added stats +    defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. + +  2008-06-17 Simon Goldschmidt +  * err.h: patch #6459: Made err_t overridable to use a more efficient type +    (define LWIP_ERR_T in cc.h) + +  2008-06-17 Simon Goldschmidt +  * slipif.c: patch #6480: Added a configuration option for slipif for symmetry +    to loopif + +  2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli) +  * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly +    modified version of patch # 6370: Moved loopif code to netif.c so that +    loopback traffic is supported on all netifs (all local IPs). +    Added option to limit loopback packets for each netifs. + + +  ++ Bugfixes: +  2009-08-12 Kieran Mansley +  * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when +    out of window or out of order properly + +  2009-08-12 Kieran Mansley +  * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1 + +  2009-07-28 Simon Goldschmidt +  * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s + +  2009-07-27 Kieran Mansley +  * api.h api_msg.h netdb.h sockets.h: add missing #include directives + +  2009-07-09 Kieran Mansley +  * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for +    recv_avail and don't increment counters until message successfully +    sent to mbox + +  2009-06-25 Kieran Mansley +  * api_msg.c api.h: BUG26722: initialise netconn write variables  +    in netconn_alloc + +  2009-06-25 Kieran Mansley +  * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set + +  2009-06-25 Kieran Mansley +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct +    simultaneous close behaviour, and make snd_nxt have the same meaning  +    as in the RFCs. + +  2009-05-12 Simon Goldschmidt +  * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on +    arp_table / uses etharp_query" by adding etharp_gratuitous() + +  2009-05-12 Simon Goldschmidt +  * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options +    to the IP header (used by igmp_ip_output_if) + +  2009-05-06 Simon Goldschmidt +  * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if +    defined) for SWAP_BYTES_IN_WORD to speed up checksumming. + +  2009-05-05 Simon Goldschmidt +  * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select() +    to crash + +  2009-05-04 Simon Goldschmidt +  * init.c: snmp was not initialized in lwip_init() + +  2009-05-04 Frédéric Bernon +  * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled. + +  2009-05-03 Simon Goldschmidt +  * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full +    (and unsent->next == NULL) + +  2009-05-02 Simon Goldschmidt +  * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after +    1.3.0 in CVS only) - fixes compilation of ppp_oe.c + +  2009-05-02 Simon Goldschmidt +  * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields + +  2009-05-01 Simon Goldschmidt +  * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets + +  2009-05-01 Simon Goldschmidt +  * ppp.c: bug #24228: Memory corruption with PPP and DHCP + +  2009-04-29 Frédéric Bernon +  * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the +    SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception +    of broadcast packets even when this option wasn't set. Port maintainers +    which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. +    If you want this option also filter broadcast on recv operations, you also +    have to set IP_SOF_BROADCAST_RECV=1 in opt.h. + +  2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen +  * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and +    DHCP/AUTOIP cooperation + +  2009-04-25 Simon Goldschmidt, Oleg Tyshev +  * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd +    Fixed by sorting the unsent and unacked queues (segments are inserted at the +    right place in tcp_output and tcp_rexmit). + +  2009-04-25 Simon Goldschmidt +  * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation +    when debugging": memp_sizes contained the wrong sizes (including sanity +    regions); memp pools for MEM_USE_POOLS were too small + +  2009-04-24 Simon Goldschmidt, Frédéric Bernon +  * inet.c: patch #6765: Fix a small problem with the last changes (incorrect +    behavior, with with ip address string not ended by a '\0', a space or a +    end of line) + +  2009-04-19 Simon Goldschmidt +  * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails, +    pcb->err is called, not pcb->connected (with an error code). + +  2009-04-19 Simon Goldschmidt +  * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with +    no-copy-tcpwrite": deallocate option data, only concat segments with same flags + +  2009-04-19 Simon Goldschmidt +  * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated +    in the header pbuf, not the data pbuf) + +  2009-04-18 Simon Goldschmidt +  * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore() + +  2009-04-15 Simon Goldschmidt +  * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp + +  2009-04-15 Simon Goldschmidt +  * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in + +  2009-04-15 Simon Goldschmidt +  * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function +    ip_hinted_output() (for smaller code mainly) + +  2009-04-15 Simon Goldschmidt +  * inet.c: patch #6765: Supporting new line characters in inet_aton() + +  2009-04-15 Simon Goldschmidt +  * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option; +    Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu +    is big enough in dhcp_start + +  2009-04-15 Simon Goldschmidt +  * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak + +  2009-04-15 Simon Goldschmidt +  * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY + +  2009-04-15 Simon Goldschmidt +  * sockets.c: bug #26121: set_errno can be overridden + +  2009-04-09 Kieran Mansley (patch from Luca Ceresoli <lucaceresoli>) +  * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when +    LWIP_TCP==0 + +  2009-04-09 Kieran Mansley (patch from Roy Lee <roylee17>) +  * tcp.h: Patch#6802 Add do-while-clauses to those function like +    macros in tcp.h + +  2009-03-31 Kieran Mansley +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window +    updates are calculated and sent (BUG20515) + +  * tcp_in.c: cope with SYN packets received during established states, +    and retransmission of initial SYN. + +  * tcp_out.c: set push bit correctly when tcp segments are merged + +  2009-03-27 Kieran Mansley +  * tcp_out.c set window correctly on probes (correcting change made +    yesterday) + +  2009-03-26 Kieran Mansley +  * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping +    connections where no reset required (bug #25622) + +  * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes  +    (bug #20779) + +  2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) +  * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be +    too small depending on MEM_ALIGNMENT + +  2009-02-16 Simon Goldschmidt +  * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard; +    converted size argument of netconn_write to 'size_t' + +  2009-02-16 Simon Goldschmidt +  * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host +    by moving accept callback function pointer to TCP_PCB_COMMON + +  2009-02-12 Simon Goldschmidt +  * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" +    option) + +  2009-02-11 Simon Goldschmidt +  * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) + +  2009-02-11 Simon Goldschmidt +  * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize: +    RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) + +  2009-02-10 Simon Goldschmidt +  * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: +    Accepts_pending is decrease on a corresponding listen pcb when a connection +    in state SYN_RCVD is close. + +  2009-01-28 Jonathan Larmour +  * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run +    out of pool pbufs. + +  2008-12-19 Simon Goldschmidt +  * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2  + +  2008-12-10 Tamas Somogyi, Frédéric Bernon +  * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and +    port uses deleted netbuf. + +  2008-10-18 Simon Goldschmidt +  * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length +    in tcp_parseopt + +  2008-10-15 Simon Goldschmidt +  * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers +    by packing the struct ip_reass_helper. + +  2008-10-03 David Woodhouse, Jonathan Larmour +  * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. + +  2008-10-02 Jonathan Larmour +  * dns.c: Hard-code structure sizes, to avoid issues on some compilers where +    padding is included. + +  2008-09-30 Jonathan Larmour +  * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an +    assertion check that addrlen isn't NULL. + +  2008-09-30 Jonathan Larmour +  * tcp.c: Fix bug #24227, wrong error message in tcp_bind. + +  2008-08-26 Simon Goldschmidt +  * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and +    inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h + +  2008-08-14 Simon Goldschmidt +  * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when +    tcp_close returns != ERR_OK) + +  2008-07-08 Frédéric Bernon +  * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters +    in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). + +  2008-06-24 Jonathan Larmour +  * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused +    if tcp_seg_copy fails. + +  2008-06-17 Simon Goldschmidt +  * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations) +    and created defines for swapping bytes and folding u32 to u16. + +  2008-05-30 Kieran Mansley +  * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd +    rather than rcv_ann_wnd when deciding if packets are in-window. +    Contributed by <arasmussen@consultant.datasys.swri.edu> + +  2008-05-30 Kieran Mansley +  * mem.h: Fix BUG#23254.  Change macro definition of mem_* to allow +    passing as function pointers when MEM_LIBC_MALLOC is defined. + +  2008-05-09 Jonathan Larmour +  * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to +    stop it being treated as a fatal error. + +  2008-04-15 Simon Goldschmidt +  * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP +    (flag now cleared) + +  2008-03-27 Simon Goldschmidt +  * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free +    from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 +    in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs +    or heap memory from interrupt context + +  2008-03-26 Simon Goldschmidt +  * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote +    host sent a zero mss as TCP option. + + +(STABLE-1.3.0) + +  ++ New features: + +  2008-03-10 Jonathan Larmour +  * inet_chksum.c: Allow choice of one of the sample algorithms to be +    made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. + +  2008-01-22 Frédéric Bernon +  * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in  +    TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names. + +  2008-01-14 Frédéric Bernon +  * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable +    to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the +    tcp_recv callback (see rawapi.txt). + +  2008-01-14 Frédéric Bernon, Marc Chaland +  * ip.c: Integrate patch #6369" ip_input : checking before realloc". +   +  2008-01-12 Frédéric Bernon +  * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field +    netconn::sem per netconn::op_completed like suggested for the task #7490 +    "Add return value to sys_mbox_post". + +  2008-01-12 Frédéric Bernon +  * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE, +    DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues +    sizes), like suggested for the task #7490 "Add return value to sys_mbox_post". + +  2008-01-10 Frédéric Bernon +  * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490 +    "Add return value to sys_mbox_post". tcpip_callback is always defined as +    "blocking" ("block" parameter = 1). + +  2008-01-10 Frédéric Bernon +  * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field +    netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490 +    "Add return value to sys_mbox_post". + +  2008-01-05 Frédéric Bernon +  * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h: +    Introduce changes for task #7490 "Add return value to sys_mbox_post" with some +    modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which +    indicate the number of pointers query by the mailbox. There is three defines +    in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the  +    netconn::acceptmbox. Port maintainers, you can decide to just add this new  +    parameter in your implementation, but to ignore it to keep the previous behavior. +    The new sys_mbox_trypost function return a value to know if the mailbox is +    full or if the message is posted. Take a look to sys_arch.txt for more details. +    This new function is used in tcpip_input (so, can be called in an interrupt +    context since the function is not blocking), and in recv_udp and recv_raw. + +  2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour +  * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c, +    tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the +    "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add +    documentation in the rawapi.txt file. + +  2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm) +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer + +  2007-12-31 Frédéric Bernon, Luca Ceresoli +  * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets +    in autoip". The change in etharp_raw could be removed, since all calls to +    etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be +    wrong in the future. + +  2007-12-30 Frédéric Bernon, Tom Evans +  * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address +    Filtering" reported by Tom Evans. + +  2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour +  * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, +    sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API +    applications have to call 'tcp_accepted(pcb)' in their accept callback to +    keep accepting new connections. + +  2007-12-13 Frédéric Bernon +  * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" +    by err_t type. Add a new err_t code "ERR_INPROGRESS". + +  2007-12-12 Frédéric Bernon +  * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles +    are the one which have ram usage. + +  2007-12-05 Frédéric Bernon +  * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static +    set of variables (=0) or a local one (=1). In this last case, your port should +    provide a function "struct hostent* sys_thread_hostent( struct hostent* h)" +    which have to do a copy of "h" and return a pointer ont the "per-thread" copy. + +  2007-12-03 Simon Goldschmidt +  * ip.c: ip_input: check if a packet is for inp first before checking all other +    netifs on netif_list (speeds up packet receiving in most cases) + +  2007-11-30 Simon Goldschmidt +  * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access +    UDP: move a (connected) pcb selected for input to the front of the list of +    pcbs so that it is found faster next time. Same for RAW pcbs that have eaten +    a packet. + +  2007-11-28 Simon Goldschmidt +  * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS + +  2007-11-25 Simon Goldschmidt +  * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy +    algorithm. + +  2007-11-24 Simon Goldschmidt +  * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c +    to the new file netdb.c; included lwip_getaddrinfo. + +  2007-11-21 Simon Goldschmidt +  * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss +    based on the MTU of the netif used to send. Enabled by default. Disable by +    setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492. + +  2007-11-19 Frédéric Bernon +  * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name +    received match the name query), implement DNS_USES_STATIC_BUF (the place where +    copy dns payload to parse the response), return an error if there is no place +    for a new query, and fix some minor problems. + +  2007-11-16 Simon Goldschmidt +  * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c +    removed files: core/inet.c, core/inet6.c +    Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into +    inet and chksum part; changed includes in all lwIP files as appropriate + +  2007-11-16 Simon Goldschmidt +  * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential +    dns resolver function for netconn api (netconn_gethostbyname) and socket api +    (gethostbyname/gethostbyname_r). + +  2007-11-15 Jim Pettinato, Frédéric Bernon +  * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name +    requests with RAW api interface. Initialization is done in lwip_init() with +    build time options. DNS timer is added in tcpip_thread context. DHCP can set +    DNS server ip addresses when options are received. You need to set LWIP_DNS=1 +    in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get +    some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo" +    list with points to improve. + +  2007-11-06 Simon Goldschmidt +  * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly +    enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status +    for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined. + +  2007-11-06 Simon Goldschmidt +  * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include +    core header files in api.h (ip/tcp/udp/raw.h) to hide the internal +    implementation from netconn api applications. + +  2007-11-03 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP & +    RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled +    by default). Netconn API users can use the netconn_recv_bufsize macro to access +    it. This is a first release which have to be improve for TCP. Note it used the +    netconn::recv_avail which need to be more "thread-safe" (note there is already +    the problem for FIONREAD with lwip_ioctl/ioctlsocket). + +  2007-11-01 Frédéric Bernon, Marc Chaland +  * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c: +    Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api +    layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api +    layer. This option enable to delayed TCP PUSH flag on multiple "write" calls. +    Note that previous "copy" parameter for "write" APIs is now called "apiflags". + +  2007-10-24 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than  +    TCP_EVENT_xxx macros to get a code more readable. It could also help to remove +    some code (like we have talk in "patch #5919 : Create compile switch to remove +    select code"), but it could be done later. + +  2007-10-08 Simon Goldschmidt +  * many files: Changed initialization: many init functions are not needed any +    more since we now rely on the compiler initializing global and static +    variables to zero! + +  2007-10-06 Simon Goldschmidt +  * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY +    to enqueue the received pbufs so that multiple packets can be reassembled +    simultaneously and no static reassembly buffer is needed. + +  2007-10-05 Simon Goldschmidt +  * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so +    all netifs (or ports) can use it. + +  2007-10-05 Frédéric Bernon +  * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the  +    common function to reduce a little bit the footprint (for all functions using +    only the "netif" parameter). + +  2007-10-03 Frédéric Bernon +  * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down, +    netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce +    a little bit the footprint (for all functions using only the "netif" parameter). + +  2007-09-15 Frédéric Bernon +  * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF +    option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for +    netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for +    IP_MULTICAST_TTL and IP_MULTICAST_IF. + +  2007-09-10 Frédéric Bernon +  * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles +    even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime() +    each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can +    decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but +    call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime() +    or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. +    This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside +    snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only +    when it's queried (any direct call to "sysuptime" is changed by a call to  +    snmp_get_sysuptime). + +  2007-09-09 Frédéric Bernon, Bill Florac +  * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP, +    and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags +    if you want IGMP on an interface. igmp_stop() is now called inside netif_remove(). +    igmp_report_groups() is now called inside netif_set_link_up() (need to have +    LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait +    the next query message to receive the matching multicast streams). + +  2007-09-08 Frédéric Bernon +  * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains +    IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change). +    Use this new field to access to common pcb fields (ttl, tos, so_options, etc...). +    Enable to access to these fields with LWIP_TCP=0. + +  2007-09-05 Frédéric Bernon +  * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h, +    ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option +    LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default). +    Be careful, disabling ICMP make your product non-compliant to RFC1122, but +    help to reduce footprint, and to reduce "visibility" on the Internet. + +  2007-09-05 Frédéric Bernon, Bill Florac +  * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list +    for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new +    parameters have to be provided: a task name, and a task stack size. For this +    one, since it's platform dependant, you could define the best one for you in +    your lwipopts.h. For port maintainers, you can just add these new parameters +    in your sys_arch.c file, and but it's not mandatory, use them in your OS +    specific functions. + +  2007-09-05 Frédéric Bernon +  * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings +    inside init.c for task #7142 "Sanity check user-configurable values". + +  2007-09-04 Frédéric Bernon, Bill Florac +  * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by +    memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the +    value). It will avoid potential fragmentation problems, use a counter to know +    how many times a group is used on an netif, and free it when all applications +    leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity +    check if LWIP_IGMP!=0). + +  2007-09-03 Frédéric Bernon +  * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement". +    Initialize igmp_mac_filter to NULL in netif_add (this field should be set in +    the netif's "init" function). Use the "imr_interface" field (for socket layer) +    and/or the "interface" field (for netconn layer), for join/leave operations. +    The igmp_join/leavegroup first parameter change from a netif to an ipaddr. +    This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany). + +  2007-08-30 Frédéric Bernon +  * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions +    from api/api_lib". Now netbuf API is independant of netconn, and can be used +    with other API (application based on raw API, or future "socket2" API). Ports +    maintainers just have to add src/api/netbuf.c in their makefile/projects. + +  2007-08-30 Frédéric Bernon, Jonathan Larmour +  * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check +    user-configurable values". + +  2007-08-29 Frédéric Bernon +  * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start. +    igmp_start is call inside netif_add. Now, igmp initialization is in the same +    spirit than the others modules. Modify some IGMP debug traces. + +  2007-08-29 Frédéric Bernon +  * Add init.h, init.c, Change opt.h, tcpip.c: Task  #7213 "Add a lwip_init function" +    Add lwip_init function to regroup all modules initializations, and to provide +    a place to add code for task #7142 "Sanity check user-configurable values". +    Ports maintainers should remove direct initializations calls from their code, +    and add init.c in their makefiles. Note that lwip_init() function is called +    inside tcpip_init, but can also be used by raw api users since all calls are +    disabled when matching options are disabled. Also note that their is new options +    in opt.h, you should configure in your lwipopts.h (they are enabled per default). + +  2007-08-26 Marc Boucher +  * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL +    since they can under certain circumstances be called with an invalid conn +    pointer after the connection has been closed (and conn has been freed).  + +  2007-08-25 Frédéric Bernon (Artem Migaev's Patch) +  * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up". +    Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set. + +  2007-08-22 Frédéric Bernon +  * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK +    to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release. + +  2007-08-22 Frédéric Bernon +  * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT & +    ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the  +    name is tcpip_input (we keep the name of 1.2.0 function). + +  2007-08-17 Jared Grubb +  * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool  +    settings into new memp_std.h and optional user file lwippools.h. This adds +    more dynamic mempools, and allows the user to create an arbitrary number of +    mempools for mem_malloc. + +  2007-08-16 Marc Boucher +  * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function; +    otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely +    close the connection. + +  2007-08-16 Marc Boucher +  * sockets.c: lwip_accept(): check netconn_peer() error return. + +  2007-08-16 Marc Boucher +  * mem.c, mem.h: Added mem_calloc(). + +  2007-08-16 Marc Boucher +  * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT) +    for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG +    and starving other message types. +    Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API + +  2007-08-16 Marc Boucher +  * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf +    type and flgs (later renamed to flags). +    Use enum pbuf_flag as pbuf_type.  Renumber PBUF_FLAG_*. +    Improved lwip_recvfrom().  TCP push now propagated. + +  2007-08-16 Marc Boucher +  * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global +    provided by etharp. + +  2007-08-16 Marc Boucher +  * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h, +    etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c: +    Added PPPoE support and various PPP improvements. + +  2007-07-25 Simon Goldschmidt +  * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial, +    making netbuf_copy_partial use this function. + +  2007-07-25 Simon Goldschmidt +  * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with +    2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and +    other stacks. + +  2007-07-13 Jared Grubb (integrated by Frédéric Bernon) +  * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add +    a link callback in the netif struct, and functions to handle it. Be carefull +    for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c) +    if you want to be sure to be compatible with future changes... + +  2007-06-30 Frédéric Bernon +  * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions. + +  2007-06-21 Simon Goldschmidt +  * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both +    LWIP_AUTOIP =0 and =1 to remove redundant code. + +  2007-06-21 Simon Goldschmidt +  * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option +    MEM_USE_POOLS to use 4 pools with different sized elements instead of a +    heap. This both prevents memory fragmentation and gives a higher speed +    at the cost of more memory consumption. Turned off by default. + +  2007-06-21 Simon Goldschmidt +  * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of +    netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into +    int to be able to send a bigger buffer than 64K with one time (mainly +    used from lwip_send). + +  2007-06-21 Simon Goldschmidt +  * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write +    into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too. + +  2007-06-21 Simon Goldschmidt +  * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in +    netconn_write from api_lib.c to api_msg.c to also prevent multiple context- +    changes on low memory or empty send-buffer. + +  2007-06-18 Simon Goldschmidt +  * etharp.c, etharp.h: Changed etharp to use a defined hardware address length +    of 6 to avoid loading netif->hwaddr_len every time (since this file is only +    used for ethernet and struct eth_addr already had a defined length of 6). + +  2007-06-17 Simon Goldschmidt +  * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets +    to disable UDP checksum generation on transmit. + +  2007-06-13 Frédéric Bernon, Simon Goldschmidt +  * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid +    pointers or parameters, and let the possibility to redefined it in cc.h. Use +    this macro to check "conn" parameter in api_msg.c functions. + +  2007-06-11 Simon Goldschmidt +  * sockets.c, sockets.h: Added UDP lite support for sockets + +  2007-06-10 Simon Goldschmidt +  * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled +    by default) to switch off UDP-Lite support if not needed (reduces udp.c code +    size) + +  2007-06-09 Dominik Spies (integrated by Frédéric Bernon) +  * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h: +    AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and +    LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt +    (see TODO mark in the source code). + +  2007-06-09 Simon Goldschmidt +  * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for +    etharp_output() to match netif->output so etharp_output() can be used +    directly as netif->output to save one function call. + +  2007-06-08 Simon Goldschmidt +  * netif.h, ethernetif.c, slipif.c, loopif.c: Added define +    NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables, +    added initialization of those to ethernetif, slipif and loopif. + +  2007-05-18 Simon Goldschmidt +  * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF +    (defaulting to off for now) that can be set to 0 to send fragmented +    packets by passing PBUF_REFs down the stack. + +  2007-05-23 Frédéric Bernon +  * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP +    connections, such present in patch #5959. + +  2007-05-23 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx +    code in only one part... + +  2007-05-18 Simon Goldschmidt +  * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp +    elements to overflow. This is achieved by adding some bytes before and after +    each pool element (increasing their size, of course), filling them with a +    prominent value and checking them on freeing the element. +    Set it to 2 to also check every element in every pool each time memp_malloc() +    or memp_free() is called (slower but more helpful). + +  2007-05-10 Simon Goldschmidt +  * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for +    PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce +    code size. + +  2007-05-11 Frédéric Bernon +  * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c: +    Include a function pointer instead of a table index in the message to reduce +    footprint. Disable some part of lwip_send and lwip_sendto if some options are +    not set (LWIP_TCP, LWIP_UDP, LWIP_RAW). + +  2007-05-10 Simon Goldschmidt +  * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus +    \ extern "C" {' in all header files. Now you can write your application using +    the lwIP stack in C++ and simply #include the core files. Note I have left +    out the netif/ppp/*h header files for now, since I don't know which files are +    included by applications and which are for internal use only. + +  2007-05-09 Simon Goldschmidt +  * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library +    memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for +    situations where some compilers might inline the copy and save a function +    call. Also replaced all calls to memcpy() with calls to (S)MEMCPY(). + +  2007-05-08 Simon Goldschmidt +  * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc()) +    to be overriden in case the C-library malloc implementation is not protected +    against concurrent access. + +  2007-05-04 Simon Goldschmidt (Atte Kojo) +  * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending +    multiple packets to the same host. + +  2007-05-04 Frédéric Bernon, Jonathan Larmour +  * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible +    to corrupt remote addr/port connection state". Reduce problems "not enought memory" with +    netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between +    sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function. +    Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct, +    these fields are now renamed "addr" & "port". + +  2007-04-11 Jonathan Larmour +  * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new +    sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return +    with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro +    by the port in sys_arch.h if desired. + +  2007-04-06 Frédéric Bernon, Simon Goldschmidt +  * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API +    allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp +    clients, using new functions from netifapi.h. Disable as default (no port change to do). + +  2007-04-05 Frédéric Bernon +  * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant. + +  2007-04-04 Simon Goldschmidt +  * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x) +    use this for and architecture-independent form to tell the compiler you intentionally +    are not using this variable. Can be overriden in cc.h. + +  2007-03-28 Frédéric Bernon +  * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to +    define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded +    string, point on one of your's ethernetif field, or alloc a string you will free yourself). +    It will be used by DHCP to register a client hostname, but can also be use when you call +    snmp_set_sysname. + +  2007-03-28 Frédéric Bernon +  * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to  +    initialize a network interface's flag with. It tell this interface is an ethernet +    device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility +    Support for IPv4" section 4.6) when interface is "up" with netif_set_up(). + +  2007-03-26 Frédéric Bernon, Jonathan Larmour +  * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build +    time if you only use PPP or SLIP. The default is enable. Note we don't have to call  +    etharp_init in your port's initilization sequence if you use tcpip.c, because this call +    is done in tcpip_init function. + +  2007-03-22 Frédéric Bernon +  * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the +    new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in +    your lwipopts.h. More, unused counters are not defined in the stats structs, and not  +    display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined +    but never used. Fix msg_in.c with the correct #if test for a stat display. + +  2007-03-21 Kieran Mansley +  * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com).  +    Provides callback on netif up/down state change. + +  2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds +  * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, +    ip.c, netif.h, tcpip.c, opt.h: +    New configuration option LWIP_IGMP to enable IGMP processing. Based on only one  +    filter per all network interfaces. Declare a new function in netif to enable to +    control the MAC filter (to reduce lwIP traffic processing). + +  2007-03-11 Frédéric Bernon +  * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can +    be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this +    unless you know what you're doing (default are RFC1122 compliant). Note +    that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds. + +  2007-03-08 Frédéric Bernon +  * tcp.h: Keepalive values can be configured at compile time, but don't change +    this unless you know what you're doing (default are RFC1122 compliant). + +  2007-03-08 Frédéric Bernon +  * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h: +    Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO +    on UDP sockets/netconn. + +  2007-03-08 Simon Goldschmidt +  * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time. + +  2007-03-06 Frédéric Bernon +  * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h:  +    Implement SO_RCVTIMEO on UDP sockets/netconn. + +  2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt) +  * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated +    on the stack and remove the API msg type from memp + +  2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) +  * sockets.h, sockets.c: Move socket initialization to new +    lwip_socket_init() function. +    NOTE: this changes the API with ports. Ports will have to be +    updated to call lwip_socket_init() now. + +  2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) +  * api_lib.c: Use memcpy in netbuf_copy_partial. + + +  ++ Bug fixes: + +  2008-03-17 Frédéric Bernon, Ed Kerekes +  * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have +    some problems to fill the IP header on some targets, use now the +    ip.h macros to do it). + +  2008-03-13 Frédéric Bernon +  * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using +    (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a +    TCP connection caused a crash. Note that using (lwip_)recvfrom +    like this is a bit slow and that using (lwip)getpeername is the +    good lwip way to do it (so, using recv is faster on tcp sockets). + +  2008-03-12 Frédéric Bernon, Jonathan Larmour +  * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's +    recv_raw() does not consume data", and the ping sample (with +    LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom +    returned the IP payload, without the IP header). + +  2008-03-04 Jonathan Larmour +  * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors +  and/or warnings on some systems where mem_size_t and size_t differ. +  * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc. + +  2008-03-04 Kieran Mansley (contributions by others)  +  * Numerous small compiler error/warning fixes from contributions to +    mailing list after 1.3.0 release candidate made. + +  2008-01-25 Cui hengbin (integrated by Frédéric Bernon) +  * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures. + +  2008-01-15 Kieran Mansley +  * tcp_out.c: BUG20511.  Modify persist timer to start when we are +    prevented from sending by a small send window, not just a zero +    send window. + +  2008-01-09 Jonathan Larmour +  * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid +    conflict with Linux system headers. + +  2008-01-06 Jonathan Larmour +  * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP +    address entirely on receiving a DHCPNAK, and restarting discovery. + +  2007-12-21 Simon Goldschmidt +  * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail +    is not protected" by using new macros for interlocked access to modify/test +    netconn->recv_avail. + +  2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev) +  * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state) + +  2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling +    of silly window avoidance and prevent lwIP from shrinking the window) + +  2007-12-04 Simon Goldschmidt +  * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last +    data packet was lost): add assert that all segment lists are empty in +    tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED +    state from LAST_ACK in tcp_process + +  2007-12-02 Simon Goldschmidt +  * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET +    If including <sys/time.h> for system-struct timeval, LWIP_TIMEVAL_PRIVATE now +    has to be set to 0 in lwipopts.h + +  2007-12-02 Simon Goldschmidt +  * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always +    allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen +    netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox. +    This is a fix for thread-safety and allocates all items needed for a netconn +    when the netconn is created. + +  2007-11-30 Simon Goldschmidt +  * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple +    netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed +    to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same +    port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address) + +  2007-11-27 Simon Goldschmidt +  * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by +    letting ip_route only use netifs that are up. + +  2007-11-27 Simon Goldschmidt +  * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF +    and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and +    sockets block most operations once they have seen a fatal error. + +  2007-11-27 Simon Goldschmidt +  * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the +    netif to send as an argument (to be able to send on netifs that are down). + +  2007-11-26 Simon Goldschmidt +  * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs +    arrive out-of-order + +  2007-11-21 Simon Goldschmidt +  * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early +    Fixed the nagle algorithm; nagle now also works for all raw API applications +    and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY' + +  2007-11-12 Frédéric Bernon +  * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most +    of the netconn_peer and netconn_addr processing is done inside tcpip_thread +    context in do_getaddr. + +  2007-11-10 Simon Goldschmidt +  * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can +    happen any time). Now the packet simply isn't enqueued when out of memory. + +  2007-11-01 Simon Goldschmidt +  * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or +    TCP_MSS if that is smaller) as long as no MSS option is received from the +    remote host. + +  2007-11-01 Simon Goldschmidt +  * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN) +    is now based on TCP_MSS instead of pcb->mss (on passive open now effectively +    sending our configured TCP_MSS instead of the one received). + +  2007-11-01 Simon Goldschmidt +  * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was +    calculated based on the configured TCP_MSS, not on the MSS option received +    with SYN+ACK. + +  2007-10-09 Simon Goldschmidt +  * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too +    short and also was generated wrong if checksum coverage != tot_len; +    receive: checksum was calculated wrong if checksum coverage != tot_len + +  2007-10-08 Simon Goldschmidt +  * mem.c: lfree was not updated in mem_realloc! + +  2007-10-07 Frédéric Bernon +  * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential +    crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT: +    this change cause an API breakage for netconn_addr, since a parameter +    type change. Any compiler should cause an error without any changes in +    yours netconn_peer calls (so, it can't be a "silent change"). It also +    reduce a little bit the footprint for socket layer (lwip_getpeername & +    lwip_getsockname use now a common lwip_getaddrname function since  +    netconn_peer & netconn_addr have the same parameters). + +  2007-09-20 Simon Goldschmidt +  * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state) +    by checking  tcp_tw_pcbs also + +  2007-09-19 Simon Goldschmidt +  * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies) + +  2007-09-15 Mike Kleshov +  * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used) + +  2007-09-06 Frédéric Bernon +  * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove +    it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which +    already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h" +    if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h. + +  2007-08-30 Frédéric Bernon +  * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces,  +    and fix some coding style. + +  2007-08-28 Frédéric Bernon +  * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any +    kind of packets. These packets are considered like Ethernet packets (payload  +    pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets  +    are considered like IP packets (payload pointing to iphdr). + +  2007-08-27 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error +    problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state +    and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT). + +  2007-08-24 Kieran Mansley +  * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy +    compiler (Paradigm C++) + +  2007-08-09 Frédéric Bernon, Bill Florac +  * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement. +    Introduce IGMP_STATS to centralize statistics management. + +  2007-08-09 Frédéric Bernon, Bill Florac +  * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast +    packet on a udp pcb binded on an netif's IP address, and not on "any". + +  2007-08-09 Frédéric Bernon, Bill Florac +  * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement. +    This is mainly on using lookup/lookfor, and some coding styles... + +  2007-07-26 Frédéric Bernon (and "thedoctor") +  * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages. + +  2007-07-25 Simon Goldschmidt +  * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if +    tcp_output fails in tcp_close, the code in do_close_internal gets simpler +    (tcp_output is called again later from tcp timers). + +  2007-07-25 Simon Goldschmidt +  * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old +    copy_from_pbuf, which illegally modified the given pbuf. + +  2007-07-25 Simon Goldschmidt +  * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs: +    changed snd_queuelen++ to snd_queuelen += pbuf_clen(p). + +  2007-07-24 Simon Goldschmidt +  * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the +    correct state (must be CLOSED). + +  2007-07-13 Thomas Taranowski (commited by Jared Grubb) +  * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed +    allocation. It now returns NULL. + +  2007-07-13 Frédéric Bernon +  * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in +    all error cases. + +  2007-07-13 Frédéric Bernon +  * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed, +    because current code doesn't follow rawapi.txt documentation. + +  2007-07-13 Kieran Mansley +  * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in +    out of sequence processing of received packets + +  2007-07-03 Simon Goldschmidt +  * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an +    assumption is made that this pbuf is in one piece (i.e. not chained). These +    assumptions clash with the possibility of converting to fully pool-based +    pbuf implementations, where PBUF_RAM pbufs might be chained. + +  2007-07-03 Simon Goldschmidt +  * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems +    when closing tcp netconns: removed conn->sem, less context switches when +    closing, both netconn_close and netconn_delete should safely close tcp +    connections. + +  2007-07-02 Simon Goldschmidt +  * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c, +    tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off) +    to cache ARP table indices with each pcb instead of single-entry cache for +    the complete stack. + +  2007-07-02 Simon Goldschmidt +  * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent +    warnings when assigning to smaller types. + +  2007-06-28 Simon Goldschmidt +  * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing. + +  2007-06-28 Simon Goldschmidt +  * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if +    a segment contained chained pbufs) + +  2007-06-28 Frédéric Bernon +  * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute +    a "pseudo-random" value based on netif's MAC and some autoip fields. It's always +    possible to define this macro in your own lwipopts.h to always use C library's +    rand(). Note that autoip_create_rand_addr doesn't use this macro. + +  2007-06-28 Frédéric Bernon +  * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option +    LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications +    in api_lib/api_msg (use pointers and not type with table, etc...)  + +  2007-06-26 Simon Goldschmidt +  * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines. + +  2007-06-25 Simon Goldschmidt +  * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload +    for udp packets with no matching pcb. + +  2007-06-25 Simon Goldschmidt +  * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match +    could get udp input packets if the remote side matched. + +  2007-06-13 Simon Goldschmidt +  * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get +    changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0. + +  2007-06-13 Simon Goldschmidt +  * api_msg.c: pcb_new sets conn->err if protocol is not implemented +    -> netconn_new_..() does not allocate a new connection for unsupported +    protocols. + +  2007-06-13 Frédéric Bernon, Simon Goldschmidt +  * api_lib.c: change return expression in netconn_addr and netconn_peer, because +    conn->err was reset to ERR_OK without any reasons (and error was lost)... + +  2007-06-13 Frédéric Bernon, Matthias Weisser +  * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename +    MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid +    some macro names collision with some OS macros. + +  2007-06-11 Simon Goldschmidt +  * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0, +    create checksum over the complete packet. On RX, if it's < 8 (and not 0), +    discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both +    UDP & UDP Lite. + +  2007-06-11 Srinivas Gollakota & Oleg Tyshev +  * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags" +    where TCP flags wasn't initialized in tcp_keepalive. + +  2007-06-03 Simon Goldschmidt +  * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function +    registered, p->payload was modified without modifying p->len if sending +    icmp_dest_unreach() (had no negative effect but was definitively wrong). + +  2007-06-03 Simon Goldschmidt +  * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp +    re-used the input pbuf even if that didn't have enough space to include the +    link headers. Now the space is tested and a new pbuf is allocated for the +    echo response packet if the echo request pbuf isn't big enough. + +  2007-06-01 Simon Goldschmidt +  * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread. + +  2007-05-23 Frédéric Bernon +  * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only +    allocated by do_listen if success) and netconn_accept errors handling. In +    most of api_lib functions, we replace some errors checkings like "if (conn==NULL)" +    by ASSERT, except for netconn_delete. + +  2007-05-23 Frédéric Bernon +  * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return +    an error code if it's impossible to fetch a pbuf on a TCP connection (and not +    directly close the recvmbox). + +  2007-05-22 Simon Goldschmidt +  * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of +    bound but unconnected (and non-listening) tcp_pcbs. + +  2007-05-22 Frédéric Bernon +  * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only +    used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of +    sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features +    like "sys_timeout" in their application threads. + +  2007-05-22 Frédéric Bernon +  * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see +    which parameters are used by which do_xxx function, and to avoid "misusing" +    parameters (patch #5938). + +  2007-05-22 Simon Goldschmidt +  * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938: +    changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto +    is only 8 bits wide. This affects the api, as there, the protocol was +    u16_t, too. + +  2007-05-18 Simon Goldschmidt +  * memp.c: addition to patch #5913: smaller pointer was returned but +    memp_memory was the same size -> did not save memory. + +  2007-05-16 Simon Goldschmidt +  * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns +    != ERR_OK. + +  2007-05-16 Simon Goldschmidt +  * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same +    as the one of the netif used for sending to prevent sending from old +    addresses after a netif address gets changed (partly fixes bug #3168). + +  2007-05-16 Frédéric Bernon +  * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work +    with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in  +    tcpip_init) because we have to be sure that network interfaces are already +    added (mac filter is updated only in igmp_init for the moment). + +  2007-05-16 Simon Goldschmidt +  * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls +    into sys_arch_sem_wait calls to prevent timers from running while waiting +    for the heap. This fixes bug #19167. + +  2007-05-13 Simon Goldschmidt +  * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines +    for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from +    tcp.h to sockets.h. + +  2007-05-07 Simon Goldschmidt +  * mem.c: Another attempt to fix bug #17922. + +  2007-05-04 Simon Goldschmidt +  * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy() +    implementation so that it can be reused (don't allocate the target +    pbuf inside pbuf_copy()). + +  2007-05-04 Simon Goldschmidt +  * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem +    to save a little RAM (next pointer of memp is not used while not in pool). + +  2007-05-03 "maq" +  * sockets.c: Fix ioctl FIONREAD when some data remains from last recv. +    (patch #3574). + +  2007-04-23 Simon Goldschmidt +  * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results +    in NULL reference for incoming TCP packets". Loopif has to be configured +    (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input() +    (multithreading environments, e.g. netif->input() = tcpip_input()) or +    putting packets on a list that is fed to the stack by calling loopif_poll() +    (single-thread / NO_SYS / polling environment where e.g. +    netif->input() = ip_input). + +  2007-04-17 Jonathan Larmour +  * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold +    the difference between two u16_t's. +  * sockets.h: FD_SETSIZE needs to match number of sockets, which is +    MEMP_NUM_NETCONN in sockets.c right now. + +  2007-04-12 Jonathan Larmour +  * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580). + +  2007-04-12 Kieran Mansley +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission +    timer is reset to fix bug#19434, with help from Oleg Tyshev. + +  2007-04-11 Simon Goldschmidt +  * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than +    previously thought need to be copied (everything but PBUF_ROM!). Cleaned up +    pbuf.c: removed functions no needed any more (by etharp). + +  2007-04-11 Kieran Mansley +  * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix +    "Constant is long" warnings with 16bit compilers.  Contributed by +    avatar@mmlab.cse.yzu.edu.tw + +  2007-04-05 Frédéric Bernon, Jonathan Larmour +  * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on +    the mailbox is active". Now, the post is only done during a connect, and do_send, +    do_write and do_join_leave_group don't do anything if a previous error was signaled. + +  2007-04-03 Frédéric Bernon +  * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output +    packets. See patch #5834. + +  2007-03-30 Frédéric Bernon +  * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add +    missing  pcb allocations checking (in do_bind, and for each raw_new). Fix style. + +  2007-03-30 Frédéric Bernon +  * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with +    others environment defines (these were too "generic"). + +  2007-03-28 Frédéric Bernon +  * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call +    result and can cause a crash. lwip_send now check netbuf_ref result. + +  2007-03-28 Simon Goldschmidt +  * sockets.c Remove "#include <errno.h>" from sockets.c to avoid multiple +    definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is +    defined. This is the way it should have been already (looking at +    doc/sys_arch.txt) + +  2007-03-28 Kieran Mansley +  * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS + +    IP and TCP headers *and* physical link headers + +  2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov) +  * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause +    to send some garbage. It is not a definitive solution, but the patch does solve +    the problem for most cases. + +  2007-03-22 Frédéric Bernon +  * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used). + +  2007-03-22 Frédéric Bernon +  * api_lib.c: somes resources couldn't be freed if there was errors during +    netconn_new_with_proto_and_callback. + +  2007-03-22 Frédéric Bernon +  * ethernetif.c: update netif->input calls to check return value. In older ports, +    it's a good idea to upgrade them, even if before, there could be another problem +    (access to an uninitialized mailbox). + +  2007-03-21 Simon Goldschmidt +  * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed +    by casting to unsigned). + +  2007-03-21 Frédéric Bernon +  * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from +    api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a +    dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call. +    Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a +    faster and more reliable communication between api_lib and tcpip. + +  2007-03-21 Frédéric Bernon +  * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0. + +  2007-03-21 Frédéric Bernon +  * api_msg.c, igmp.c, igmp.h: Fix C++ style comments + +  2007-03-21 Kieran Mansley +  * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS + +    IP and TCP headers + +  2007-03-21 Kieran Mansley +  * Fix all uses of pbuf_header to check the return value.  In some +    cases just assert if it fails as I'm not sure how to fix them, but +    this is no worse than before when they would carry on regardless +    of the failure. + +  2007-03-21 Kieran Mansley +  * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and +    comment out missing header include in icmp.c + +  2007-03-20 Frédéric Bernon +  * memp.h, stats.c: Fix stats_display function where memp_names table wasn't +    synchronized with memp.h. + +  2007-03-20 Frédéric Bernon +  * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input, +    tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with  +    network interfaces. Also fix a compiler warning. + +  2007-03-20 Kieran Mansley +  * udp.c: Only try and use pbuf_header() to make space for headers if +    not a ROM or REF pbuf. + +  2007-03-19 Frédéric Bernon +  * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg() +    and api_msg_post(). + +  2007-03-19 Frédéric Bernon +  * Remove unimplemented "memp_realloc" function from memp.h. + +  2007-03-11 Simon Goldschmidt +  * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused +    memory corruption. + +  2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov) +  * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251 +    (missing `const' qualifier in socket functions), to get more compatible to +    standard POSIX sockets. + +  2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov) +  * sockets.c: Add asserts inside bind, connect and sendto to check input +    parameters. Remove excessive set_errno() calls after get_socket(), because +    errno is set inside of get_socket(). Move last sock_set_errno() inside +    lwip_close. + +  2007-03-09 Simon Goldschmidt +  * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory +    was allocated too small. + +  2007-03-06 Simon Goldschmidt +  * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect +    the stack from concurrent access. + +  2007-03-06 Frédéric Bernon, Dmitry Potapov +  * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy +    call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input(). + +  2007-03-06 Simon Goldschmidt +  * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files +    if IP_FRAG == 0 and IP_REASSEMBLY == 0 + +  2007-03-06 Frédéric Bernon, Simon Goldschmidt +  * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration +    option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput. +    Allow to do ARP processing for incoming packets inside tcpip_thread +    (protecting ARP layer against concurrent access). You can also disable +    old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0. +    Older ports have to use tcpip_ethinput. + +  2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov) +  * err.h, err.c: fixed compiler warning "initialization dircards qualifiers +    from pointer target type" + +  2007-03-05 Frédéric Bernon +  * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES, +    ETHARP_TRUST_IP_MAC, review SO_REUSE) + +  2007-03-04 Frédéric Bernon +  * api_msg.c: Remove some compiler warnings : parameter "pcb" was never +    referenced. + +  2007-03-04 Frédéric Bernon +  * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from +    Dmitry Potapov). +    The api_msg struct stay on the stack (not moved to netconn struct). + +  2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov) +  * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if +    SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available) +    Also fixed cast warning in pbuf_alloc() + +  2007-03-04 Simon Goldschmidt +  * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt +    existing pbuf chain when enqueuing multiple pbufs to a pending ARP request + +  2007-03-03 Frédéric Bernon +  * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;" +    It is static, and never used in udp.c except udp_init(). + +  2007-03-02 Simon Goldschmidt +  * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from +    tcpip_thread() to tcpip_init(). This way, raw API connections can be +    initialized before tcpip_thread is running (e.g. before OS is started) + +  2007-03-02 Frédéric Bernon +  * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call +    interval. + +  2007-02-28 Kieran Mansley  +  * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved +    outside the region of the pbuf by pbuf_header() + +  2007-02-28 Kieran Mansley  +  * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero +    when supplied timeout is also non-zero  + +(STABLE-1.2.0) + +  2006-12-05 Leon Woestenberg +  * CHANGELOG: Mention STABLE-1.2.0 release. + +  ++ New features: + +  2006-12-01 Christiaan Simons +  * mem.h, opt.h: Added MEM_LIBC_MALLOC option. +    Note this is a workaround. Currently I have no other options left. + +  2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour) +  * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define +    to include/lwip/opt.h. +  * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL. +    Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h. +  * opt.h: Add above new options. + +  2006-08-18 Christiaan Simons +  * tcp_{in,out}.c: added SNMP counters. +  * ipv4/ip.c: added SNMP counters. +  * ipv4/ip_frag.c: added SNMP counters. + +  2006-08-08 Christiaan Simons +  * etharp.{c,h}: added etharp_find_addr() to read +    (stable) ethernet/IP address pair from ARP table + +  2006-07-14 Christiaan Simons +  * mib_structs.c: added +  * include/lwip/snmp_structs.h: added +  * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct + +  2006-07-06 Christiaan Simons +  * snmp/asn1_{enc,dec}.c added +  * snmp/mib2.c added +  * snmp/msg_{in,out}.c added +  * include/lwip/snmp_asn1.h added +  * include/lwip/snmp_msg.h added +  * doc/snmp_agent.txt added + +  2006-03-29 Christiaan Simons +  * inet.c, inet.h: Added platform byteswap support. +    Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and +    optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros. + +  ++ Bug fixes: + +  2006-11-30 Christiaan Simons +  * dhcp.c: Fixed false triggers of request_timeout. + +  2006-11-28 Christiaan Simons +  * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags. + +  2006-10-11 Christiaan Simons +  * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h: +    Partially accepted patch #5449 for ANSI C compatibility / build fixes. +  * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol +    identifier from 170 to 136 (bug #17574). + +  2006-10-10 Christiaan Simons +  * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice. + +  2006-08-17 Christiaan Simons +  * udp.c: Fixed bug #17200, added check for broadcast +    destinations for PCBs bound to a unicast address. + +  2006-08-07 Christiaan Simons +  * api_msg.c: Flushing TCP output in do_close() (bug #15926). + +  2006-06-27 Christiaan Simons +  * api_msg.c: Applied patch for cold case (bug #11135). +    In accept_function() ensure newconn->callback is always initialized. + +  2006-06-15 Christiaan Simons +  * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748), +    facilitate printing of mem_size_t and u16_t statistics. + +  2006-06-14 Christiaan Simons +  * api_msg.c: Applied patch #5146 to handle allocation failures +    in accept() by Kevin Lawson. + +  2006-05-26 Christiaan Simons +  * api_lib.c: Removed conn->sem creation and destruction  +    from netconn_write() and added sys_sem_new to netconn_new_*. + +(STABLE-1_1_1) + +  2006-03-03  Christiaan Simons +  * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap +    access and added pbuf_alloc() return value checks. + +  2006-01-01  Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is +    now handled by the checksum routine properly. + +  2006-02-27  Leon Woestenberg <leon.woestenberg@gmx.net> +   * pbuf.c: Fix alignment; pbuf_init() would not work unless +     pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.) + +  2005-12-20  Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch +    submitted by Mitrani Hiroshi. + +  2005-12-15  Christiaan Simons +  * inet.c: Disabled the added summing routine to preserve code space. + +  2005-12-14  Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson. +    Added Curt McDowell's optimized checksumming routine for future +    inclusion. Need to create test case for unaliged, aligned, odd, +    even length combination of cases on various endianess machines. + +  2005-12-09  Christiaan Simons +  * inet.c: Rewrote standard checksum routine in proper portable C. + +  2005-11-25  Christiaan Simons +  * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only. +  * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t, +    u32_t, s32_t typedefs. This solves most debug word-length assumes. + +  2005-07-17 Leon Woestenberg <leon.woestenberg@gmx.net> +  * inet.c: Fixed unaligned 16-bit access in the standard checksum +    routine by Peter Jolasson. +  * slipif.c: Fixed implementation assumption of single-pbuf datagrams. + +  2005-02-04 Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch. +  * tcp_{out|in}.c: Applied patch fixing unaligned access. + +  2005-01-04 Leon Woestenberg <leon.woestenberg@gmx.net> +  * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement. + +  2005-01-03 Leon Woestenberg <leon.woestenberg@gmx.net> +  * udp.c: UDP pcb->recv() was called even when it was NULL. + +(STABLE-1_1_0) + +  2004-12-28 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.*: Disabled multiple packets on the ARP queue. +    This clashes with TCP queueing. + +  2004-11-28 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.*: Fixed race condition from ARP request to ARP timeout. +    Halved the ARP period, doubled the period counts. +    ETHARP_MAX_PENDING now should be at least 2. This prevents +    the counter from reaching 0 right away (which would allow +    too little time for ARP responses to be received). + +  2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net> +  * dhcp.c: Decline messages were not multicast but unicast. +  * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD. +    Do not try hard to insert arbitrary packet's source address, +    etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD.  +    etharp_query() now always DOES call ETHARP_TRY_HARD so that users +    querying an address will see it appear in the cache (DHCP could +    suffer from this when a server invalidly gave an in-use address.) +  * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are +    comparing network addresses (identifiers), not the network masks +    themselves. +  * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given +    IP address actually belongs to the network of the given interface. + +  2004-11-24 Kieran Mansley <kjm25@cam.ac.uk> +  * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state. + +(STABLE-1_1_0-RC1) + +  2004-10-16 Kieran Mansley <kjm25@cam.ac.uk> +  * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately, +    even if one is already pending, if the rcv_wnd is above a threshold +    (currently TCP_WND/2). This avoids waiting for a timer to expire to send a +    delayed ACK in order to open the window if the stack is only receiving data. + +  2004-09-12 Kieran Mansley <kjm25@cam.ac.uk> +  * tcp*.*: Retransmit time-out handling improvement by Sam Jansen. + +  2004-08-20 Tony Mountifield <tony@softins.co.uk> +  * etharp.c: Make sure the first pbuf queued on an ARP entry +    is properly ref counted. + +  2004-07-27 Tony Mountifield <tony@softins.co.uk> +  * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler +    warnings about comparison. +  * pbuf.c: Stopped compiler complaining of empty if statement +    when LWIP_DEBUGF() empty.  Closed an unclosed comment. +  * tcp.c: Stopped compiler complaining of empty if statement +    when LWIP_DEBUGF() empty. +  * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons(). +  * inet.c: Added a couple of casts to quiet the compiler. +    No need to test isascii(c) before isdigit(c) or isxdigit(c). + +  2004-07-22 Tony Mountifield <tony@softins.co.uk> +  * inet.c: Made data types consistent in inet_ntoa(). +    Added casts for return values of checksum routines, to pacify compiler. +  * ip_frag.c, tcp_out.c, sockets.c, pbuf.c +    Small corrections to some debugging statements, to pacify compiler. + +  2004-07-21 Tony Mountifield <tony@softins.co.uk> +  * etharp.c: Removed spurious semicolon and added missing end-of-comment. +  * ethernetif.c Updated low_level_output() to match prototype for +    netif->linkoutput and changed low_level_input() similarly for consistency. +  * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype +    of raw_recv() in raw.h and so avoid compiler error. +  * sockets.c: Added trivial (int) cast to keep compiler happier. +  * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros. + +(STABLE-1_0_0) + +  ++ Changes: + +  2004-07-05 Leon Woestenberg <leon.woestenberg@gmx.net> +  * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure +    your cc.h file defines this either 1 or 0. If non-defined, +    defaults to 1. +  * .c: Added <string.h> and <errno.h> includes where used. +  * etharp.c: Made some array indices unsigned. + +  2004-06-27 Leon Woestenberg <leon.woestenberg@gmx.net> +  * netif.*: Added netif_set_up()/down(). +  * dhcp.c: Changes to restart program flow. + +  2004-05-07 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.c: In find_entry(), instead of a list traversal per candidate, do a +    single-pass lookup for different candidates. Should exploit locality. + +  2004-04-29 Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp*.c: Cleaned up source comment documentation for Doxygen processing. +  * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC. +  * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by +    the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option. + +  ++ Bug fixes: + +  2004-04-27 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution +    suggested by Timmy Brolin. Fix for 32-bit processors that cannot access +    non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix +    is to prefix the 14-bit Ethernet headers with two padding bytes. + +  2004-04-23 Leon Woestenberg <leon.woestenberg@gmx.net> +  * ip_addr.c: Fix in the ip_addr_isbroadcast() check. +  * etharp.c: Fixed the case where the packet that initiates the ARP request +    is not queued, and gets lost. Fixed the case where the packets destination +    address is already known; we now always queue the packet and perform an ARP +    request. + +(STABLE-0_7_0) + +  ++ Bug fixes: + +  * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition. +  * Fixed TCP bug in dequeueing of FIN from out of order segment queue. +  * Fixed two possible NULL references in rare cases. + +(STABLE-0_6_6) + +  ++ Bug fixes: + +  * Fixed DHCP which did not include the IP address in DECLINE messages. + +  ++ Changes: + +  * etharp.c has been hauled over a bit. + +(STABLE-0_6_5) + +  ++ Bug fixes: + +  * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic. +  * Packets sent from ARP queue had invalid source hardware address. + +  ++ Changes: + +  * Pass-by ARP requests do now update the cache. + +  ++ New features: + +  * No longer dependent on ctype.h. +  * New socket options. +  * Raw IP pcb support. + +(STABLE-0_6_4) + +  ++ Bug fixes: + +  * Some debug formatters and casts fixed. +  * Numereous fixes in PPP. + +  ++ Changes: + +  * DEBUGF now is LWIP_DEBUGF +  * pbuf_dechain() has been re-enabled. +  * Mentioned the changed use of CVS branches in README. + +(STABLE-0_6_3) + +  ++ Bug fixes: + +  * Fixed pool pbuf memory leak in pbuf_alloc(). +    Occured if not enough PBUF_POOL pbufs for a packet pbuf chain. +    Reported by Savin Zlobec. + +  * PBUF_POOL chains had their tot_len field not set for non-first +    pbufs. Fixed in pbuf_alloc(). + +  ++ New features: + +  * Added PPP stack contributed by Marc Boucher + +  ++ Changes: + +  * Now drops short packets for ICMP/UDP/TCP protocols. More robust. + +  * ARP queueuing now queues the latest packet instead of the first. +    This is the RFC recommended behaviour, but can be overridden in +    lwipopts.h. + +(0.6.2) + +  ++ Bugfixes: + +  * TCP has been fixed to deal with the new use of the pbuf->ref +    counter. + +  * DHCP dhcp_inform() crash bug fixed. + +  ++ Changes: + +  * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed +    pbuf_refresh(). This has sped up pbuf pool operations considerably. +    Implemented by David Haas. + +(0.6.1) + +  ++ New features: + +  * The packet buffer implementation has been enhanced to support +    zero-copy and copy-on-demand for packet buffers which have their +    payloads in application-managed memory. +    Implemented by David Haas. + +    Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy +    if an outgoing packet can be directly sent on the link, or perform +    a copy-on-demand when necessary. + +    The application can safely assume the packet is sent, and the RAM +    is available to the application directly after calling udp_send() +    or similar function. + +  ++ Bugfixes: + +  * ARP_QUEUEING should now correctly work for all cases, including +    PBUF_REF. +    Implemented by Leon Woestenberg. + +  ++ Changes: + +  * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer +    to a '0.0.0.0' IP address. + +  * The packet buffer implementation is changed. The pbuf->ref counter +    meaning has changed, and several pbuf functions have been +    adapted accordingly. + +  * netif drivers have to be changed to set the hardware address length field +    that must be initialized correctly by the driver (hint: 6 for Ethernet MAC). +    See the contrib/ports/c16x cs8900 driver as a driver example. + +  * netif's have a dhcp field that must be initialized to NULL by the driver. +    See the contrib/ports/c16x cs8900 driver as a driver example. + +(0.5.x) This file has been unmaintained up to 0.6.1. All changes are +  logged in CVS but have not been explained here. + +(0.5.3) Changes since version 0.5.2 + +  ++ Bugfixes: + +  * memp_malloc(MEMP_API_MSG) could fail with multiple application +    threads because it wasn't protected by semaphores. + +  ++ Other changes: + +  * struct ip_addr now packed. + +  * The name of the time variable in arp.c has been changed to ctime +    to avoid conflicts with the time() function. + +(0.5.2) Changes since version 0.5.1 + +  ++ New features: + +  * A new TCP function, tcp_tmr(), now handles both TCP timers. + +  ++ Bugfixes: + +  * A bug in tcp_parseopt() could cause the stack to hang because of a +    malformed TCP option. + +  * The address of new connections in the accept() function in the BSD +    socket library was not handled correctly. + +  * pbuf_dechain() did not update the ->tot_len field of the tail. + +  * Aborted TCP connections were not handled correctly in all +    situations. + +  ++ Other changes: + +  * All protocol header structs are now packed. + +  * The ->len field in the tcp_seg structure now counts the actual +    amount of data, and does not add one for SYN and FIN segments. + +(0.5.1) Changes since version 0.5.0 + +  ++ New features: + +  * Possible to run as a user process under Linux. + +  * Preliminary support for cross platform packed structs. + +  * ARP timer now implemented. + +  ++ Bugfixes: + +  * TCP output queue length was badly initialized when opening +    connections. + +  * TCP delayed ACKs were not sent correctly. + +  * Explicit initialization of BSS segment variables. + +  * read() in BSD socket library could drop data. + +  * Problems with memory alignment. + +  * Situations when all TCP buffers were used could lead to +    starvation. + +  * TCP MSS option wasn't parsed correctly. + +  * Problems with UDP checksum calculation. + +  * IP multicast address tests had endianess problems. + +  * ARP requests had wrong destination hardware address. + +  ++ Other changes: + +  * struct eth_addr changed from u16_t[3] array to u8_t[6]. + +  * A ->linkoutput() member was added to struct netif. + +  * TCP and UDP ->dest_* struct members where changed to ->remote_*. + +  * ntoh* macros are now null definitions for big endian CPUs. + +(0.5.0) Changes since version 0.4.2 + +  ++ New features: + +  * Redesigned operating system emulation layer to make porting easier. + +  * Better control over TCP output buffers. + +  * Documenation added. + +  ++ Bugfixes: + +  * Locking issues in buffer management. + +  * Bugfixes in the sequential API. + +  * IP forwarding could cause memory leakage. This has been fixed. + +  ++ Other changes: + +  * Directory structure somewhat changed; the core/ tree has been +    collapsed. + +(0.4.2) Changes since version 0.4.1 + +  ++ New features: + +  * Experimental ARP implementation added. + +  * Skeleton Ethernet driver added. + +  * Experimental BSD socket API library added. + +  ++ Bugfixes: + +  * In very intense situations, memory leakage could occur. This has +    been fixed. + +  ++ Other changes: + +  * Variables named "data" and "code" have been renamed in order to +    avoid name conflicts in certain compilers. + +  * Variable++ have in appliciable cases been translated to ++variable +    since some compilers generate better code in the latter case. + +(0.4.1) Changes since version 0.4 + +  ++ New features: + +  * TCP: Connection attempts time out earlier than data +    transmissions. Nagle algorithm implemented. Push flag set on the +    last segment in a burst. + +  * UDP: experimental support for UDP-Lite extensions. + +  ++ Bugfixes: + +  * TCP: out of order segments were in some cases handled incorrectly, +    and this has now been fixed. Delayed acknowledgements was broken +    in 0.4, has now been fixed. Binding to an address that is in use +    now results in an error. Reset connections sometimes hung an +    application; this has been fixed. + +  * Checksum calculation sometimes failed for chained pbufs with odd +    lengths. This has been fixed. + +  * API: a lot of bug fixes in the API. The UDP API has been improved +    and tested. Error reporting and handling has been +    improved. Logical flaws and race conditions for incoming TCP +    connections has been found and removed. + +  * Memory manager: alignment issues. Reallocating memory sometimes +    failed, this has been fixed. + +  * Generic library: bcopy was flawed and has been fixed. + +  ++ Other changes: + +  * API: all datatypes has been changed from generic ones such as +    ints, to specified ones such as u16_t. Functions that return +    errors now have the correct type (err_t). + +  * General: A lot of code cleaned up and debugging code removed. Many +    portability issues have been fixed. + +  * The license was changed; the advertising clause was removed. + +  * C64 port added. + +  * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri +    Kosunen, Mikael Caleres, and Frits Wilmink for reporting and +    fixing bugs! + +(0.4) Changes since version 0.3.1 + +  * Memory management has been radically changed; instead of +    allocating memory from a shared heap, memory for objects that are +    rapidly allocated and deallocated is now kept in pools. Allocation +    and deallocation from those memory pools is very fast. The shared +    heap is still present but is used less frequently. + +  * The memory, memory pool, and packet buffer subsystems now support +    4-, 2-, or 1-byte alignment. + +  * "Out of memory" situations are handled in a more robust way. + +  * Stack usage has been reduced. + +  * Easier configuration of lwIP parameters such as memory usage, +    TTLs, statistics gathering, etc. All configuration parameters are +    now kept in a single header file "lwipopts.h". + +  * The directory structure has been changed slightly so that all +    architecture specific files are kept under the src/arch +    hierarchy. + +  * Error propagation has been improved, both in the protocol modules +    and in the API. + +  * The code for the RTXC architecture has been implemented, tested +    and put to use. + +  * Bugs have been found and corrected in the TCP, UDP, IP, API, and +    the Internet checksum modules. + +  * Bugs related to porting between a 32-bit and a 16-bit architecture +    have been found and corrected. + +  * The license has been changed slightly to conform more with the +    original BSD license, including the advertisement clause. + +(0.3.1) Changes since version 0.3 + +  * Fix of a fatal bug in the buffer management. Pbufs with allocated +    RAM never returned the RAM when the pbuf was deallocated. + +  * TCP congestion control, window updates and retransmissions did not +    work correctly. This has now been fixed. + +  * Bugfixes in the API. + +(0.3) Changes since version 0.2 + +  * New and improved directory structure. All include files are now +    kept in a dedicated include/ directory. + +  * The API now has proper error handling. A new function, +    netconn_err(), now returns an error code for the connection in +    case of errors. + +  * Improvements in the memory management subsystem. The system now +    keeps a pointer to the lowest free memory block. A new function, +    mem_malloc2() tries to allocate memory once, and if it fails tries +    to free some memory and retry the allocation. + +  * Much testing has been done with limited memory +    configurations. lwIP now does a better job when overloaded. + +  * Some bugfixes and improvements to the buffer (pbuf) subsystem. + +  * Many bugfixes in the TCP code: + +    - Fixed a bug in tcp_close(). + +    - The TCP receive window was incorrectly closed when out of +      sequence segments was received. This has been fixed. + +    - Connections are now timed-out of the FIN-WAIT-2 state. + +    - The initial congestion window could in some cases be too +      large. This has been fixed. + +    - The retransmission queue could in some cases be screwed up. This +      has been fixed. + +    - TCP RST flag now handled correctly. + +    - Out of sequence data was in some cases never delivered to the +      application. This has been fixed. + +    - Retransmitted segments now contain the correct acknowledgment +      number and advertised window. + +    - TCP retransmission timeout backoffs are not correctly computed +      (ala BSD). After a number of retransmissions, TCP now gives up +      the connection. + +  * TCP connections now are kept on three lists, one for active +    connections, one for listening connections, and one for +    connections that are in TIME-WAIT. This greatly speeds up the fast +    timeout processing for sending delayed ACKs. + +  * TCP now provides proper feedback to the application when a +    connection has been successfully set up. + +  * More comments have been added to the code. The code has also been +    somewhat cleaned up. + +(0.2) Initial public release. diff --git a/firmware/microblaze/lwip/lwip-1.3.1/COPYING b/firmware/microblaze/lwip/lwip-1.3.1/COPYING new file mode 100644 index 000000000..e23898b5e --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/COPYING @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2001, 2002 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/FILES b/firmware/microblaze/lwip/lwip-1.3.1/FILES new file mode 100644 index 000000000..66253196f --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/FILES @@ -0,0 +1,4 @@ +src/      - The source code for the lwIP TCP/IP stack. +doc/      - The documentation for lwIP. + +See also the FILES file in each subdirectory. diff --git a/firmware/microblaze/lwip/lwip-1.3.1/README b/firmware/microblaze/lwip/lwip-1.3.1/README new file mode 100644 index 000000000..8dda4b468 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/README @@ -0,0 +1,89 @@ +INTRODUCTION + +lwIP is a small independent implementation of the TCP/IP protocol +suite that has been developed by Adam Dunkels at the Computer and +Networks Architectures (CNA) lab at the Swedish Institute of Computer +Science (SICS). + +The focus of the lwIP TCP/IP implementation is to reduce the RAM usage +while still having a full scale TCP. This making lwIP suitable for use +in embedded systems with tens of kilobytes of free RAM and room for +around 40 kilobytes of code ROM. + +FEATURES + +  * IP (Internet Protocol) including packet forwarding over multiple network +    interfaces +  * ICMP (Internet Control Message Protocol) for network maintenance and debugging +  * IGMP (Internet Group Management Protocol) for multicast traffic management +  * UDP (User Datagram Protocol) including experimental UDP-lite extensions +  * TCP (Transmission Control Protocol) with congestion control, RTT estimation +    and fast recovery/fast retransmit +  * Specialized raw/native API for enhanced performance +  * Optional Berkeley-like socket API +  * DNS (Domain names resolver) +  * SNMP (Simple Network Management Protocol) +  * DHCP (Dynamic Host Configuration Protocol) +  * AUTOIP (for IPv4, conform with RFC 3927) +  * PPP (Point-to-Point Protocol) +  * ARP (Address Resolution Protocol) for Ethernet + +LICENSE + +lwIP is freely available under a BSD license. + +DEVELOPMENT + +lwIP has grown into an excellent TCP/IP stack for embedded devices, +and developers using the stack often submit bug fixes, improvements, +and additions to the stack to further increase its usefulness. + +Development of lwIP is hosted on Savannah, a central point for +software development, maintenance and distribution. Everyone can +help improve lwIP by use of Savannah's interface, CVS and the +mailing list. A core team of developers will commit changes to the +CVS source tree. + +The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and +contributions (such as platform ports) are in the 'contrib' module. + +See doc/savannah.txt for details on CVS server access for users and +developers. + +Last night's CVS tar ball can be downloaded from: +  http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING] + +The current CVS trees are web-browsable: +  http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/ +  http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/ + +Submit patches and bugs via the lwIP project page: +  http://savannah.nongnu.org/projects/lwip/ + + +DOCUMENTATION + +The original out-dated homepage of lwIP and Adam Dunkels' papers on +lwIP are at the official lwIP home page: +  http://www.sics.se/~adam/lwip/ + +Self documentation of the source code is regularly extracted from the +current CVS sources and is available from this web page: +  http://www.nongnu.org/lwip/ + +There is now a constantly growin wiki about lwIP at +  http://lwip.scribblewiki.com/ + +Also, there are mailing lists you can subscribe at +  http://savannah.nongnu.org/mail/?group=lwip +plus searchable archives: +  http://lists.nongnu.org/archive/html/lwip-users/ +  http://lists.nongnu.org/archive/html/lwip-devel/ + +Reading Adam's papers, the files in docs/, browsing the source code +documentation and browsing the mailing list archives is a good way to +become familiar with the design of lwIP. + +Adam Dunkels <adam@sics.se> +Leon Woestenberg <leon.woestenberg@gmx.net> + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/doc/FILES b/firmware/microblaze/lwip/lwip-1.3.1/doc/FILES new file mode 100644 index 000000000..05d356f4f --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/doc/FILES @@ -0,0 +1,6 @@ +savannah.txt   - How to obtain the current development source code. +contrib.txt    - How to contribute to lwIP as a developer. +rawapi.txt     - The documentation for the core API of lwIP. +                 Also provides an overview about the other APIs and multithreading. +snmp_agent.txt - The documentation for the lwIP SNMP agent. +sys_arch.txt   - The documentation for a system abstraction layer of lwIP. diff --git a/firmware/microblaze/lwip/lwip-1.3.1/doc/contrib.txt b/firmware/microblaze/lwip/lwip-1.3.1/doc/contrib.txt new file mode 100644 index 000000000..39596fca3 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/doc/contrib.txt @@ -0,0 +1,63 @@ +1 Introduction + +This document describes some guidelines for people participating +in lwIP development. + +2 How to contribute to lwIP + +Here is a short list of suggestions to anybody working with lwIP and  +trying to contribute bug reports, fixes, enhancements, platform ports etc. +First of all as you may already know lwIP is a volunteer project so feedback +to fixes or questions might often come late. Hopefully the bug and patch tracking  +features of Savannah help us not lose users' input. + +2.1 Source code style: + +1. do not use tabs. +2. indentation is two spaces per level (i.e. per tab). +3. end debug messages with a trailing newline (\n). +4. one space between keyword and opening bracket. +5. no space between function and opening bracket. +6. one space and no newline before opening curly braces of a block. +7. closing curly brace on a single line. +8. spaces surrounding assignment and comparisons. +9. don't initialize static and/or global variables to zero, the compiler takes care of that. +10. use current source code style as further reference. + +2.2 Source code documentation style: + +1. JavaDoc compliant and Doxygen compatible. +2. Function documentation above functions in .c files, not .h files. +   (This forces you to synchronize documentation and implementation.) +3. Use current documentation style as further reference. +  +2.3 Bug reports and patches: + +1. Make sure you are reporting bugs or send patches against the latest +   sources. (From the latest release and/or the current CVS sources.) +2. If you think you found a bug make sure it's not already filed in the +   bugtracker at Savannah. +3. If you have a fix put the patch on Savannah. If it is a patch that affects +   both core and arch specific stuff please separate them so that the core can +   be applied separately while leaving the other patch 'open'. The prefered way +   is to NOT touch archs you can't test and let maintainers take care of them. +   This is a good way to see if they are used at all - the same goes for unix +   netifs except tapif. +4. Do not file a bug and post a fix to it to the patch area. Either a bug report +   or a patch will be enough. +   If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area. +5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two) +   can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded +   as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead +   for reporting a compiler warning fix. +6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other +   trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you +   change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than +   if it's not to the point and long :) so the chances for it to be applied are greater.  + +2.4 Platform porters: + +1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and +   you think it could benefit others[1] you might want discuss this on the mailing list. You +   can also ask for CVS access to submit and maintain your port in the contrib CVS module. +   
\ No newline at end of file diff --git a/firmware/microblaze/lwip/lwip-1.3.1/doc/rawapi.txt b/firmware/microblaze/lwip/lwip-1.3.1/doc/rawapi.txt new file mode 100644 index 000000000..8eec6e786 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/doc/rawapi.txt @@ -0,0 +1,478 @@ +Raw TCP/IP interface for lwIP + +Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons + +lwIP provides three Application Program's Interfaces (APIs) for programs +to use for communication with the TCP/IP code: +* low-level "core" / "callback" or "raw" API. +* higher-level "sequential" API. +* BSD-style socket API. + +The sequential API provides a way for ordinary, sequential, programs +to use the lwIP stack. It is quite similar to the BSD socket API. The +model of execution is based on the blocking open-read-write-close +paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP +code and the application program must reside in different execution +contexts (threads). + +The socket API is a compatibility API for existing applications, +currently it is built on top of the sequential API. It is meant to +provide all functions needed to run socket API applications running +on other platforms (e.g. unix / windows etc.). However, due to limitations +in the specification of this API, there might be incompatibilities +that require small modifications of existing programs. + +** Threading + +lwIP started targeting single-threaded environments. When adding multi- +threading support, instead of making the core thread-safe, another +approach was chosen: there is one main thread running the lwIP core +(also known as the "tcpip_thread"). The raw API may only be used from +this thread! Application threads using the sequential- or socket API +communicate with this main thread through message passing. + +      As such, the list of functions that may be called from +      other threads or an ISR is very limited! Only functions +      from these API header files are thread-safe: +      - api.h +      - netbuf.h +      - netdb.h +      - netifapi.h +      - sockets.h +      - sys.h + +      Additionaly, memory (de-)allocation functions may be +      called from multiple threads (not ISR!) with NO_SYS=0 +      since they are protected by SYS_LIGHTWEIGHT_PROT and/or +      semaphores. + +      Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1 +      and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, +      pbuf_free() may also be called from another thread or +      an ISR (since only then, mem_free - for PBUF_RAM - may +      be called from an ISR: otherwise, the HEAP is only +      protected by semaphores). +       + +** The remainder of this document discusses the "raw" API. ** + +The raw TCP/IP interface allows the application program to integrate +better with the TCP/IP code. Program execution is event based by +having callback functions being called from within the TCP/IP +code. The TCP/IP code and the application program both run in the same +thread. The sequential API has a much higher overhead and is not very +well suited for small systems since it forces a multithreaded paradigm +on the application. + +The raw TCP/IP interface is not only faster in terms of code execution +time but is also less memory intensive. The drawback is that program +development is somewhat harder and application programs written for +the raw TCP/IP interface are more difficult to understand. Still, this +is the preferred way of writing applications that should be small in +code size and memory usage. + +Both APIs can be used simultaneously by different application +programs. In fact, the sequential API is implemented as an application +program using the raw TCP/IP interface. + +--- Callbacks + +Program execution is driven by callbacks. Each callback is an ordinary +C function that is called from within the TCP/IP code. Every callback +function is passed the current TCP or UDP connection state as an +argument. Also, in order to be able to keep program specific state, +the callback functions are called with a program specified argument +that is independent of the TCP/IP state. + +The function for setting the application connection state is: + +- void tcp_arg(struct tcp_pcb *pcb, void *arg) + +  Specifies the program specific state that should be passed to all +  other callback functions. The "pcb" argument is the current TCP +  connection control block, and the "arg" argument is the argument +  that will be passed to the callbacks. + +   +--- TCP connection setup + +The functions used for setting up connections is similar to that of +the sequential API and of the BSD socket API. A new TCP connection +identifier (i.e., a protocol control block - PCB) is created with the +tcp_new() function. This PCB can then be either set to listen for new +incoming connections or be explicitly connected to another host. + +- struct tcp_pcb *tcp_new(void) + +  Creates a new connection identifier (PCB). If memory is not +  available for creating the new pcb, NULL is returned. + +- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port) + +  Binds the pcb to a local IP address and port number. The IP address +  can be specified as IP_ADDR_ANY in order to bind the connection to +  all local IP addresses. + +  If another connection is bound to the same port, the function will +  return ERR_USE, otherwise ERR_OK is returned. + +- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb) + +  Commands a pcb to start listening for incoming connections. When an +  incoming connection is accepted, the function specified with the +  tcp_accept() function will be called. The pcb will have to be bound +  to a local port with the tcp_bind() function. + +  The tcp_listen() function returns a new connection identifier, and +  the one passed as an argument to the function will be +  deallocated. The reason for this behavior is that less memory is +  needed for a connection that is listening, so tcp_listen() will +  reclaim the memory needed for the original connection and allocate a +  new smaller memory block for the listening connection. + +  tcp_listen() may return NULL if no memory was available for the +  listening connection. If so, the memory associated with the pcb +  passed as an argument to tcp_listen() will not be deallocated. + +- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) + +  Same as tcp_listen, but limits the number of outstanding connections +  in the listen queue to the value specified by the backlog argument. +  To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. + +- void tcp_accepted(struct tcp_pcb *pcb) + +  Inform lwIP that an incoming connection has been accepted. This would +  usually be called from the accept callback. This allows lwIP to perform +  housekeeping tasks, such as allowing further incoming connections to be +  queued in the listen backlog. + +- void tcp_accept(struct tcp_pcb *pcb, +                  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, +                                   err_t err)) + +  Specified the callback function that should be called when a new +  connection arrives on a listening connection. +       +- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                    u16_t port, err_t (* connected)(void *arg, +                                                    struct tcp_pcb *tpcb, +                                                    err_t err)); + +  Sets up the pcb to connect to the remote host and sends the +  initial SYN segment which opens the connection.  + +  The tcp_connect() function returns immediately; it does not wait for +  the connection to be properly setup. Instead, it will call the +  function specified as the fourth argument (the "connected" argument) +  when the connection is established. If the connection could not be +  properly established, either because the other host refused the +  connection or because the other host didn't answer, the "err" +  callback function of this pcb (registered with tcp_err, see below) +  will be called. + +  The tcp_connect() function can return ERR_MEM if no memory is +  available for enqueueing the SYN segment. If the SYN indeed was +  enqueued successfully, the tcp_connect() function returns ERR_OK. + +   +--- Sending TCP data + +TCP data is sent by enqueueing the data with a call to +tcp_write(). When the data is successfully transmitted to the remote +host, the application will be notified with a call to a specified +callback function. + +- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len, +                  u8_t copy) + +  Enqueues the data pointed to by the argument dataptr. The length of +  the data is passed as the len parameter. The copy argument is either +  0 or 1 and indicates whether the new memory should be allocated for +  the data to be copied into. If the argument is 0, no new memory +  should be allocated and the data should only be referenced by +  pointer. + +  The tcp_write() function will fail and return ERR_MEM if the length +  of the data exceeds the current send buffer size or if the length of +  the queue of outgoing segment is larger than the upper limit defined +  in lwipopts.h. The number of bytes available in the output queue can +  be retrieved with the tcp_sndbuf() function. + +  The proper way to use this function is to call the function with at +  most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, +  the application should wait until some of the currently enqueued +  data has been successfully received by the other host and try again. + +- void tcp_sent(struct tcp_pcb *pcb, +                err_t (* sent)(void *arg, struct tcp_pcb *tpcb, +                u16_t len)) + +  Specifies the callback function that should be called when data has +  successfully been received (i.e., acknowledged) by the remote +  host. The len argument passed to the callback function gives the +  amount bytes that was acknowledged by the last acknowledgment. + +   +--- Receiving TCP data + +TCP data reception is callback based - an application specified +callback function is called when new data arrives. When the +application has taken the data, it has to call the tcp_recved() +function to indicate that TCP can advertise increase the receive +window. + +- void tcp_recv(struct tcp_pcb *pcb, +                err_t (* recv)(void *arg, struct tcp_pcb *tpcb, +                               struct pbuf *p, err_t err)) + +  Sets the callback function that will be called when new data +  arrives. The callback function will be passed a NULL pbuf to +  indicate that the remote host has closed the connection. If +  there are no errors and the callback function is to return +  ERR_OK, then it must free the pbuf. Otherwise, it must not +  free the pbuf so that lwIP core code can store it. + +- void tcp_recved(struct tcp_pcb *pcb, u16_t len) + +  Must be called when the application has received the data. The len +  argument indicates the length of the received data. +     + +--- Application polling + +When a connection is idle (i.e., no data is either transmitted or +received), lwIP will repeatedly poll the application by calling a +specified callback function. This can be used either as a watchdog +timer for killing connections that have stayed idle for too long, or +as a method of waiting for memory to become available. For instance, +if a call to tcp_write() has failed because memory wasn't available, +the application may use the polling functionality to call tcp_write() +again when the connection has been idle for a while. + +- void tcp_poll(struct tcp_pcb *pcb, u8_t interval, +                err_t (* poll)(void *arg, struct tcp_pcb *tpcb)) + +  Specifies the polling interval and the callback function that should +  be called to poll the application. The interval is specified in +  number of TCP coarse grained timer shots, which typically occurs +  twice a second. An interval of 10 means that the application would +  be polled every 5 seconds. + + +--- Closing and aborting connections + +- err_t tcp_close(struct tcp_pcb *pcb) + +  Closes the connection. The function may return ERR_MEM if no memory +  was available for closing the connection. If so, the application +  should wait and try again either by using the acknowledgment +  callback or the polling functionality. If the close succeeds, the +  function returns ERR_OK. + +  The pcb is deallocated by the TCP code after a call to tcp_close().  + +- void tcp_abort(struct tcp_pcb *pcb) + +  Aborts the connection by sending a RST (reset) segment to the remote +  host. The pcb is deallocated. This function never fails. + +If a connection is aborted because of an error, the application is +alerted of this event by the err callback. Errors that might abort a +connection are when there is a shortage of memory. The callback +function to be called is set using the tcp_err() function. + +- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, +       err_t err)) + +  The error callback function does not get the pcb passed to it as a +  parameter since the pcb may already have been deallocated. + + +--- Lower layer TCP interface + +TCP provides a simple interface to the lower layers of the +system. During system initialization, the function tcp_init() has +to be called before any other TCP function is called. When the system +is running, the two timer functions tcp_fasttmr() and tcp_slowtmr() +must be called with regular intervals. The tcp_fasttmr() should be +called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and +tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.  + + +--- UDP interface + +The UDP interface is similar to that of TCP, but due to the lower +level of complexity of UDP, the interface is significantly simpler. + +- struct udp_pcb *udp_new(void) + +  Creates a new UDP pcb which can be used for UDP communication. The +  pcb is not active until it has either been bound to a local address +  or connected to a remote address. + +- void udp_remove(struct udp_pcb *pcb) + +  Removes and deallocates the pcb.   +   +- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port) + +  Binds the pcb to a local address. The IP-address argument "ipaddr" +  can be IP_ADDR_ANY to indicate that it should listen to any local IP +  address. The function currently always return ERR_OK. + +- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, +                    u16_t port) + +  Sets the remote end of the pcb. This function does not generate any +  network traffic, but only set the remote address of the pcb. + +- err_t udp_disconnect(struct udp_pcb *pcb) + +  Remove the remote end of the pcb. This function does not generate +  any network traffic, but only removes the remote address of the pcb. + +- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) + +  Sends the pbuf p. The pbuf is not deallocated. + +- void udp_recv(struct udp_pcb *pcb, +                void (* recv)(void *arg, struct udp_pcb *upcb, +                                         struct pbuf *p, +                                         struct ip_addr *addr, +                                         u16_t port), +                              void *recv_arg) + +  Specifies a callback function that should be called when a UDP +  datagram is received. +   + +--- System initalization + +A truly complete and generic sequence for initializing the lwip stack +cannot be given because it depends on the build configuration (lwipopts.h) +and additional initializations for your runtime environment (e.g. timers). + +We can give you some idea on how to proceed when using the raw API. +We assume a configuration using a single Ethernet netif and the +UDP and TCP transport layers, IPv4 and the DHCP client. + +Call these functions in the order of appearance: + +- stats_init() + +  Clears the structure where runtime statistics are gathered. + +- sys_init() +   +  Not of much use since we set the NO_SYS 1 option in lwipopts.h, +  to be called for easy configuration changes. + +- mem_init() + +  Initializes the dynamic memory heap defined by MEM_SIZE. + +- memp_init() + +  Initializes the memory pools defined by MEMP_NUM_x. + +- pbuf_init() + +  Initializes the pbuf memory pool defined by PBUF_POOL_SIZE. +   +- etharp_init() + +  Initializes the ARP table and queue. +  Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval +  after this initialization. + +- ip_init() + +  Doesn't do much, it should be called to handle future changes. + +- udp_init() + +  Clears the UDP PCB list. + +- tcp_init() + +  Clears the TCP PCB list and clears some internal TCP timers. +  Note: you must call tcp_fasttmr() and tcp_slowtmr() at the +  predefined regular intervals after this initialization.  +   +- netif_add(struct netif *netif, struct ip_addr *ipaddr, +            struct ip_addr *netmask, struct ip_addr *gw, +            void *state, err_t (* init)(struct netif *netif), +            err_t (* input)(struct pbuf *p, struct netif *netif)) + +  Adds your network interface to the netif_list. Allocate a struct +  netif and pass a pointer to this structure as the first argument. +  Give pointers to cleared ip_addr structures when using DHCP, +  or fill them with sane numbers otherwise. The state pointer may be NULL. + +  The init function pointer must point to a initialization function for +  your ethernet netif interface. The following code illustrates it's use. +   +  err_t netif_if_init(struct netif *netif) +  { +    u8_t i; +     +    for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i]; +    init_my_eth_device(); +    return ERR_OK; +  } +   +  For ethernet drivers, the input function pointer must point to the lwip +  function ethernet_input() declared in "netif/etharp.h". Other drivers +  must use ip_input() declared in "lwip/ip.h". +   +- netif_set_default(struct netif *netif) + +  Registers the default network interface. + +- netif_set_up(struct netif *netif) + +  When the netif is fully configured this function must be called. + +- dhcp_start(struct netif *netif) + +  Creates a new DHCP client for this interface on the first call. +  Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at +  the predefined regular intervals after starting the client. +   +  You can peek in the netif->dhcp struct for the actual DHCP status. + + +--- Optimalization hints + +The first thing you want to optimize is the lwip_standard_checksum() +routine from src/core/inet.c. You can override this standard +function with the #define LWIP_CHKSUM <your_checksum_routine>. + +There are C examples given in inet.c or you might want to +craft an assembly function for this. RFC1071 is a good +introduction to this subject. + +Other significant improvements can be made by supplying +assembly or inline replacements for htons() and htonl() +if you're using a little-endian architecture. +#define LWIP_PLATFORM_BYTESWAP 1 +#define LWIP_PLATFORM_HTONS(x) <your_htons> +#define LWIP_PLATFORM_HTONL(x) <your_htonl> + +Check your network interface driver if it reads at +a higher speed than the maximum wire-speed. If the +hardware isn't serviced frequently and fast enough +buffer overflows are likely to occur. + +E.g. when using the cs8900 driver, call cs8900if_service(ethif) +as frequently as possible. When using an RTOS let the cs8900 interrupt +wake a high priority task that services your driver using a binary +semaphore or event flag. Some drivers might allow additional tuning +to match your application and network. + +For a production release it is recommended to set LWIP_STATS to 0. +Note that speed performance isn't influenced much by simply setting +high values to the memory options. diff --git a/firmware/microblaze/lwip/lwip-1.3.1/doc/savannah.txt b/firmware/microblaze/lwip/lwip-1.3.1/doc/savannah.txt new file mode 100644 index 000000000..409905b10 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/doc/savannah.txt @@ -0,0 +1,135 @@ +Daily Use Guide for using Savannah for lwIP + +Table of Contents: + +1 - Obtaining lwIP from the CVS repository +2 - Committers/developers CVS access using SSH (to be written) +3 - Merging from DEVEL branch to main trunk (stable branch) +4 - How to release lwIP + + + +1 Obtaining lwIP from the CVS repository +---------------------------------------- + +To perform an anonymous CVS checkout of the main trunk (this is where +bug fixes and incremental enhancements occur), do this: + +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip +  +Or, obtain a stable branch (updated with bug fixes only) as follows: +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ +  -r STABLE-0_7 -d lwip-0.7 lwip + +Or, obtain a specific (fixed) release as follows: +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ +  -r STABLE-0_7_0 -d lwip-0.7.0 lwip + +3 Committers/developers CVS access using SSH +-------------------------------------------- + +The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption. +As such, CVS commits to the server occur through a SSH tunnel for project members. +To create a SSH2 key pair in UNIX-like environments, do this: + +ssh-keygen -t dsa + +Under Windows, a recommended SSH client is "PuTTY", freely available with good +documentation and a graphic user interface. Use its key generator. + +Now paste the id_dsa.pub contents into your Savannah account public key list. Wait +a while so that Savannah can update its configuration (This can take minutes). + +Try to login using SSH: + +ssh -v your_login@cvs.sv.gnu.org + +If it tells you: + +Authenticating with public key "your_key_name"... +Server refused to allocate pty + +then you could login; Savannah refuses to give you a shell - which is OK, as we +are allowed to use SSH for CVS only. Now, you should be able to do this: + +export CVS_RSH=ssh +cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip +  +after which you can edit your local files with bug fixes or new features and +commit them. Make sure you know what you are doing when using CVS to make +changes on the repository. If in doubt, ask on the lwip-members mailing list. + +(If SSH asks about authenticity of the host, you can check the key + fingerprint against http://savannah.nongnu.org/cvs/?group=lwip) + + +3 Merging from DEVEL branch to main trunk (stable) +-------------------------------------------------- + +Merging is a delicate process in CVS and requires the +following disciplined steps in order to prevent conflicts +in the future. Conflicts can be hard to solve! + +Merging from branch A to branch B requires that the A branch +has a tag indicating the previous merger. This tag is called +'merged_from_A_to_B'. After merging, the tag is moved in the +A branch to remember this merger for future merge actions. + +IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE +REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE +MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME). + +Merge all changes in DEVEL since our last merge to main: + +In the working copy of the main trunk: +cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL  + +(This will apply the changes between 'merged_from_DEVEL_to_main' +and 'DEVEL' to your work set of files) + +We can now commit the merge result. +cvs commit -R -m "Merged from DEVEL to main."  + +If this worked out OK, we now move the tag in the DEVEL branch +to this merge point, so we can use this point for future merges: + +cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip  + +4 How to release lwIP +--------------------- + +First, checkout a clean copy of the branch to be released. Tag this set with +tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example). + +Login CVS using pserver authentication, then export a clean copy of the +tagged tree. Export is similar to a checkout, except that the CVS metadata +is not created locally.  + +export CVS_RSH=ssh +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ +  -r STABLE-0_6_3 -d lwip-0.6.3 lwip + +Archive this directory using tar, gzip'd, bzip2'd and zip'd. + +tar czvf lwip-0.6.3.tar.gz lwip-0.6.3 +tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3 +zip -r lwip-0.6.3.zip lwip-0.6.3 + +Now, sign the archives with a detached GPG binary signature as follows: + +gpg -b lwip-0.6.3.tar.gz +gpg -b lwip-0.6.3.tar.bz2 +gpg -b lwip-0.6.3.zip + +Upload these files using anonymous FTP: +ncftp ftp://savannah.gnu.org/incoming/savannah/lwip + +ncftp>mput *0.6.3.* + +Additionally, you may post a news item on Savannah, like this: + +A new 0.6.3 release is now available here: +http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3 + +You will have to submit this via the user News interface, then approve +this via the Administrator News interface.
\ No newline at end of file diff --git a/firmware/microblaze/lwip/lwip-1.3.1/doc/snmp_agent.txt b/firmware/microblaze/lwip/lwip-1.3.1/doc/snmp_agent.txt new file mode 100644 index 000000000..9b58616a6 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/doc/snmp_agent.txt @@ -0,0 +1,181 @@ +SNMPv1 agent for lwIP + +Author: Christiaan Simons + +This is a brief introduction how to use and configure the SNMP agent. +Note the agent uses the raw-API UDP interface so you may also want to +read rawapi.txt to gain a better understanding of the SNMP message handling. + +0 Agent Capabilities +==================== + +SNMPv1 per RFC1157 +  This is an old(er) standard but is still widely supported. +  For SNMPv2c and v3 have a greater complexity and need many +  more lines of code. IMHO this breaks the idea of "lightweight IP". + +  Note the S in SNMP stands for "Simple". Note that "Simple" is +  relative. SNMP is simple compared to the complex ISO network +  management protocols CMIP (Common Management Information Protocol) +  and CMOT (CMip Over Tcp). + +MIB II per RFC1213 +  The standard lwIP stack management information base. +  This is a required MIB, so this is always enabled. +  When builing lwIP without TCP, the mib-2.tcp group is omitted. +  The groups EGP, CMOT and transmission are disabled by default. +   +  Most mib-2 objects are not writable except: +  sysName, sysLocation, sysContact, snmpEnableAuthenTraps. +  Writing to or changing the ARP and IP address and route +  tables is not possible. +  +  Note lwIP has a very limited notion of IP routing. It currently +  doen't have a route table and doesn't have a notion of the U,G,H flags. +  Instead lwIP uses the interface list with only one default interface +  acting as a single gateway interface (G) for the default route. + +  The agent returns a "virtual table" with the default route 0.0.0.0 +  for the default interface and network routes (no H) for each +  network interface in the netif_list. +  All routes are considered to be up (U). + +Loading additional MIBs +  MIBs can only be added in compile-time, not in run-time. +  There is no MIB compiler thus additional MIBs must be hand coded. + +Large SNMP message support +  The packet decoding and encoding routines are designed +  to use pbuf-chains. Larger payloads then the minimum +  SNMP requirement of 484 octets are supported if the  +  PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your +  local requirement. + +1 Building the Agent +==================== + +First of all you'll need to add the following define +to your local lwipopts.h: + +#define LWIP_SNMP               1 + +and add the source files in lwip/src/core/snmp +and some snmp headers in lwip/src/include/lwip to your makefile. + +Note you'll might need to adapt you network driver to update +the mib2 variables for your interface. + +2 Running the Agent +=================== + +The following function calls must be made in your program to +actually get the SNMP agent running. + +Before starting the agent you should supply pointers +to non-volatile memory for sysContact, sysLocation, +and snmpEnableAuthenTraps. You can do this by calling + +snmp_set_syscontact() +snmp_set_syslocation() +snmp_set_snmpenableauthentraps() + +Additionally you may want to set + +snmp_set_sysdescr() +snmp_set_sysobjid() (if you have a private MIB) +snmp_set_sysname() + +Also before starting the agent you need to setup +one or more trap destinations using these calls: + +snmp_trap_dst_enable(); +snmp_trap_dst_ip_set(); + +In the lwIP initialisation sequence call snmp_init() just after +the call to udp_init(). + +Exactly every 10 msec the SNMP uptime timestamp must be updated with +snmp_inc_sysuptime(). You should call this from a timer interrupt +or a timer signal handler depending on your runtime environment. + +An alternative way to update the SNMP uptime timestamp is to do a call like +snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to +a lower frequency). Another one is to not call snmp_inc_sysuptime() or +snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. +This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside +snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only +when it's queried (any function which need "sysuptime" have to call +snmp_get_sysuptime). + + +3 Private MIBs +============== + +If want to extend the agent with your own private MIB you'll need to +add the following define to your local lwipopts.h: + +#define SNMP_PRIVATE_MIB        1 + +You must provide the private_mib.h and associated files yourself. +Note we don't have a "MIB compiler" that generates C source from a MIB, +so you're required to do some serious coding if you enable this! + +Note the lwIP enterprise ID (26381) is assigned to the lwIP project, +ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP +MAINTAINERS! + +If you need to create your own private MIB you'll need +to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html  + +You can set it by passing a struct snmp_obj_id to the agent +using snmp_set_sysobjid(&my_object_id), just before snmp_init(). + +Note the object identifiers for thes MIB-2 and your private MIB +tree must be kept in sorted ascending (lexicographical) order. +This to ensure correct getnext operation. + +An example for a private MIB is part of the "minimal Unix" project: +contrib/ports/unix/proj/minimal/lwip_prvmib.c + +The next chapter gives a more detailed description of the +MIB-2 tree and the optional private MIB. + +4 The Gory Details +================== + +4.0 Object identifiers and the MIB tree. + +We have three distinct parts for all object identifiers: + +The prefix +  .iso.org.dod.internet + +the middle part  +  .mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress + +and the index part +  .1.192.168.0.1 + +Objects located above the .internet hierarchy aren't supported. +Currently only the .mgmt sub-tree is available and +when the SNMP_PRIVATE_MIB is enabled the .private tree +becomes available too. + +Object identifiers from incoming requests are checked +for a matching prefix, middle part and index part +or are expanded(*) for GetNext requests with short +or inexisting names in the request. +(* we call this "expansion" but this also +resembles the "auto-completion" operation) + +The middle part is usually located in ROM (const) +to preserve precious RAM on small microcontrollers. +However RAM location is possible for an dynamically +changing private tree. + +The index part is handled by functions which in +turn use dynamically allocated index trees from RAM. +These trees are updated by e.g. the etharp code +when new entries are made or removed form the ARP cache. + +/** @todo more gory details */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/doc/sys_arch.txt b/firmware/microblaze/lwip/lwip-1.3.1/doc/sys_arch.txt new file mode 100644 index 000000000..66310a91e --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/doc/sys_arch.txt @@ -0,0 +1,228 @@ +sys_arch interface for lwIP 0.6++ + +Author: Adam Dunkels + +The operating system emulation layer provides a common interface +between the lwIP code and the underlying operating system kernel. The +general idea is that porting lwIP to new architectures requires only +small changes to a few header files and a new sys_arch +implementation. It is also possible to do a sys_arch implementation +that does not rely on any underlying operating system. + +The sys_arch provides semaphores and mailboxes to lwIP. For the full +lwIP functionality, multiple threads support can be implemented in the +sys_arch, but this is not required for the basic lwIP +functionality. Previous versions of lwIP required the sys_arch to +implement timer scheduling as well but as of lwIP 0.5 this is +implemented in a higher layer. + +In addition to the source file providing the functionality of sys_arch, +the OS emulation layer must provide several header files defining +macros used throughout lwip.  The files required and the macros they +must define are listed below the sys_arch description. + +Semaphores can be either counting or binary - lwIP works with both +kinds. Mailboxes are used for message passing and can be implemented +either as a queue which allows multiple messages to be posted to a +mailbox, or as a rendez-vous point where only one message can be +posted at a time. lwIP works with both kinds, but the former type will +be more efficient. A message in a mailbox is just a pointer, nothing +more.  + +Semaphores are represented by the type "sys_sem_t" which is typedef'd +in the sys_arch.h file. Mailboxes are equivalently represented by the +type "sys_mbox_t". lwIP does not place any restrictions on how +sys_sem_t or sys_mbox_t are represented internally. + +The following functions must be implemented by the sys_arch: + +- void sys_init(void) + +  Is called to initialize the sys_arch layer. + +- sys_sem_t sys_sem_new(u8_t count) + +  Creates and returns a new semaphore. The "count" argument specifies +  the initial state of the semaphore. + +- void sys_sem_free(sys_sem_t sem) + +  Deallocates a semaphore. + +- void sys_sem_signal(sys_sem_t sem) + +  Signals a semaphore. + +- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) + +  Blocks the thread while waiting for the semaphore to be +  signaled. If the "timeout" argument is non-zero, the thread should +  only be blocked for the specified time (measured in +  milliseconds). If the "timeout" argument is zero, the thread should be +  blocked until the semaphore is signalled. + +  If the timeout argument is non-zero, the return value is the number of +  milliseconds spent waiting for the semaphore to be signaled. If the +  semaphore wasn't signaled within the specified time, the return value is +  SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore +  (i.e., it was already signaled), the function may return zero. + +  Notice that lwIP implements a function with a similar name, +  sys_sem_wait(), that uses the sys_arch_sem_wait() function. + +- sys_mbox_t sys_mbox_new(int size) + +  Creates an empty mailbox for maximum "size" elements. Elements stored +  in mailboxes are pointers. You have to define macros "_MBOX_SIZE" +  in your lwipopts.h, or ignore this parameter in your implementation +  and use a default size. + +- void sys_mbox_free(sys_mbox_t mbox) + +  Deallocates a mailbox. If there are messages still present in the +  mailbox when the mailbox is deallocated, it is an indication of a +  programming error in lwIP and the developer should be notified. + +- void sys_mbox_post(sys_mbox_t mbox, void *msg) + +  Posts the "msg" to the mailbox. This function have to block until +  the "msg" is really posted. + +- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg) + +  Try to post the "msg" to the mailbox. Returns ERR_MEM if this one +  is full, else, ERR_OK if the "msg" is posted. + +- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) + +  Blocks the thread until a message arrives in the mailbox, but does +  not block the thread longer than "timeout" milliseconds (similar to +  the sys_arch_sem_wait() function). If "timeout" is 0, the thread should +  be blocked until a message arrives. The "msg" argument is a result +  parameter that is set by the function (i.e., by doing "*msg = +  ptr"). The "msg" parameter maybe NULL to indicate that the message +  should be dropped. + +  The return values are the same as for the sys_arch_sem_wait() function: +  Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a +  timeout. + +  Note that a function with a similar name, sys_mbox_fetch(), is +  implemented by lwIP.  + +- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) + +  This is similar to sys_arch_mbox_fetch, however if a message is not +  present in the mailbox, it immediately returns with the code +  SYS_MBOX_EMPTY. On success 0 is returned. + +  To allow for efficient implementations, this can be defined as a +  function-like macro in sys_arch.h instead of a normal function. For +  example, a naive implementation could be: +    #define sys_arch_mbox_tryfetch(mbox,msg) \ +      sys_arch_mbox_fetch(mbox,msg,1) +  although this would introduce unnecessary delays. +   +- struct sys_timeouts *sys_arch_timeouts(void) + +  Returns a pointer to the per-thread sys_timeouts structure. In lwIP, +  each thread has a list of timeouts which is repressented as a linked +  list of sys_timeout structures. The sys_timeouts structure holds a +  pointer to a linked list of timeouts. This function is called by +  the lwIP timeout scheduler and must not return a NULL value.  + +  In a single thread sys_arch implementation, this function will +  simply return a pointer to a global sys_timeouts variable stored in +  the sys_arch module. +   +If threads are supported by the underlying operating system and if +such functionality is needed in lwIP, the following function will have +to be implemented as well: + +- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) + +  Starts a new thread named "name" with priority "prio" that will begin its +  execution in the function "thread()". The "arg" argument will be passed as an +  argument to the thread() function. The stack size to used for this thread is +  the "stacksize" parameter. The id of the new thread is returned. Both the id +  and the priority are system dependent. + +- sys_prot_t sys_arch_protect(void) + +  This optional function does a "fast" critical region protection and returns +  the previous protection level. This function is only called during very short +  critical regions. An embedded system which supports ISR-based drivers might +  want to implement this function by disabling interrupts. Task-based systems +  might want to implement this by using a mutex or disabling tasking. This +  function should support recursive calls from the same task or interrupt. In +  other words, sys_arch_protect() could be called while already protected. In +  that case the return value indicates that it is already protected. + +  sys_arch_protect() is only required if your port is supporting an operating +  system. + +- void sys_arch_unprotect(sys_prot_t pval) + +  This optional function does a "fast" set of critical region protection to the +  value specified by pval. See the documentation for sys_arch_protect() for +  more information. This function is only required if your port is supporting +  an operating system. + +Note: + +Be carefull with using mem_malloc() in sys_arch. When malloc() refers to +mem_malloc() you can run into a circular function call problem. In mem.c +mem_init() tries to allcate a semaphore using mem_malloc, which of course +can't be performed when sys_arch uses mem_malloc. + +------------------------------------------------------------------------------- +Additional files required for the "OS support" emulation layer: +------------------------------------------------------------------------------- + +cc.h       - Architecture environment, some compiler specific, some +             environment specific (probably should move env stuff  +             to sys_arch.h.) + +  Typedefs for the types used by lwip - +    u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t + +  Compiler hints for packing lwip's structures - +    PACK_STRUCT_FIELD(x) +    PACK_STRUCT_STRUCT +    PACK_STRUCT_BEGIN +    PACK_STRUCT_END + +  Platform specific diagnostic output - +    LWIP_PLATFORM_DIAG(x)    - non-fatal, print a message. +    LWIP_PLATFORM_ASSERT(x)  - fatal, print message and abandon execution. +    Portability defines for printf formatters: +    U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F + +  "lightweight" synchronization mechanisms - +    SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable. +    SYS_ARCH_PROTECT(x)      - enter protection mode. +    SYS_ARCH_UNPROTECT(x)    - leave protection mode. + +  If the compiler does not provide memset() this file must include a +  definition of it, or include a file which defines it. + +  This file must either include a system-local <errno.h> which defines +  the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO +  to make lwip/arch.h define the codes which are used throughout. + + +perf.h     - Architecture specific performance measurement. +  Measurement calls made throughout lwip, these can be defined to nothing. +    PERF_START               - start measuring something. +    PERF_STOP(x)             - stop measuring something, and record the result. + +sys_arch.h - Tied to sys_arch.c + +  Arch dependent types for the following objects: +    sys_sem_t, sys_mbox_t, sys_thread_t, +  And, optionally: +    sys_prot_t + +  Defines to set vars of sys_mbox_t and sys_sem_t to NULL. +    SYS_MBOX_NULL NULL +    SYS_SEM_NULL NULL diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/.hgignore b/firmware/microblaze/lwip/lwip-1.3.1/src/.hgignore new file mode 100644 index 000000000..f88587df3 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/.hgignore @@ -0,0 +1,26 @@ +syntax: glob  +  +*.pyc  +*.orig  +*.rej  +*~  +TAGS  +Module.symvers  +*.ncb +*.suo +*.bak +*.orig +*.rej + +syntax: regexp +\.\#.+ +[\\/]CVS$ +^CVS$ +^build$ +^install$ +^logs.build_tree$ +[\\/]bin$ +^bin$ +[\\/]obj$ +^obj$ +\.cvsignore diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/FILES b/firmware/microblaze/lwip/lwip-1.3.1/src/FILES new file mode 100644 index 000000000..952aeabb4 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/FILES @@ -0,0 +1,13 @@ +api/      - The code for the high-level wrapper API. Not needed if +            you use the lowel-level call-back/raw API. + +core/     - The core of the TPC/IP stack; protocol implementations, +            memory and buffer management, and the low-level raw API. + +include/  - lwIP include files. + +netif/    - Generic network interface device drivers are kept here, +            as well as the ARP module. + +For more information on the various subdirectories, check the FILES +file in each directory. diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/api_lib.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/api_lib.c new file mode 100644 index 000000000..86df911ea --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/api_lib.c @@ -0,0 +1,557 @@ +/** + * @file + * Sequential API External module + * + */ +  +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +/* This is the part of the API that is linked with +   the application */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api.h" +#include "lwip/tcpip.h" +#include "lwip/memp.h" + +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include <string.h> + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is also created. + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + *         NULL on memory error + */ +struct netconn* +netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) +{ +  struct netconn *conn; +  struct api_msg msg; + +  conn = netconn_alloc(t, callback); +  if (conn != NULL ) { +    msg.function = do_newconn; +    msg.msg.msg.n.proto = proto; +    msg.msg.conn = conn; +    TCPIP_APIMSG(&msg); + +    if (conn->err != ERR_OK) { +      LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); +      LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL); +      LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL); +      LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL); +      sys_sem_free(conn->op_completed); +      sys_mbox_free(conn->recvmbox); +      memp_free(MEMP_NETCONN, conn); +      return NULL; +    } +  } +  return conn; +} + +/** + * Close a netconn 'connection' and free its resources. + * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate + * after this returns. + * + * @param conn the netconn to delete + * @return ERR_OK if the connection was deleted + */ +err_t +netconn_delete(struct netconn *conn) +{ +  struct api_msg msg; + +  /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ +  if (conn == NULL) { +    return ERR_OK; +  } + +  msg.function = do_delconn; +  msg.msg.conn = conn; +  tcpip_apimsg(&msg); + +  conn->pcb.tcp = NULL; +  netconn_free(conn); + +  return ERR_OK; +} + +/** + * Get the local or remote IP address and port of a netconn. + * For RAW netconns, this returns the protocol instead of a port! + * + * @param conn the netconn to query + * @param addr a pointer to which to save the IP address + * @param port a pointer to which to save the port (or protocol for RAW) + * @param local 1 to get the local IP address, 0 to get the remote one + * @return ERR_CONN for invalid connections + *         ERR_OK if the information was retrieved + */ +err_t +netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); + +  msg.function = do_getaddr; +  msg.msg.conn = conn; +  msg.msg.msg.ad.ipaddr = addr; +  msg.msg.msg.ad.port = port; +  msg.msg.msg.ad.local = local; +  TCPIP_APIMSG(&msg); + +  return conn->err; +} + +/** + * Bind a netconn to a specific local IP address and port. + * Binding one netconn twice might not always be checked correctly! + * + * @param conn the netconn to bind + * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY + *             to bind to all addresses) + * @param port the local port to bind the netconn to (not used for RAW) + * @return ERR_OK if bound, any other err_t on failure + */ +err_t +netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_bind; +  msg.msg.conn = conn; +  msg.msg.msg.bc.ipaddr = addr; +  msg.msg.msg.bc.port = port; +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Connect a netconn to a specific remote IP address and port. + * + * @param conn the netconn to connect + * @param addr the remote IP address to connect to + * @param port the remote port to connect to (no used for RAW) + * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise + */ +err_t +netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_connect; +  msg.msg.conn = conn; +  msg.msg.msg.bc.ipaddr = addr; +  msg.msg.msg.bc.port = port; +  /* This is the only function which need to not block tcpip_thread */ +  tcpip_apimsg(&msg); +  return conn->err; +} + +/** + * Disconnect a netconn from its current peer (only valid for UDP netconns). + * + * @param conn the netconn to disconnect + * @return TODO: return value is not set here... + */ +err_t +netconn_disconnect(struct netconn *conn) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_disconnect; +  msg.msg.conn = conn; +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Set a TCP netconn into listen mode + * + * @param conn the tcp netconn to set to listen mode + * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 + * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns + *         don't return any error (yet?)) + */ +err_t +netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) +{ +  struct api_msg msg; + +  /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ +  LWIP_UNUSED_ARG(backlog); + +  LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_listen; +  msg.msg.conn = conn; +#if TCP_LISTEN_BACKLOG +  msg.msg.msg.lb.backlog = backlog; +#endif /* TCP_LISTEN_BACKLOG */ +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Accept a new connection on a TCP listening netconn. + * + * @param conn the TCP listen netconn + * @return the newly accepted netconn or NULL on timeout + */ +struct netconn * +netconn_accept(struct netconn *conn) +{ +  struct netconn *newconn; + +  LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return NULL;); +  LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;); + +#if LWIP_SO_RCVTIMEO +  if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { +    newconn = NULL; +  } else +#else +  sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0); +#endif /* LWIP_SO_RCVTIMEO*/ +  { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + +#if TCP_LISTEN_BACKLOG +    if (newconn != NULL) { +      /* Let the stack know that we have accepted the connection. */ +      struct api_msg msg; +      msg.function = do_recv; +      msg.msg.conn = conn; +      TCPIP_APIMSG(&msg); +    } +#endif /* TCP_LISTEN_BACKLOG */ +  } + +  return newconn; +} + +/** + * Receive data (in form of a netbuf containing a packet buffer) from a netconn + * + * @param conn the netconn from which to receive data + * @return a new netbuf containing received data or NULL on memory error or timeout + */ +struct netbuf * +netconn_recv(struct netconn *conn) +{ +  struct api_msg msg; +  struct netbuf *buf = NULL; +  struct pbuf *p; +  u16_t len; + +  LWIP_ERROR("netconn_recv: invalid conn",  (conn != NULL), return NULL;); + +  if (conn->recvmbox == SYS_MBOX_NULL) { +    /* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */ +    /* TCP listen conns don't have a recvmbox! */ +    conn->err = ERR_CONN; +    return NULL; +  } + +  if (ERR_IS_FATAL(conn->err)) { +    return NULL; +  } + +  if (conn->type == NETCONN_TCP) { +#if LWIP_TCP +    if (conn->state == NETCONN_LISTEN) { +      /* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */ +      conn->err = ERR_CONN; +      return NULL; +    } + +    buf = memp_malloc(MEMP_NETBUF); + +    if (buf == NULL) { +      conn->err = ERR_MEM; +      return NULL; +    } + +#if LWIP_SO_RCVTIMEO +    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { +      conn->err = ERR_TIMEOUT; +      p = NULL; +    } +#else +    sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + +    if (p != NULL) { +      len = p->tot_len; +      SYS_ARCH_DEC(conn->recv_avail, len); +    } else { +      len = 0; +    } + +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); + +    /* If we are closed, we indicate that we no longer wish to use the socket */ +    if (p == NULL) { +      memp_free(MEMP_NETBUF, buf); +      /* Avoid to lose any previous error code */ +      if (conn->err == ERR_OK) { +        conn->err = ERR_CLSD; +      } +      return NULL; +    } + +    buf->p = p; +    buf->ptr = p; +    buf->port = 0; +    buf->addr = NULL; + +    /* Let the stack know that we have taken the data. */ +    msg.function = do_recv; +    msg.msg.conn = conn; +    if (buf != NULL) { +      msg.msg.msg.r.len = buf->p->tot_len; +    } else { +      msg.msg.msg.r.len = 1; +    } +    TCPIP_APIMSG(&msg); +#endif /* LWIP_TCP */ +  } else { +#if (LWIP_UDP || LWIP_RAW) +#if LWIP_SO_RCVTIMEO +    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { +      buf = NULL; +    } +#else +    sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0); +#endif /* LWIP_SO_RCVTIMEO*/ +    if (buf!=NULL) { +      SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len); +      /* Register event with callback */ +      API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len); +    } +#endif /* (LWIP_UDP || LWIP_RAW) */ +  } + +  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err)); + +  return buf; +} + +/** + * Send data (in form of a netbuf) to a specific remote IP address and port. + * Only to be used for UDP and RAW netconns (not TCP). + * + * @param conn the netconn over which to send data + * @param buf a netbuf containing the data to send + * @param addr the remote IP address to which to send the data + * @param port the remote port to which to send the data + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port) +{ +  if (buf != NULL) { +    buf->addr = addr; +    buf->port = port; +    return netconn_send(conn, buf); +  } +  return ERR_VAL; +} + +/** + * Send data over a UDP or RAW netconn (that is already connected). + * + * @param conn the UDP or RAW netconn over which to send data + * @param buf a netbuf containing the data to send + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_send(struct netconn *conn, struct netbuf *buf) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;); + +  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); +  msg.function = do_send; +  msg.msg.conn = conn; +  msg.msg.msg.b = buf; +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Send data over a TCP netconn. + * + * @param conn the TCP netconn over which to send data + * @param dataptr pointer to the application buffer that contains the data to send + * @param size size of the application data to send + * @param apiflags combination of following flags : + * - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack + * - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_write: invalid conn->type",  (conn->type == NETCONN_TCP), return ERR_VAL;); + +  msg.function = do_write; +  msg.msg.conn = conn; +  msg.msg.msg.w.dataptr = dataptr; +  msg.msg.msg.w.apiflags = apiflags; +  msg.msg.msg.w.len = size; +  /* For locking the core: this _can_ be delayed on low memory/low send buffer, +     but if it is, this is done inside api_msg.c:do_write(), so we can use the +     non-blocking version here. */ +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Close a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_close(struct netconn *conn) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;); + +  msg.function = do_close; +  msg.msg.conn = conn; +  tcpip_apimsg(&msg); +  return conn->err; +} + +#if LWIP_IGMP +/** + * Join multicast groups for UDP netconns. + * + * @param conn the UDP netconn for which to change multicast addresses + * @param multiaddr IP address of the multicast group to join or leave + * @param interface the IP address of the network interface on which to send + *                  the igmp message + * @param join_or_leave flag whether to send a join- or leave-message + * @return ERR_OK if the action was taken, any err_t on error + */ +err_t +netconn_join_leave_group(struct netconn *conn, +                         struct ip_addr *multiaddr, +                         struct ip_addr *interface, +                         enum netconn_igmp join_or_leave) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;); + +  msg.function = do_join_leave_group; +  msg.msg.conn = conn; +  msg.msg.msg.jl.multiaddr = multiaddr; +  msg.msg.msg.jl.interface = interface; +  msg.msg.msg.jl.join_or_leave = join_or_leave; +  TCPIP_APIMSG(&msg); +  return conn->err; +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Execute a DNS query, only one IP address is returned + * + * @param name a string representation of the DNS host name to query + * @param addr a preallocated struct ip_addr where to store the resolved IP address + * @return ERR_OK: resolving succeeded + *         ERR_MEM: memory error, try again later + *         ERR_ARG: dns client not initialized or invalid hostname + *         ERR_VAL: dns server response was invalid + */ +err_t +netconn_gethostbyname(const char *name, struct ip_addr *addr) +{ +  struct dns_api_msg msg; +  err_t err; +  sys_sem_t sem; + +  LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); + +  sem = sys_sem_new(0); +  if (sem == SYS_SEM_NULL) { +    return ERR_MEM; +  } + +  msg.name = name; +  msg.addr = addr; +  msg.err = &err; +  msg.sem = sem; + +  tcpip_callback(do_gethostbyname, &msg); +  sys_sem_wait(sem); +  sys_sem_free(sem); + +  return err; +} +#endif /* LWIP_DNS*/ + +#endif /* LWIP_NETCONN */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/api_msg.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/api_msg.c new file mode 100644 index 000000000..28d101019 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/api_msg.c @@ -0,0 +1,1232 @@ +/** + * @file + * Sequential API Internal module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" + +#include "lwip/ip.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" + +#include "lwip/memp.h" +#include "lwip/tcpip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" + +#include <string.h> + +/* forward declarations */ +#if LWIP_TCP +static err_t do_writemore(struct netconn *conn); +static void do_close_internal(struct netconn *conn); +#endif + +#if LWIP_RAW +/** + * Receive callback function for RAW netconns. + * Doesn't 'eat' the packet, only references it and sends it to + * conn->recvmbox + * + * @see raw.h (struct raw_pcb.recv) for parameters and return value + */ +static u8_t +recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, +    struct ip_addr *addr) +{ +  struct pbuf *q; +  struct netbuf *buf; +  struct netconn *conn; +#if LWIP_SO_RCVBUF +  int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + +  LWIP_UNUSED_ARG(addr); +  conn = arg; + +#if LWIP_SO_RCVBUF +  SYS_ARCH_GET(conn->recv_avail, recv_avail); +  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) && +      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) { +#else  /* LWIP_SO_RCVBUF */ +  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) { +#endif /* LWIP_SO_RCVBUF */ +    /* copy the whole packet into new pbufs */ +    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); +    if(q != NULL) { +      if (pbuf_copy(q, p) != ERR_OK) { +        pbuf_free(q); +        q = NULL; +      } +    } + +    if(q != NULL) { +      buf = memp_malloc(MEMP_NETBUF); +      if (buf == NULL) { +        pbuf_free(q); +        return 0; +      } + +      buf->p = q; +      buf->ptr = q; +      buf->addr = &(((struct ip_hdr*)(q->payload))->src); +      buf->port = pcb->protocol; + +      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { +        netbuf_delete(buf); +        return 0; +      } else { +        SYS_ARCH_INC(conn->recv_avail, q->tot_len); +        /* Register event with callback */ +        API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); +      } +    } +  } + +  return 0; /* do not eat the packet */ +} +#endif /* LWIP_RAW*/ + +#if LWIP_UDP +/** + * Receive callback function for UDP netconns. + * Posts the packet to conn->recvmbox or deletes it on memory error. + * + * @see udp.h (struct udp_pcb.recv) for parameters + */ +static void +recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, +   struct ip_addr *addr, u16_t port) +{ +  struct netbuf *buf; +  struct netconn *conn; +#if LWIP_SO_RCVBUF +  int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + +  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ +  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); +  LWIP_ASSERT("recv_udp must have an argument", arg != NULL); +  conn = arg; +  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); + +#if LWIP_SO_RCVBUF +  SYS_ARCH_GET(conn->recv_avail, recv_avail); +  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) || +      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { +#else  /* LWIP_SO_RCVBUF */ +  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { +#endif /* LWIP_SO_RCVBUF */ +    pbuf_free(p); +    return; +  } + +  buf = memp_malloc(MEMP_NETBUF); +  if (buf == NULL) { +    pbuf_free(p); +    return; +  } else { +    buf->p = p; +    buf->ptr = p; +    buf->addr = addr; +    buf->port = port; +  } + +  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { +    netbuf_delete(buf); +    return; +  } else { +    SYS_ARCH_INC(conn->recv_avail, p->tot_len); +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); +  } +} +#endif /* LWIP_UDP */ + +#if LWIP_TCP +/** + * Receive callback function for TCP netconns. + * Posts the packet to conn->recvmbox, but doesn't delete it on errors. + * + * @see tcp.h (struct tcp_pcb.recv) for parameters and return value + */ +static err_t +recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ +  struct netconn *conn; +  u16_t len; + +  LWIP_UNUSED_ARG(pcb); +  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); +  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); +  conn = arg; +  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); + +  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { +    return ERR_VAL; +  } + +  conn->err = err; +  if (p != NULL) { +    len = p->tot_len; +    SYS_ARCH_INC(conn->recv_avail, len); +  } else { +    len = 0; +  } + +  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { +    return ERR_MEM; +  } else { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); +  } + +  return ERR_OK; +} + +/** + * Poll callback function for TCP netconns. + * Wakes up an application thread that waits for a connection to close + * or data to be sent. The application thread then takes the + * appropriate action to go on. + * + * Signals the conn->sem. + * netconn_close waits for conn->sem if closing failed. + * + * @see tcp.h (struct tcp_pcb.poll) for parameters and return value + */ +static err_t +poll_tcp(void *arg, struct tcp_pcb *pcb) +{ +  struct netconn *conn = arg; + +  LWIP_UNUSED_ARG(pcb); +  LWIP_ASSERT("conn != NULL", (conn != NULL)); + +  if (conn->state == NETCONN_WRITE) { +    do_writemore(conn); +  } else if (conn->state == NETCONN_CLOSE) { +    do_close_internal(conn); +  } + +  return ERR_OK; +} + +/** + * Sent callback function for TCP netconns. + * Signals the conn->sem and calls API_EVENT. + * netconn_write waits for conn->sem if send buffer is low. + * + * @see tcp.h (struct tcp_pcb.sent) for parameters and return value + */ +static err_t +sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) +{ +  struct netconn *conn = arg; + +  LWIP_UNUSED_ARG(pcb); +  LWIP_ASSERT("conn != NULL", (conn != NULL)); + +  if (conn->state == NETCONN_WRITE) { +    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); +    do_writemore(conn); +  } else if (conn->state == NETCONN_CLOSE) { +    do_close_internal(conn); +  } + +  if (conn) { +    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) { +      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); +    } +  } +   +  return ERR_OK; +} + +/** + * Error callback function for TCP netconns. + * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. + * The application thread has then to decide what to do. + * + * @see tcp.h (struct tcp_pcb.err) for parameters + */ +static void +err_tcp(void *arg, err_t err) +{ +  struct netconn *conn; + +  conn = arg; +  LWIP_ASSERT("conn != NULL", (conn != NULL)); + +  conn->pcb.tcp = NULL; + +  conn->err = err; +  if (conn->recvmbox != SYS_MBOX_NULL) { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +    sys_mbox_post(conn->recvmbox, NULL); +  } +  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) { +    conn->state = NETCONN_NONE; +    sys_sem_signal(conn->op_completed); +  } +  if (conn->acceptmbox != SYS_MBOX_NULL) { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +    sys_mbox_post(conn->acceptmbox, NULL); +  } +  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { +    /* calling do_writemore/do_close_internal is not necessary +       since the pcb has already been deleted! */ +    conn->state = NETCONN_NONE; +    /* wake up the waiting task */ +    sys_sem_signal(conn->op_completed); +  } +} + +/** + * Setup a tcp_pcb with the correct callback function pointers + * and their arguments. + * + * @param conn the TCP netconn to setup + */ +static void +setup_tcp(struct netconn *conn) +{ +  struct tcp_pcb *pcb; + +  pcb = conn->pcb.tcp; +  tcp_arg(pcb, conn); +  tcp_recv(pcb, recv_tcp); +  tcp_sent(pcb, sent_tcp); +  tcp_poll(pcb, poll_tcp, 4); +  tcp_err(pcb, err_tcp); +} + +/** + * Accept callback function for TCP netconns. + * Allocates a new netconn and posts that to conn->acceptmbox. + * + * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value + */ +static err_t +accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) +{ +  struct netconn *newconn; +  struct netconn *conn; + +#if API_MSG_DEBUG +#if TCP_DEBUG +  tcp_debug_print_state(newpcb->state); +#endif /* TCP_DEBUG */ +#endif /* API_MSG_DEBUG */ +  conn = (struct netconn *)arg; + +  LWIP_ERROR("accept_function: invalid conn->acceptmbox", +             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;); + +  /* We have to set the callback here even though +   * the new socket is unknown. conn->socket is marked as -1. */ +  newconn = netconn_alloc(conn->type, conn->callback); +  if (newconn == NULL) { +    return ERR_MEM; +  } +  newconn->pcb.tcp = newpcb; +  setup_tcp(newconn); +  newconn->err = err; + +  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { +    /* When returning != ERR_OK, the connection is aborted in tcp_process(), +       so do nothing here! */ +    newconn->pcb.tcp = NULL; +    netconn_free(newconn); +    return ERR_MEM; +  } else { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +  } + +  return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Create a new pcb of a specific type. + * Called from do_newconn(). + * + * @param msg the api_msg_msg describing the connection type + * @return msg->conn->err, but the return value is currently ignored + */ +static err_t +pcb_new(struct api_msg_msg *msg) +{ +   msg->conn->err = ERR_OK; + +   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + +   /* Allocate a PCB for this connection */ +   switch(NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +   case NETCONN_RAW: +     msg->conn->pcb.raw = raw_new(msg->msg.n.proto); +     if(msg->conn->pcb.raw == NULL) { +       msg->conn->err = ERR_MEM; +       break; +     } +     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); +     break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +   case NETCONN_UDP: +     msg->conn->pcb.udp = udp_new(); +     if(msg->conn->pcb.udp == NULL) { +       msg->conn->err = ERR_MEM; +       break; +     } +#if LWIP_UDPLITE +     if (msg->conn->type==NETCONN_UDPLITE) { +       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); +     } +#endif /* LWIP_UDPLITE */ +     if (msg->conn->type==NETCONN_UDPNOCHKSUM) { +       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); +     } +     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); +     break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +   case NETCONN_TCP: +     msg->conn->pcb.tcp = tcp_new(); +     if(msg->conn->pcb.tcp == NULL) { +       msg->conn->err = ERR_MEM; +       break; +     } +     setup_tcp(msg->conn); +     break; +#endif /* LWIP_TCP */ +   default: +     /* Unsupported netconn type, e.g. protocol disabled */ +     msg->conn->err = ERR_VAL; +     break; +   } + +  return msg->conn->err; +} + +/** + * Create a new pcb of a specific type inside a netconn. + * Called from netconn_new_with_proto_and_callback. + * + * @param msg the api_msg_msg describing the connection type + */ +void +do_newconn(struct api_msg_msg *msg) +{ +   if(msg->conn->pcb.tcp == NULL) { +     pcb_new(msg); +   } +   /* Else? This "new" connection already has a PCB allocated. */ +   /* Is this an error condition? Should it be deleted? */ +   /* We currently just are happy and return. */ + +   TCPIP_APIMSG_ACK(msg); +} + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is NOT created! + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + *         NULL on memory error + */ +struct netconn* +netconn_alloc(enum netconn_type t, netconn_callback callback) +{ +  struct netconn *conn; +  int size; + +  conn = memp_malloc(MEMP_NETCONN); +  if (conn == NULL) { +    return NULL; +  } + +  conn->err = ERR_OK; +  conn->type = t; +  conn->pcb.tcp = NULL; + +#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ +    (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) +  size = DEFAULT_RAW_RECVMBOX_SIZE; +#else +  switch(NETCONNTYPE_GROUP(t)) { +#if LWIP_RAW +  case NETCONN_RAW: +    size = DEFAULT_RAW_RECVMBOX_SIZE; +    break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +  case NETCONN_UDP: +    size = DEFAULT_UDP_RECVMBOX_SIZE; +    break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +  case NETCONN_TCP: +    size = DEFAULT_TCP_RECVMBOX_SIZE; +    break; +#endif /* LWIP_TCP */ +  default: +    LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); +    break; +  } +#endif + +  if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) { +    memp_free(MEMP_NETCONN, conn); +    return NULL; +  } +  if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) { +    sys_sem_free(conn->op_completed); +    memp_free(MEMP_NETCONN, conn); +    return NULL; +  } + +  conn->acceptmbox   = SYS_MBOX_NULL; +  conn->state        = NETCONN_NONE; +  /* initialize socket to -1 since 0 is a valid socket */ +  conn->socket       = -1; +  conn->callback     = callback; +  conn->recv_avail   = 0; +#if LWIP_TCP +  conn->write_msg    = NULL; +  conn->write_offset = 0; +#if LWIP_TCPIP_CORE_LOCKING +  conn->write_delayed = 0; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_TCP */ +#if LWIP_SO_RCVTIMEO +  conn->recv_timeout = 0; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +  conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; +#endif /* LWIP_SO_RCVBUF */ +  return conn; +} + +/** + * Delete a netconn and all its resources. + * The pcb is NOT freed (since we might not be in the right thread context do this). + * + * @param conn the netconn to free + */ +void +netconn_free(struct netconn *conn) +{ +  void *mem; +  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); + +  /* Drain the recvmbox. */ +  if (conn->recvmbox != SYS_MBOX_NULL) { +    while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { +      if (conn->type == NETCONN_TCP) { +        if(mem != NULL) { +          pbuf_free((struct pbuf *)mem); +        } +      } else { +        netbuf_delete((struct netbuf *)mem); +      } +    } +    sys_mbox_free(conn->recvmbox); +    conn->recvmbox = SYS_MBOX_NULL; +  } + +  /* Drain the acceptmbox. */ +  if (conn->acceptmbox != SYS_MBOX_NULL) { +    while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { +      netconn_delete((struct netconn *)mem); +    } +    sys_mbox_free(conn->acceptmbox); +    conn->acceptmbox = SYS_MBOX_NULL; +  } + +  sys_sem_free(conn->op_completed); +  conn->op_completed = SYS_SEM_NULL; + +  memp_free(MEMP_NETCONN, conn); +} + +#if LWIP_TCP +/** + * Internal helper function to close a TCP netconn: since this sometimes + * doesn't work at the first attempt, this function is called from multiple + * places. + * + * @param conn the TCP netconn to close + */ +static void +do_close_internal(struct netconn *conn) +{ +  err_t err; + +  LWIP_ASSERT("invalid conn", (conn != NULL)); +  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); +  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); +  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); + +  /* Set back some callback pointers */ +  tcp_arg(conn->pcb.tcp, NULL); +  if (conn->pcb.tcp->state == LISTEN) { +    tcp_accept(conn->pcb.tcp, NULL); +  } else { +    tcp_recv(conn->pcb.tcp, NULL); +    tcp_accept(conn->pcb.tcp, NULL); +    /* some callbacks have to be reset if tcp_close is not successful */ +    tcp_sent(conn->pcb.tcp, NULL); +    tcp_poll(conn->pcb.tcp, NULL, 4); +    tcp_err(conn->pcb.tcp, NULL); +  } +  /* Try to close the connection */ +  err = tcp_close(conn->pcb.tcp); +  if (err == ERR_OK) { +    /* Closing succeeded */ +    conn->state = NETCONN_NONE; +    /* Set back some callback pointers as conn is going away */ +    conn->pcb.tcp = NULL; +    conn->err = ERR_OK; +    /* Trigger select() in socket layer. This send should something else so the +       errorfd is set, not the read and write fd! */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +    API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); +    /* wake up the application task */ +    sys_sem_signal(conn->op_completed); +  } else { +    /* Closing failed, restore some of the callbacks */ +    /* Closing of listen pcb will never fail! */ +    LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); +    tcp_sent(conn->pcb.tcp, sent_tcp); +    tcp_poll(conn->pcb.tcp, poll_tcp, 4); +    tcp_err(conn->pcb.tcp, err_tcp); +    tcp_arg(conn->pcb.tcp, conn); +  } +  /* If closing didn't succeed, we get called again either +     from poll_tcp or from sent_tcp */ +} +#endif /* LWIP_TCP */ + +/** + * Delete the pcb inside a netconn. + * Called from netconn_delete. + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_delconn(struct api_msg_msg *msg) +{ +  if (msg->conn->pcb.tcp != NULL) { +    switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +    case NETCONN_RAW: +      raw_remove(msg->conn->pcb.raw); +      break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +    case NETCONN_UDP: +      msg->conn->pcb.udp->recv_arg = NULL; +      udp_remove(msg->conn->pcb.udp); +      break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +    case NETCONN_TCP: +      msg->conn->state = NETCONN_CLOSE; +      do_close_internal(msg->conn); +      /* API_EVENT is called inside do_close_internal, before releasing +         the application thread, so we can return at this point! */ +      return; +#endif /* LWIP_TCP */ +    default: +      break; +    } +  } +  /* tcp netconns don't come here! */ + +  /* Trigger select() in socket layer. This send should something else so the +     errorfd is set, not the read and write fd! */ +  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); +  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); + +  if (msg->conn->op_completed != SYS_SEM_NULL) { +    sys_sem_signal(msg->conn->op_completed); +  } +} + +/** + * Bind a pcb contained in a netconn + * Called from netconn_bind. + * + * @param msg the api_msg_msg pointing to the connection and containing + *            the IP address and port to bind to + */ +void +do_bind(struct api_msg_msg *msg) +{ +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +      case NETCONN_RAW: +        msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); +        break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +      case NETCONN_UDP: +        msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); +        break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +      case NETCONN_TCP: +        msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); +        break; +#endif /* LWIP_TCP */ +      default: +        break; +      } +    } else { +      /* msg->conn->pcb is NULL */ +      msg->conn->err = ERR_VAL; +    } +  } +  TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * TCP callback function if a connection (opened by tcp_connect/do_connect) has + * been established (or reset by the remote host). + * + * @see tcp.h (struct tcp_pcb.connected) for parameters and return values + */ +static err_t +do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ +  struct netconn *conn; + +  LWIP_UNUSED_ARG(pcb); + +  conn = arg; + +  if (conn == NULL) { +    return ERR_VAL; +  } + +  conn->err = err; +  if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { +    setup_tcp(conn); +  } +  conn->state = NETCONN_NONE; +  sys_sem_signal(conn->op_completed); +  return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Connect a pcb contained inside a netconn + * Called from netconn_connect. + * + * @param msg the api_msg_msg pointing to the connection and containing + *            the IP address and port to connect to + */ +void +do_connect(struct api_msg_msg *msg) +{ +  if (msg->conn->pcb.tcp == NULL) { +    sys_sem_signal(msg->conn->op_completed); +    return; +  } + +  switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +  case NETCONN_RAW: +    msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); +    sys_sem_signal(msg->conn->op_completed); +    break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +  case NETCONN_UDP: +    msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); +    sys_sem_signal(msg->conn->op_completed); +    break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +  case NETCONN_TCP: +    msg->conn->state = NETCONN_CONNECT; +    setup_tcp(msg->conn); +    msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port, +                                 do_connected); +    /* sys_sem_signal() is called from do_connected (or err_tcp()), +     * when the connection is established! */ +    break; +#endif /* LWIP_TCP */ +  default: +    break; +  } +} + +/** + * Connect a pcb contained inside a netconn + * Only used for UDP netconns. + * Called from netconn_disconnect. + * + * @param msg the api_msg_msg pointing to the connection to disconnect + */ +void +do_disconnect(struct api_msg_msg *msg) +{ +#if LWIP_UDP +  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +    udp_disconnect(msg->conn->pcb.udp); +  } +#endif /* LWIP_UDP */ +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Set a TCP pcb contained in a netconn into listen mode + * Called from netconn_listen. + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_listen(struct api_msg_msg *msg) +{ +#if LWIP_TCP +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      if (msg->conn->type == NETCONN_TCP) { +        if (msg->conn->pcb.tcp->state == CLOSED) { +#if TCP_LISTEN_BACKLOG +          struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); +#else  /* TCP_LISTEN_BACKLOG */ +          struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); +#endif /* TCP_LISTEN_BACKLOG */ +          if (lpcb == NULL) { +            msg->conn->err = ERR_MEM; +          } else { +            /* delete the recvmbox and allocate the acceptmbox */ +            if (msg->conn->recvmbox != SYS_MBOX_NULL) { +              /** @todo: should we drain the recvmbox here? */ +              sys_mbox_free(msg->conn->recvmbox); +              msg->conn->recvmbox = SYS_MBOX_NULL; +            } +            if (msg->conn->acceptmbox == SYS_MBOX_NULL) { +              if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) { +                msg->conn->err = ERR_MEM; +              } +            } +            if (msg->conn->err == ERR_OK) { +              msg->conn->state = NETCONN_LISTEN; +              msg->conn->pcb.tcp = lpcb; +              tcp_arg(msg->conn->pcb.tcp, msg->conn); +              tcp_accept(msg->conn->pcb.tcp, accept_function); +            } +          } +        } else { +          msg->conn->err = ERR_CONN; +        } +      } +    } +  } +#endif /* LWIP_TCP */ +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Send some data on a RAW or UDP pcb contained in a netconn + * Called from netconn_send + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_send(struct api_msg_msg *msg) +{ +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +      case NETCONN_RAW: +        if (msg->msg.b->addr == NULL) { +          msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); +        } else { +          msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr); +        } +        break; +#endif +#if LWIP_UDP +      case NETCONN_UDP: +        if (msg->msg.b->addr == NULL) { +          msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); +        } else { +          msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port); +        } +        break; +#endif /* LWIP_UDP */ +      default: +        break; +      } +    } +  } +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Indicate data has been received from a TCP pcb contained in a netconn + * Called from netconn_recv + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_recv(struct api_msg_msg *msg) +{ +#if LWIP_TCP +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      if (msg->conn->type == NETCONN_TCP) { +#if TCP_LISTEN_BACKLOG +        if (msg->conn->pcb.tcp->state == LISTEN) { +          tcp_accepted(msg->conn->pcb.tcp); +        } else +#endif /* TCP_LISTEN_BACKLOG */ +        { +          tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); +        } +      } +    } +  } +#endif /* LWIP_TCP */ +  TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * See if more data needs to be written from a previous call to netconn_write. + * Called initially from do_write. If the first call can't send all data + * (because of low memory or empty send-buffer), this function is called again + * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the + * blocking application thread (waiting in netconn_write) is released. + * + * @param conn netconn (that is currently in state NETCONN_WRITE) to process + * @return ERR_OK + *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished + */ +static err_t +do_writemore(struct netconn *conn) +{ +  err_t err; +  void *dataptr; +  u16_t len, available; +  u8_t write_finished = 0; +  size_t diff; + +  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); + +  dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset; +  diff = conn->write_msg->msg.w.len - conn->write_offset; +  if (diff > 0xffffUL) { /* max_u16_t */ +    len = 0xffff; +#if LWIP_TCPIP_CORE_LOCKING +    conn->write_delayed = 1; +#endif +  } else { +    len = (u16_t)diff; +  } +  available = tcp_sndbuf(conn->pcb.tcp); +  if (available < len) { +    /* don't try to write more than sendbuf */ +    len = available; +#if LWIP_TCPIP_CORE_LOCKING +    conn->write_delayed = 1; +#endif +  } + +  err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags); +  LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len)); +  if (err == ERR_OK) { +    conn->write_offset += len; +    if (conn->write_offset == conn->write_msg->msg.w.len) { +      /* everything was written */ +      write_finished = 1; +      conn->write_msg = NULL; +      conn->write_offset = 0; +      /* API_EVENT might call tcp_tmr, so reset conn->state now */ +      conn->state = NETCONN_NONE; +    } +    err = tcp_output_nagle(conn->pcb.tcp); +    conn->err = err; +    if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) { +      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); +    } +  } else if (err == ERR_MEM) { +    /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called +       we do NOT return to the application thread, since ERR_MEM is +       only a temporary error! */ + +    /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */ +    err = tcp_output(conn->pcb.tcp); + +#if LWIP_TCPIP_CORE_LOCKING +    conn->write_delayed = 1; +#endif +  } else { +    /* On errors != ERR_MEM, we don't try writing any more but return +       the error to the application thread. */ +    conn->err = err; +    write_finished = 1; +  } + +  if (write_finished) { +    /* everything was written: set back connection state +       and back to application task */ +    conn->state = NETCONN_NONE; +#if LWIP_TCPIP_CORE_LOCKING +    if (conn->write_delayed != 0) +#endif +    { +      sys_sem_signal(conn->op_completed); +    } +  } +#if LWIP_TCPIP_CORE_LOCKING +  else +    return ERR_MEM; +#endif +  return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a TCP pcb contained in a netconn + * Called from netconn_write + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_write(struct api_msg_msg *msg) +{ +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { +#if LWIP_TCP +      msg->conn->state = NETCONN_WRITE; +      /* set all the variables used by do_writemore */ +      LWIP_ASSERT("already writing", msg->conn->write_msg == NULL && +        msg->conn->write_offset == 0); +      msg->conn->write_msg = msg; +      msg->conn->write_offset = 0; +#if LWIP_TCPIP_CORE_LOCKING +      msg->conn->write_delayed = 0; +      if (do_writemore(msg->conn) != ERR_OK) { +        LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); +        UNLOCK_TCPIP_CORE(); +        sys_arch_sem_wait(msg->conn->op_completed, 0); +        LOCK_TCPIP_CORE(); +        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); +      } +#else +      do_writemore(msg->conn); +#endif +      /* for both cases: if do_writemore was called, don't ACK the APIMSG! */ +      return; +#endif /* LWIP_TCP */ +#if (LWIP_UDP || LWIP_RAW) +    } else { +      msg->conn->err = ERR_VAL; +#endif /* (LWIP_UDP || LWIP_RAW) */ +    } +  } +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Return a connection's local or remote address + * Called from netconn_getaddr + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_getaddr(struct api_msg_msg *msg) +{ +  if (msg->conn->pcb.ip != NULL) { +    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip); +     +    switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +    case NETCONN_RAW: +      if (msg->msg.ad.local) { +        *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; +      } else { +        /* return an error as connecting is only a helper for upper layers */ +        msg->conn->err = ERR_CONN; +      } +      break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +    case NETCONN_UDP: +      if (msg->msg.ad.local) { +        *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; +      } else { +        if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { +          msg->conn->err = ERR_CONN; +        } else { +          *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; +        } +      } +      break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +    case NETCONN_TCP: +      *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); +      break; +#endif /* LWIP_TCP */ +    } +  } else { +    msg->conn->err = ERR_CONN; +  } +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Close a TCP pcb contained in a netconn + * Called from netconn_close + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_close(struct api_msg_msg *msg) +{ +#if LWIP_TCP +  if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { +      msg->conn->state = NETCONN_CLOSE; +      do_close_internal(msg->conn); +      /* for tcp netconns, do_close_internal ACKs the message */ +  } else +#endif /* LWIP_TCP */ +  { +    msg->conn->err = ERR_VAL; +    TCPIP_APIMSG_ACK(msg); +  } +} + +#if LWIP_IGMP +/** + * Join multicast groups for UDP netconns. + * Called from netconn_join_leave_group + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_join_leave_group(struct api_msg_msg *msg) +{  +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +#if LWIP_UDP +        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { +          msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); +        } else { +          msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); +        } +#endif /* LWIP_UDP */ +#if (LWIP_TCP || LWIP_RAW) +      } else { +        msg->conn->err = ERR_VAL; +#endif /* (LWIP_TCP || LWIP_RAW) */ +      } +    } +  } +  TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Callback function that is called when DNS name is resolved + * (or on timeout). A waiting application thread is waked up by + * signaling the semaphore. + */ +static void +do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg) +{ +  struct dns_api_msg *msg = (struct dns_api_msg*)arg; + +  LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); + +  if (ipaddr == NULL) { +    /* timeout or memory error */ +    *msg->err = ERR_VAL; +  } else { +    /* address was resolved */ +    *msg->err = ERR_OK; +    *msg->addr = *ipaddr; +  } +  /* wake up the application task waiting in netconn_gethostbyname */ +  sys_sem_signal(msg->sem); +} + +/** + * Execute a DNS query + * Called from netconn_gethostbyname + * + * @param arg the dns_api_msg pointing to the query + */ +void +do_gethostbyname(void *arg) +{ +  struct dns_api_msg *msg = (struct dns_api_msg*)arg; + +  *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); +  if (*msg->err != ERR_INPROGRESS) { +    /* on error or immediate success, wake up the application +     * task waiting in netconn_gethostbyname */ +    sys_sem_signal(msg->sem); +  } +} +#endif /* LWIP_DNS */ + +#endif /* LWIP_NETCONN */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/err.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/err.c new file mode 100644 index 000000000..a90cb98c8 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/err.c @@ -0,0 +1,74 @@ +/** + * @file + * Error Management module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/err.h" + +#ifdef LWIP_DEBUG + +static const char *err_strerr[] = { +           "Ok.",                    /* ERR_OK          0  */ +           "Out of memory error.",   /* ERR_MEM        -1  */ +           "Buffer error.",          /* ERR_BUF        -2  */ +           "Timeout.",               /* ERR_TIMEOUT    -3 */ +           "Routing problem.",       /* ERR_RTE        -4  */ +           "Connection aborted.",    /* ERR_ABRT       -5  */ +           "Connection reset.",      /* ERR_RST        -6  */ +           "Connection closed.",     /* ERR_CLSD       -7  */ +           "Not connected.",         /* ERR_CONN       -8  */ +           "Illegal value.",         /* ERR_VAL        -9  */ +           "Illegal argument.",      /* ERR_ARG        -10 */ +           "Address in use.",        /* ERR_USE        -11 */ +           "Low-level netif error.", /* ERR_IF         -12 */ +           "Already connected.",     /* ERR_ISCONN     -13 */ +           "Operation in progress."  /* ERR_INPROGRESS -14 */ +}; + +/** + * Convert an lwip internal error to a string representation. + * + * @param err an lwip internal err_t + * @return a string representation for err + */ +const char * +lwip_strerr(err_t err) +{ +  return err_strerr[-err]; + +} + +#endif /* LWIP_DEBUG */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/netbuf.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/netbuf.c new file mode 100644 index 000000000..af44eefc7 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/netbuf.c @@ -0,0 +1,235 @@ +/** + * @file + * Network buffer management + * + */ +  +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netbuf.h" +#include "lwip/memp.h" + +#include <string.h> + +/** + * Create (allocate) and initialize a new netbuf. + * The netbuf doesn't yet contain a packet buffer! + * + * @return a pointer to a new netbuf + *         NULL on lack of memory + */ +struct +netbuf *netbuf_new(void) +{ +  struct netbuf *buf; + +  buf = memp_malloc(MEMP_NETBUF); +  if (buf != NULL) { +    buf->p = NULL; +    buf->ptr = NULL; +    buf->addr = NULL; +    return buf; +  } else { +    return NULL; +  } +} + +/** + * Deallocate a netbuf allocated by netbuf_new(). + * + * @param buf pointer to a netbuf allocated by netbuf_new() + */ +void +netbuf_delete(struct netbuf *buf) +{ +  if (buf != NULL) { +    if (buf->p != NULL) { +      pbuf_free(buf->p); +      buf->p = buf->ptr = NULL; +    } +    memp_free(MEMP_NETBUF, buf); +  } +} + +/** + * Allocate memory for a packet buffer for a given netbuf. + * + * @param buf the netbuf for which to allocate a packet buffer + * @param size the size of the packet buffer to allocate + * @return pointer to the allocated memory + *         NULL if no memory could be allocated + */ +void * +netbuf_alloc(struct netbuf *buf, u16_t size) +{ +  LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); + +  /* Deallocate any previously allocated memory. */ +  if (buf->p != NULL) { +    pbuf_free(buf->p); +  } +  buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); +  if (buf->p == NULL) { +     return NULL; +  } +  LWIP_ASSERT("check that first pbuf can hold size", +             (buf->p->len >= size)); +  buf->ptr = buf->p; +  return buf->p->payload; +} + +/** + * Free the packet buffer included in a netbuf + * + * @param buf pointer to the netbuf which contains the packet buffer to free + */ +void +netbuf_free(struct netbuf *buf) +{ +  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); +  if (buf->p != NULL) { +    pbuf_free(buf->p); +  } +  buf->p = buf->ptr = NULL; +} + +/** + * Let a netbuf reference existing (non-volatile) data. + * + * @param buf netbuf which should reference the data + * @param dataptr pointer to the data to reference + * @param size size of the data + * @return ERR_OK if data is referenced + *         ERR_MEM if data couldn't be referenced due to lack of memory + */ +err_t +netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) +{ +  LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); +  if (buf->p != NULL) { +    pbuf_free(buf->p); +  } +  buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); +  if (buf->p == NULL) { +    buf->ptr = NULL; +    return ERR_MEM; +  } +  buf->p->payload = (void*)dataptr; +  buf->p->len = buf->p->tot_len = size; +  buf->ptr = buf->p; +  return ERR_OK; +} + +/** + * Chain one netbuf to another (@see pbuf_chain) + * + * @param head the first netbuf + * @param tail netbuf to chain after head, freed by this function, may not be reference after returning + */ +void +netbuf_chain(struct netbuf *head, struct netbuf *tail) +{ +  LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;); +  LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); +  pbuf_cat(head->p, tail->p); +  head->ptr = head->p; +  memp_free(MEMP_NETBUF, tail); +} + +/** + * Get the data pointer and length of the data inside a netbuf. + * + * @param buf netbuf to get the data from + * @param dataptr pointer to a void pointer where to store the data pointer + * @param len pointer to an u16_t where the length of the data is stored + * @return ERR_OK if the information was retreived, + *         ERR_BUF on error. + */ +err_t +netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) +{ +  LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); +  LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); +  LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); + +  if (buf->ptr == NULL) { +    return ERR_BUF; +  } +  *dataptr = buf->ptr->payload; +  *len = buf->ptr->len; +  return ERR_OK; +} + +/** + * Move the current data pointer of a packet buffer contained in a netbuf + * to the next part. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + * @return -1 if there is no next part + *         1  if moved to the next part but now there is no next part + *         0  if moved to the next part and there are still more parts + */ +s8_t +netbuf_next(struct netbuf *buf) +{ +  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;); +  if (buf->ptr->next == NULL) { +    return -1; +  } +  buf->ptr = buf->ptr->next; +  if (buf->ptr->next == NULL) { +    return 1; +  } +  return 0; +} + +/** + * Move the current data pointer of a packet buffer contained in a netbuf + * to the beginning of the packet. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + */ +void +netbuf_first(struct netbuf *buf) +{ +  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); +  buf->ptr = buf->p; +} + +#endif /* LWIP_NETCONN */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/netdb.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/netdb.c new file mode 100644 index 000000000..8aa237f4c --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/netdb.c @@ -0,0 +1,356 @@ +/** + * @file + * API functions for name resolving + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Simon Goldschmidt + * + */ + +#include "lwip/netdb.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/err.h" +#include "lwip/mem.h" +#include "lwip/ip_addr.h" +#include "lwip/api.h" + +#include <string.h> +#include <stdlib.h> + +/** helper struct for gethostbyname_r to access the char* buffer */ +struct gethostbyname_r_helper { +  struct ip_addr *addrs; +  struct ip_addr addr; +  char *aliases; +}; + +/** h_errno is exported in netdb.h for access by applications. */ +#if LWIP_DNS_API_DECLARE_H_ERRNO +int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ + +/** define "hostent" variables storage: 0 if we use a static (but unprotected) + * set of variables for lwip_gethostbyname, 1 if we use a local storage */ +#ifndef LWIP_DNS_API_HOSTENT_STORAGE +#define LWIP_DNS_API_HOSTENT_STORAGE 0 +#endif + +/** define "hostent" variables storage */ +#if LWIP_DNS_API_HOSTENT_STORAGE +#define HOSTENT_STORAGE +#else +#define HOSTENT_STORAGE static +#endif /* LWIP_DNS_API_STATIC_HOSTENT */ + +/** + * Returns an entry containing addresses of address family AF_INET + * for the host with name name. + * Due to dns_gethostbyname limitations, only one address is returned. + * + * @param name the hostname to resolve + * @return an entry containing addresses of address family AF_INET + *         for the host with name name + */ +struct hostent* +lwip_gethostbyname(const char *name) +{ +  err_t err; +  struct ip_addr addr; + +  /* buffer variables for lwip_gethostbyname() */ +  HOSTENT_STORAGE struct hostent s_hostent; +  HOSTENT_STORAGE char *s_aliases; +  HOSTENT_STORAGE struct ip_addr s_hostent_addr; +  HOSTENT_STORAGE struct ip_addr *s_phostent_addr; + +  /* query host IP address */ +  err = netconn_gethostbyname(name, &addr); +  if (err != ERR_OK) { +    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); +    h_errno = HOST_NOT_FOUND; +    return NULL; +  } + +  /* fill hostent */ +  s_hostent_addr = addr; +  s_phostent_addr = &s_hostent_addr; +  s_hostent.h_name = (char*)name; +  s_hostent.h_aliases = &s_aliases; +  s_hostent.h_addrtype = AF_INET; +  s_hostent.h_length = sizeof(struct ip_addr); +  s_hostent.h_addr_list = (char**)&s_phostent_addr; + +#if DNS_DEBUG +  /* dump hostent */ +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n", s_hostent.h_name)); +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == %p\n", s_hostent.h_aliases)); +  if (s_hostent.h_aliases != NULL) { +    u8_t idx; +    for ( idx=0; s_hostent.h_aliases[idx]; idx++) { +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %p\n", idx, s_hostent.h_aliases[idx])); +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n",      idx, s_hostent.h_aliases[idx])); +    } +  } +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", s_hostent.h_addrtype)); +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %d\n", s_hostent.h_length)); +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == %p\n", s_hostent.h_addr_list)); +  if (s_hostent.h_addr_list != NULL) { +    u8_t idx; +    for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == %p\n", idx, s_hostent.h_addr_list[idx])); +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx]))))); +    } +  } +#endif /* DNS_DEBUG */ + +#if LWIP_DNS_API_HOSTENT_STORAGE +  /* this function should return the "per-thread" hostent after copy from s_hostent */ +  return sys_thread_hostent(&s_hostent); +#else +  return &s_hostent; +#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ +} + +/** + * Thread-safe variant of lwip_gethostbyname: instead of using a static + * buffer, this function takes buffer and errno pointers as arguments + * and uses these for the result. + * + * @param name the hostname to resolve + * @param ret pre-allocated struct where to store the result + * @param buf pre-allocated buffer where to store additional data + * @param buflen the size of buf + * @param result pointer to a hostent pointer that is set to ret on success + *               and set to zero on error + * @param h_errnop pointer to an int where to store errors (instead of modifying + *                 the global h_errno) + * @return 0 on success, non-zero on error, additional error information + *         is stored in *h_errnop instead of h_errno to be thread-safe + */ +int +lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, +                size_t buflen, struct hostent **result, int *h_errnop) +{ +  err_t err; +  struct gethostbyname_r_helper *h; +  char *hostname; +  size_t namelen; +  int lh_errno; + +  if (h_errnop == NULL) { +    /* ensure h_errnop is never NULL */ +    h_errnop = &lh_errno; +  } + +  if (result == NULL) { +    /* not all arguments given */ +    *h_errnop = EINVAL; +    return -1; +  } +  /* first thing to do: set *result to nothing */ +  *result = NULL; +  if ((name == NULL) || (ret == NULL) || (buf == 0)) { +    /* not all arguments given */ +    *h_errnop = EINVAL; +    return -1; +  } + +  namelen = strlen(name); +  if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { +    /* buf can't hold the data needed + a copy of name */ +    *h_errnop = ERANGE; +    return -1; +  } + +  h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); +  hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); + +  /* query host IP address */ +  err = netconn_gethostbyname(name, &(h->addr)); +  if (err != ERR_OK) { +    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); +    *h_errnop = ENSRNOTFOUND; +    return -1; +  } + +  /* copy the hostname into buf */ +  MEMCPY(hostname, name, namelen); +  hostname[namelen] = 0; + +  /* fill hostent */ +  h->addrs = &(h->addr); +  h->aliases = NULL; +  ret->h_name = (char*)hostname; +  ret->h_aliases = &(h->aliases); +  ret->h_addrtype = AF_INET; +  ret->h_length = sizeof(struct ip_addr); +  ret->h_addr_list = (char**)&(h->addrs); + +  /* set result != NULL */ +  *result = ret; + +  /* return success */ +  return 0; +} + +/** + * Frees one or more addrinfo structures returned by getaddrinfo(), along with + * any additional storage associated with those structures. If the ai_next field + * of the structure is not null, the entire list of structures is freed. + * + * @param ai struct addrinfo to free + */ +void +lwip_freeaddrinfo(struct addrinfo *ai) +{ +  struct addrinfo *next; + +  while (ai != NULL) { +    if (ai->ai_addr != NULL) { +      mem_free(ai->ai_addr); +    } +    if (ai->ai_canonname != NULL) { +      mem_free(ai->ai_canonname); +    } +    next = ai->ai_next; +    mem_free(ai); +    ai = next; +  } +} + +/** + * Translates the name of a service location (for example, a host name) and/or + * a service name and returns a set of socket addresses and associated + * information to be used in creating a socket with which to address the + * specified service. + * Memory for the result is allocated internally and must be freed by calling + * lwip_freeaddrinfo()! + * + * Due to a limitation in dns_gethostbyname, only the first address of a + * host is returned. + * Also, service names are not supported (only port numbers)! + * + * @param nodename descriptive name or address string of the host + *                 (may be NULL -> local address) + * @param servname port number as string of NULL  + * @param hints structure containing input values that set socktype and protocol + * @param res pointer to a pointer where to store the result (set to NULL on failure) + * @return 0 on success, non-zero on failure + */ +int +lwip_getaddrinfo(const char *nodename, const char *servname, +       const struct addrinfo *hints, struct addrinfo **res) +{ +  err_t err; +  struct ip_addr addr; +  struct addrinfo *ai; +  struct sockaddr_in *sa = NULL; +  int port_nr = 0; + +  if (res == NULL) { +    return EAI_FAIL; +  } +  *res = NULL; +  if ((nodename == NULL) && (servname == NULL)) { +    return EAI_NONAME; +  } + +  if (servname != NULL) { +    /* service name specified: convert to port number +     * @todo?: currently, only ASCII integers (port numbers) are supported! */ +    port_nr = atoi(servname); +    if ((port_nr <= 0) || (port_nr > 0xffff)) { +      return EAI_SERVICE; +    } +  } + +  if (nodename != NULL) { +    /* service location specified, try to resolve */ +    err = netconn_gethostbyname(nodename, &addr); +    if (err != ERR_OK) { +      return EAI_FAIL; +    } +  } else { +    /* service location specified, use loopback address */ +    addr.addr = INADDR_LOOPBACK; +  } + +  ai = mem_malloc(sizeof(struct addrinfo)); +  if (ai == NULL) { +    goto memerr; +  } +  memset(ai, 0, sizeof(struct addrinfo)); +  sa = mem_malloc(sizeof(struct sockaddr_in)); +  if (sa == NULL) { +    goto memerr; +  } +  memset(sa, 0, sizeof(struct sockaddr_in)); +  /* set up sockaddr */ +  sa->sin_addr.s_addr = addr.addr; +  sa->sin_family = AF_INET; +  sa->sin_len = sizeof(struct sockaddr_in); +  sa->sin_port = htons(port_nr); + +  /* set up addrinfo */ +  ai->ai_family = AF_INET; +  if (hints != NULL) { +    /* copy socktype & protocol from hints if specified */ +    ai->ai_socktype = hints->ai_socktype; +    ai->ai_protocol = hints->ai_protocol; +  } +  if (nodename != NULL) { +    /* copy nodename to canonname if specified */ +    size_t namelen = strlen(nodename); +    LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1); +    ai->ai_canonname = mem_malloc((mem_size_t)(namelen + 1)); +    if (ai->ai_canonname == NULL) { +      goto memerr; +    } +    MEMCPY(ai->ai_canonname, nodename, namelen); +    ai->ai_canonname[namelen] = 0; +  } +  ai->ai_addrlen = sizeof(struct sockaddr_in); +  ai->ai_addr = (struct sockaddr*)sa; + +  *res = ai; + +  return 0; +memerr: +  if (ai != NULL) { +    mem_free(ai); +  } +  if (sa != NULL) { +    mem_free(sa); +  } +  return EAI_MEMORY; +} + +#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/netifapi.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/netifapi.c new file mode 100644 index 000000000..491837378 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/netifapi.c @@ -0,0 +1,126 @@ +/** + * @file + * Network Interface Sequential API module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + */ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netifapi.h" +#include "lwip/tcpip.h" + +/** + * Call netif_add() inside the tcpip_thread context. + */ +void +do_netifapi_netif_add( struct netifapi_msg_msg *msg) +{ +  if (!netif_add( msg->netif, +                  msg->msg.add.ipaddr, +                  msg->msg.add.netmask, +                  msg->msg.add.gw, +                  msg->msg.add.state, +                  msg->msg.add.init, +                  msg->msg.add.input)) { +    msg->err = ERR_IF; +  } else { +    msg->err = ERR_OK; +  } +  TCPIP_NETIFAPI_ACK(msg); +} + +/** + * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the + * tcpip_thread context. + */ +void +do_netifapi_netif_common( struct netifapi_msg_msg *msg) +{ +  if (msg->msg.common.errtfunc!=NULL) { +    msg->err = +    msg->msg.common.errtfunc(msg->netif); +  } else { +    msg->err = ERR_OK; +    msg->msg.common.voidfunc(msg->netif); +  } +  TCPIP_NETIFAPI_ACK(msg); +} + +/** + * Call netif_add() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_add() + */ +err_t +netifapi_netif_add(struct netif *netif, +                   struct ip_addr *ipaddr, +                   struct ip_addr *netmask, +                   struct ip_addr *gw, +                   void *state, +                   err_t (* init)(struct netif *netif), +                   err_t (* input)(struct pbuf *p, struct netif *netif)) +{ +  struct netifapi_msg msg; +  msg.function = do_netifapi_netif_add; +  msg.msg.netif = netif; +  msg.msg.msg.add.ipaddr  = ipaddr; +  msg.msg.msg.add.netmask = netmask; +  msg.msg.msg.add.gw      = gw; +  msg.msg.msg.add.state   = state; +  msg.msg.msg.add.init    = init; +  msg.msg.msg.add.input   = input; +  TCPIP_NETIFAPI(&msg); +  return msg.msg.err; +} + +/** + * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe + * way by running that function inside the tcpip_thread context. + * + * @note use only for functions where there is only "netif" parameter. + */ +err_t +netifapi_netif_common( struct netif *netif, +                       void  (* voidfunc)(struct netif *netif), +                       err_t (* errtfunc)(struct netif *netif) ) +{ +  struct netifapi_msg msg; +  msg.function = do_netifapi_netif_common; +  msg.msg.netif = netif; +  msg.msg.msg.common.voidfunc = voidfunc; +  msg.msg.msg.common.errtfunc = errtfunc; +  TCPIP_NETIFAPI(&msg); +  return msg.msg.err; +} + +#endif /* LWIP_NETIF_API */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/sockets.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/sockets.c new file mode 100644 index 000000000..f177261e1 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/sockets.c @@ -0,0 +1,1970 @@ +/** + * @file + * Sockets BSD-Like API module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu> + * + */ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sockets.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcpip.h" + +#include <string.h> + +#define NUM_SOCKETS MEMP_NUM_NETCONN + +/** Contains all internal pointers and states used for a socket */ +struct lwip_socket { +  /** sockets currently are built on netconns, each socket has one netconn */ +  struct netconn *conn; +  /** data that was left from the previous read */ +  struct netbuf *lastdata; +  /** offset in the data that was left from the previous read */ +  u16_t lastoffset; +  /** number of times data was received, set by event_callback(), +      tested by the receive and select functions */ +  s16_t rcvevent; +  /** number of times data was received, set by event_callback(), +      tested by select */ +  u16_t sendevent; +  /** socket flags (currently, only used for O_NONBLOCK) */ +  u16_t flags; +  /** last error that occurred on this socket */ +  int err; +}; + +/** Description for a task waiting in select */ +struct lwip_select_cb { +  /** Pointer to the next waiting task */ +  struct lwip_select_cb *next; +  /** readset passed to select */ +  fd_set *readset; +  /** writeset passed to select */ +  fd_set *writeset; +  /** unimplemented: exceptset passed to select */ +  fd_set *exceptset; +  /** don't signal the same semaphore twice: set to 1 when signalled */ +  int sem_signalled; +  /** semaphore to wake up a task waiting for select */ +  sys_sem_t sem; +}; + +/** This struct is used to pass data to the set/getsockopt_internal + * functions running in tcpip_thread context (only a void* is allowed) */ +struct lwip_setgetsockopt_data { +  /** socket struct for which to change options */ +  struct lwip_socket *sock; +  /** socket index for which to change options */ +  int s; +  /** level of the option to process */ +  int level; +  /** name of the option to process */ +  int optname; +  /** set: value to set the option to +    * get: value of the option is stored here */ +  void *optval; +  /** size of *optval */ +  socklen_t *optlen; +  /** if an error occures, it is temporarily stored here */ +  err_t err; +}; + +/** The global array of available sockets */ +static struct lwip_socket sockets[NUM_SOCKETS]; +/** The global list of tasks waiting for select */ +static struct lwip_select_cb *select_cb_list; + +/** Semaphore protecting the sockets array */ +static sys_sem_t socksem; +/** Semaphore protecting select_cb_list */ +static sys_sem_t selectsem; + +/** Table to quickly map an lwIP error (err_t) to a socket error +  * by using -err as an index */ +static const int err_to_errno_table[] = { +  0,             /* ERR_OK          0      No error, everything OK. */ +  ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */ +  ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */ +  ETIMEDOUT,     /* ERR_TIMEOUT    -3      Timeout                  */ +  EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */ +  ECONNABORTED,  /* ERR_ABRT       -5      Connection aborted.      */ +  ECONNRESET,    /* ERR_RST        -6      Connection reset.        */ +  ESHUTDOWN,     /* ERR_CLSD       -7      Connection closed.       */ +  ENOTCONN,      /* ERR_CONN       -8      Not connected.           */ +  EINVAL,        /* ERR_VAL        -9      Illegal value.           */ +  EIO,           /* ERR_ARG        -10     Illegal argument.        */ +  EADDRINUSE,    /* ERR_USE        -11     Address in use.          */ +  -1,            /* ERR_IF         -12     Low-level netif error    */ +  -1,            /* ERR_ISCONN     -13     Already connected.       */ +  EINPROGRESS    /* ERR_INPROGRESS -14     Operation in progress    */ +}; + +#define ERR_TO_ERRNO_TABLE_SIZE \ +  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) + +#define err_to_errno(err) \ +  ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ +    err_to_errno_table[-(err)] : EIO) + +#ifdef ERRNO +#ifndef set_errno +#define set_errno(err) errno = (err) +#endif +#else +#define set_errno(err) +#endif + +#define sock_set_errno(sk, e) do { \ +  sk->err = (e); \ +  set_errno(sk->err); \ +} while (0) + +/* Forward delcaration of some functions */ +static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); +static void lwip_getsockopt_internal(void *arg); +static void lwip_setsockopt_internal(void *arg); + +/** + * Initialize this module. This function has to be called before any other + * functions in this module! + */ +void +lwip_socket_init(void) +{ +  socksem   = sys_sem_new(1); +  selectsem = sys_sem_new(1); +} + +/** + * Map a externally used socket index to the internal socket representation. + * + * @param s externally used socket index + * @return struct lwip_socket for the socket or NULL if not found + */ +static struct lwip_socket * +get_socket(int s) +{ +  struct lwip_socket *sock; + +  if ((s < 0) || (s >= NUM_SOCKETS)) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); +    set_errno(EBADF); +    return NULL; +  } + +  sock = &sockets[s]; + +  if (!sock->conn) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); +    set_errno(EBADF); +    return NULL; +  } + +  return sock; +} + +/** + * Allocate a new socket for a given netconn. + * + * @param newconn the netconn for which to allocate a socket + * @return the index of the new socket; -1 on error + */ +static int +alloc_socket(struct netconn *newconn) +{ +  int i; + +  /* Protect socket array */ +  sys_sem_wait(socksem); + +  /* allocate a new socket identifier */ +  for (i = 0; i < NUM_SOCKETS; ++i) { +    if (!sockets[i].conn) { +      sockets[i].conn       = newconn; +      sockets[i].lastdata   = NULL; +      sockets[i].lastoffset = 0; +      sockets[i].rcvevent   = 0; +      sockets[i].sendevent  = 1; /* TCP send buf is empty */ +      sockets[i].flags      = 0; +      sockets[i].err        = 0; +      sys_sem_signal(socksem); +      return i; +    } +  } +  sys_sem_signal(socksem); +  return -1; +} + +/* Below this, the well-known socket functions are implemented. + * Use google.com or opengroup.org to get a good description :-) + * + * Exceptions are documented! + */ + +int +lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ +  struct lwip_socket *sock, *nsock; +  struct netconn *newconn; +  struct ip_addr naddr; +  u16_t port; +  int newsock; +  struct sockaddr_in sin; +  err_t err; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); +  sock = get_socket(s); +  if (!sock) +    return -1; + +  if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); +    sock_set_errno(sock, EWOULDBLOCK); +    return -1; +  } + +  newconn = netconn_accept(sock->conn); +  if (!newconn) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err)); +    sock_set_errno(sock, err_to_errno(sock->conn->err)); +    return -1; +  } + +  /* get the IP address and port of the remote host */ +  err = netconn_peer(newconn, &naddr, &port); +  if (err != ERR_OK) { +    netconn_delete(newconn); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  /* Note that POSIX only requires us to check addr is non-NULL. addrlen must +   * not be NULL if addr is valid. +   */ +  if (NULL != addr) { +    LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); +    memset(&sin, 0, sizeof(sin)); +    sin.sin_len = sizeof(sin); +    sin.sin_family = AF_INET; +    sin.sin_port = htons(port); +    sin.sin_addr.s_addr = naddr.addr; + +    if (*addrlen > sizeof(sin)) +      *addrlen = sizeof(sin); + +    MEMCPY(addr, &sin, *addrlen); +  } + +  newsock = alloc_socket(newconn); +  if (newsock == -1) { +    netconn_delete(newconn); +    sock_set_errno(sock, ENFILE); +    return -1; +  } +  LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); +  newconn->callback = event_callback; +  nsock = &sockets[newsock]; +  LWIP_ASSERT("invalid socket pointer", nsock != NULL); + +  sys_sem_wait(socksem); +  /* See event_callback: If data comes in right away after an accept, even +   * though the server task might not have created a new socket yet. +   * In that case, newconn->socket is counted down (newconn->socket--), +   * so nsock->rcvevent is >= 1 here! +   */ +  nsock->rcvevent += -1 - newconn->socket; +  newconn->socket = newsock; +  sys_sem_signal(socksem); + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); +  ip_addr_debug_print(SOCKETS_DEBUG, &naddr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); + +  sock_set_errno(sock, 0); +  return newsock; +} + +int +lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ +  struct lwip_socket *sock; +  struct ip_addr local_addr; +  u16_t local_port; +  err_t err; + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && +             ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), +             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + +  local_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; +  local_port = ((const struct sockaddr_in *)name)->sin_port; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); +  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); + +  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); + +  if (err != ERR_OK) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); +  sock_set_errno(sock, 0); +  return 0; +} + +int +lwip_close(int s) +{ +  struct lwip_socket *sock; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); + +  sock = get_socket(s); +  if (!sock) { +    return -1; +  } + +  netconn_delete(sock->conn); + +  sys_sem_wait(socksem); +  if (sock->lastdata) { +    netbuf_delete(sock->lastdata); +  } +  sock->lastdata   = NULL; +  sock->lastoffset = 0; +  sock->conn       = NULL; +  sock_set_errno(sock, 0); +  sys_sem_signal(socksem); +  return 0; +} + +int +lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ +  struct lwip_socket *sock; +  err_t err; + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && +             ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), +             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + +  if (((const struct sockaddr_in *)name)->sin_family == AF_UNSPEC) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); +    err = netconn_disconnect(sock->conn); +  } else { +    struct ip_addr remote_addr; +    u16_t remote_port; + +    remote_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; +    remote_port = ((const struct sockaddr_in *)name)->sin_port; + +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); +    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); +    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); + +    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); +  } + +  if (err != ERR_OK) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); +  sock_set_errno(sock, 0); +  return 0; +} + +/** + * Set a socket into listen mode. + * The socket may not have been used for another connection previously. + * + * @param s the socket to set to listening mode + * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1) + * @return 0 on success, non-zero on failure + */ +int +lwip_listen(int s, int backlog) +{ +  struct lwip_socket *sock; +  err_t err; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  /* limit the "backlog" parameter to fit in an u8_t */ +  if (backlog < 0) { +    backlog = 0; +  } +  if (backlog > 0xff) { +    backlog = 0xff; +  } + +  err = netconn_listen_with_backlog(sock->conn, backlog); + +  if (err != ERR_OK) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  sock_set_errno(sock, 0); +  return 0; +} + +int +lwip_recvfrom(int s, void *mem, size_t len, int flags, +        struct sockaddr *from, socklen_t *fromlen) +{ +  struct lwip_socket *sock; +  struct netbuf      *buf; +  u16_t               buflen, copylen, off = 0; +  struct ip_addr     *addr; +  u16_t               port; +  u8_t                done = 0; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); +  sock = get_socket(s); +  if (!sock) +    return -1; + +  do { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata)); +    /* Check if there is data left from the last recv operation. */ +    if (sock->lastdata) { +      buf = sock->lastdata; +    } else { +      /* If this is non-blocking call, then check first */ +      if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) &&  +          (sock->rcvevent <= 0)) { +        if (off > 0) { +          /* already received data, return that */ +          sock_set_errno(sock, 0); +          return off; +        } +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); +        sock_set_errno(sock, EWOULDBLOCK); +        return -1; +      } + +      /* No data was left from the previous operation, so we try to get +      some from the network. */ +      sock->lastdata = buf = netconn_recv(sock->conn); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf)); + +      if (!buf) { +        if (off > 0) { +          /* already received data, return that */ +          sock_set_errno(sock, 0); +          return off; +        } +        /* We should really do some error checking here. */ +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s)); +        sock_set_errno(sock, (((sock->conn->pcb.ip != NULL) && (sock->conn->err == ERR_OK)) +          ? ETIMEDOUT : err_to_errno(sock->conn->err))); +        return 0; +      } +    } + +    buflen = netbuf_len(buf); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%"U16_F" sock->lastoffset=%"U16_F"\n", +      buflen, len, off, sock->lastoffset)); + +    buflen -= sock->lastoffset; + +    if (len > buflen) { +      copylen = buflen; +    } else { +      copylen = (u16_t)len; +    } + +    /* copy the contents of the received buffer into +    the supplied memory pointer mem */ +    netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset); + +    off += copylen; + +    if (netconn_type(sock->conn) == NETCONN_TCP) { +      LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); +      len -= copylen; +      if ( (len <= 0) ||  +           (buf->p->flags & PBUF_FLAG_PUSH) ||  +           (sock->rcvevent <= 0) ||  +           ((flags & MSG_PEEK)!=0)) { +        done = 1; +      } +    } else { +      done = 1; +    } + +    /* Check to see from where the data was.*/ +    if (done) { +      if (from && fromlen) { +        struct sockaddr_in sin; + +        if (netconn_type(sock->conn) == NETCONN_TCP) { +          addr = (struct ip_addr*)&(sin.sin_addr.s_addr); +          netconn_getaddr(sock->conn, addr, &port, 0); +        } else { +          addr = netbuf_fromaddr(buf); +          port = netbuf_fromport(buf); +        } + +        memset(&sin, 0, sizeof(sin)); +        sin.sin_len = sizeof(sin); +        sin.sin_family = AF_INET; +        sin.sin_port = htons(port); +        sin.sin_addr.s_addr = addr->addr; + +        if (*fromlen > sizeof(sin)) { +          *fromlen = sizeof(sin); +        } + +        MEMCPY(from, &sin, *fromlen); + +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); +        ip_addr_debug_print(SOCKETS_DEBUG, addr); +        LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); +      } else { +  #if SOCKETS_DEBUG +        struct sockaddr_in sin; + +        if (netconn_type(sock->conn) == NETCONN_TCP) { +          addr = (struct ip_addr*)&(sin.sin_addr.s_addr); +          netconn_getaddr(sock->conn, addr, &port, 0); +        } else { +          addr = netbuf_fromaddr(buf); +          port = netbuf_fromport(buf); +        } + +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); +        ip_addr_debug_print(SOCKETS_DEBUG, addr); +        LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); +  #endif /*  SOCKETS_DEBUG */ +      } +    } + +    /* If we don't peek the incoming message... */ +    if ((flags & MSG_PEEK)==0) { +      /* If this is a TCP socket, check if there is data left in the +         buffer. If so, it should be saved in the sock structure for next +         time around. */ +      if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { +        sock->lastdata = buf; +        sock->lastoffset += copylen; +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf)); +      } else { +        sock->lastdata = NULL; +        sock->lastoffset = 0; +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf)); +        netbuf_delete(buf); +      } +    } +  } while (!done); + +  sock_set_errno(sock, 0); +  return off; +} + +int +lwip_read(int s, void *mem, size_t len) +{ +  return lwip_recvfrom(s, mem, len, 0, NULL, NULL); +} + +int +lwip_recv(int s, void *mem, size_t len, int flags) +{ +  return lwip_recvfrom(s, mem, len, flags, NULL, NULL); +} + +int +lwip_send(int s, const void *data, size_t size, int flags) +{ +  struct lwip_socket *sock; +  err_t err; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", +                              s, data, size, flags)); + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  if (sock->conn->type != NETCONN_TCP) { +#if (LWIP_UDP || LWIP_RAW) +    return lwip_sendto(s, data, size, flags, NULL, 0); +#else +    sock_set_errno(sock, err_to_errno(ERR_ARG)); +    return -1; +#endif /* (LWIP_UDP || LWIP_RAW) */ +  } + +  err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0)); + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); +  sock_set_errno(sock, err_to_errno(err)); +  return (err == ERR_OK ? (int)size : -1); +} + +int +lwip_sendto(int s, const void *data, size_t size, int flags, +       const struct sockaddr *to, socklen_t tolen) +{ +  struct lwip_socket *sock; +  struct ip_addr remote_addr; +  err_t err; +  u16_t short_size; +#if !LWIP_TCPIP_CORE_LOCKING +  struct netbuf buf; +  u16_t remote_port; +#endif + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  if (sock->conn->type == NETCONN_TCP) { +#if LWIP_TCP +    return lwip_send(s, data, size, flags); +#else +    sock_set_errno(sock, err_to_errno(ERR_ARG)); +    return -1; +#endif /* LWIP_TCP */ +  } + +  LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); +  short_size = (u16_t)size; +  LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || +             ((tolen == sizeof(struct sockaddr_in)) && +             ((((const struct sockaddr_in *)to)->sin_family) == AF_INET))), +             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + +#if LWIP_TCPIP_CORE_LOCKING +  /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ +  { struct pbuf* p; +   +    p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); +    if (p == NULL) { +      err = ERR_MEM; +    } else { +      p->payload = (void*)data; +      p->len = p->tot_len = short_size; +       +      remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr; +       +      LOCK_TCPIP_CORE(); +      if (sock->conn->type==NETCONN_RAW) { +        err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr); +      } else { +        err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((const struct sockaddr_in *)to)->sin_port)); +      } +      UNLOCK_TCPIP_CORE(); +       +      pbuf_free(p); +    } +  } +#else +  /* initialize a buffer */ +  buf.p = buf.ptr = NULL; +  if (to) { +    remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr; +    remote_port      = ntohs(((const struct sockaddr_in *)to)->sin_port); +    buf.addr         = &remote_addr; +    buf.port         = remote_port; +  } else { +    remote_addr.addr = 0; +    remote_port      = 0; +    buf.addr         = NULL; +    buf.port         = 0; +  } + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=", +              s, data, short_size, flags)); +  ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); + +  /* make the buffer point to the data that should be sent */ +#if LWIP_NETIF_TX_SINGLE_PBUF +  /* Allocate a new netbuf and copy the data into it. */ +  if (netbuf_alloc(&buf, short_size) == NULL) { +    err = ERR_MEM; +  } else { +    err = netbuf_take(&buf, data, short_size); +  } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ +  err = netbuf_ref(&buf, data, short_size); +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ +  if (err == ERR_OK) { +    /* send the data */ +    err = netconn_send(sock->conn, &buf); +  } + +  /* deallocated the buffer */ +  netbuf_free(&buf); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +  sock_set_errno(sock, err_to_errno(err)); +  return (err == ERR_OK ? short_size : -1); +} + +int +lwip_socket(int domain, int type, int protocol) +{ +  struct netconn *conn; +  int i; + +  LWIP_UNUSED_ARG(domain); + +  /* create a netconn */ +  switch (type) { +  case SOCK_RAW: +    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", +                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); +    break; +  case SOCK_DGRAM: +    conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? +                 NETCONN_UDPLITE : NETCONN_UDP, event_callback); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", +                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); +    break; +  case SOCK_STREAM: +    conn = netconn_new_with_callback(NETCONN_TCP, event_callback); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", +                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); +    break; +  default: +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", +                                 domain, type, protocol)); +    set_errno(EINVAL); +    return -1; +  } + +  if (!conn) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); +    set_errno(ENOBUFS); +    return -1; +  } + +  i = alloc_socket(conn); + +  if (i == -1) { +    netconn_delete(conn); +    set_errno(ENFILE); +    return -1; +  } +  conn->socket = i; +  LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); +  set_errno(0); +  return i; +} + +int +lwip_write(int s, const void *data, size_t size) +{ +  return lwip_send(s, data, size, 0); +} + +/** + * Go through the readset and writeset lists and see which socket of the sockets + * set in the sets has events. On return, readset, writeset and exceptset have + * the sockets enabled that had events. + * + * exceptset is not used for now!!! + * + * @param maxfdp1 the highest socket index in the sets + * @param readset in: set of sockets to check for read events; + *                out: set of sockets that had read events + * @param writeset in: set of sockets to check for write events; + *                 out: set of sockets that had write events + * @param exceptset not yet implemented + * @return number of sockets that had events (read+write) + */ +static int +lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset) +{ +  int i, nready = 0; +  fd_set lreadset, lwriteset, lexceptset; +  struct lwip_socket *p_sock; +   +  FD_ZERO(&lreadset); +  FD_ZERO(&lwriteset); +  FD_ZERO(&lexceptset); +   +  /* Go through each socket in each list to count number of sockets which +  currently match */ +  for(i = 0; i < maxfdp1; i++) { +    if (FD_ISSET(i, readset)) { +      /* See if netconn of this socket is ready for read */ +      p_sock = get_socket(i); +      if (p_sock && (p_sock->lastdata || (p_sock->rcvevent > 0))) { +        FD_SET(i, &lreadset); +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); +        nready++; +      } +    } +    if (FD_ISSET(i, writeset)) { +      /* See if netconn of this socket is ready for write */ +      p_sock = get_socket(i); +      if (p_sock && p_sock->sendevent) { +        FD_SET(i, &lwriteset); +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); +        nready++; +      } +    } +  } +  *readset = lreadset; +  *writeset = lwriteset; +  FD_ZERO(exceptset); +   +  return nready; +} + + +/** + * Processing exceptset is not yet implemented. + */ +int +lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, +               struct timeval *timeout) +{ +  int i; +  int nready; +  fd_set lreadset, lwriteset, lexceptset; +  u32_t msectimeout; +  struct lwip_select_cb select_cb; +  struct lwip_select_cb *p_selcb; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", +                  maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, +                  timeout ? (long)timeout->tv_sec : (long)-1, +                  timeout ? (long)timeout->tv_usec : (long)-1)); + +  select_cb.next = 0; +  select_cb.readset = readset; +  select_cb.writeset = writeset; +  select_cb.exceptset = exceptset; +  select_cb.sem_signalled = 0; + +  /* Protect ourselves searching through the list */ +  sys_sem_wait(selectsem); + +  if (readset) +    lreadset = *readset; +  else +    FD_ZERO(&lreadset); +  if (writeset) +    lwriteset = *writeset; +  else +    FD_ZERO(&lwriteset); +  if (exceptset) +    lexceptset = *exceptset; +  else +    FD_ZERO(&lexceptset); + +  /* Go through each socket in each list to count number of sockets which +     currently match */ +  nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); + +  /* If we don't have any current events, then suspend if we are supposed to */ +  if (!nready) { +    if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { +      sys_sem_signal(selectsem); +      if (readset) +        FD_ZERO(readset); +      if (writeset) +        FD_ZERO(writeset); +      if (exceptset) +        FD_ZERO(exceptset); +   +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); +      set_errno(0); +   +      return 0; +    } +     +    /* add our semaphore to list */ +    /* We don't actually need any dynamic memory. Our entry on the +     * list is only valid while we are in this function, so it's ok +     * to use local variables */ +     +    select_cb.sem = sys_sem_new(0); +    /* Note that we are still protected */ +    /* Put this select_cb on top of list */ +    select_cb.next = select_cb_list; +    select_cb_list = &select_cb; +     +    /* Now we can safely unprotect */ +    sys_sem_signal(selectsem); +     +    /* Now just wait to be woken */ +    if (timeout == 0) +      /* Wait forever */ +      msectimeout = 0; +    else { +      msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); +      if(msectimeout == 0) +        msectimeout = 1; +    } +     +    i = sys_sem_wait_timeout(select_cb.sem, msectimeout); +     +    /* Take us off the list */ +    sys_sem_wait(selectsem); +    if (select_cb_list == &select_cb) +      select_cb_list = select_cb.next; +    else +      for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) { +        if (p_selcb->next == &select_cb) { +          p_selcb->next = select_cb.next; +          break; +        } +      } +     +    sys_sem_signal(selectsem); +     +    sys_sem_free(select_cb.sem); +    if (i == 0)  { +      /* Timeout */ +      if (readset) +        FD_ZERO(readset); +      if (writeset) +        FD_ZERO(writeset); +      if (exceptset) +        FD_ZERO(exceptset); +   +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); +      set_errno(0); +   +      return 0; +    } +     +    if (readset) +      lreadset = *readset; +    else +      FD_ZERO(&lreadset); +    if (writeset) +      lwriteset = *writeset; +    else +      FD_ZERO(&lwriteset); +    if (exceptset) +      lexceptset = *exceptset; +    else +      FD_ZERO(&lexceptset); +     +    /* See what's set */ +    nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); +  } else +    sys_sem_signal(selectsem); +   +  if (readset) +    *readset = lreadset; +  if (writeset) +    *writeset = lwriteset; +  if (exceptset) +    *exceptset = lexceptset; +   +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); +  set_errno(0); +   +  return nready; +} + +/** + * Callback registered in the netconn layer for each socket-netconn. + * Processes recvevent (data available) and wakes up tasks waiting for select. + */ +static void +event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) +{ +  int s; +  struct lwip_socket *sock; +  struct lwip_select_cb *scb; + +  LWIP_UNUSED_ARG(len); + +  /* Get socket */ +  if (conn) { +    s = conn->socket; +    if (s < 0) { +      /* Data comes in right away after an accept, even though +       * the server task might not have created a new socket yet. +       * Just count down (or up) if that's the case and we +       * will use the data later. Note that only receive events +       * can happen before the new socket is set up. */ +      sys_sem_wait(socksem); +      if (conn->socket < 0) { +        if (evt == NETCONN_EVT_RCVPLUS) { +          conn->socket--; +        } +        sys_sem_signal(socksem); +        return; +      } +      sys_sem_signal(socksem); +    } + +    sock = get_socket(s); +    if (!sock) { +      return; +    } +  } else { +    return; +  } + +  sys_sem_wait(selectsem); +  /* Set event as required */ +  switch (evt) { +    case NETCONN_EVT_RCVPLUS: +      sock->rcvevent++; +      break; +    case NETCONN_EVT_RCVMINUS: +      sock->rcvevent--; +      break; +    case NETCONN_EVT_SENDPLUS: +      sock->sendevent = 1; +      break; +    case NETCONN_EVT_SENDMINUS: +      sock->sendevent = 0; +      break; +    default: +      LWIP_ASSERT("unknown event", 0); +      break; +  } +  sys_sem_signal(selectsem); + +  /* Now decide if anyone is waiting for this socket */ +  /* NOTE: This code is written this way to protect the select link list +     but to avoid a deadlock situation by releasing socksem before +     signalling for the select. This means we need to go through the list +     multiple times ONLY IF a select was actually waiting. We go through +     the list the number of waiting select calls + 1. This list is +     expected to be small. */ +  while (1) { +    sys_sem_wait(selectsem); +    for (scb = select_cb_list; scb; scb = scb->next) { +      if (scb->sem_signalled == 0) { +        /* Test this select call for our socket */ +        if (scb->readset && FD_ISSET(s, scb->readset)) +          if (sock->rcvevent > 0) +            break; +        if (scb->writeset && FD_ISSET(s, scb->writeset)) +          if (sock->sendevent) +            break; +      } +    } +    if (scb) { +      scb->sem_signalled = 1; +      sys_sem_signal(scb->sem); +      sys_sem_signal(selectsem); +    } else { +      sys_sem_signal(selectsem); +      break; +    } +  } +} + +/** + * Unimplemented: Close one end of a full-duplex connection. + * Currently, the full connection is closed. + */ +int +lwip_shutdown(int s, int how) +{ +  LWIP_UNUSED_ARG(how); +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); +  return lwip_close(s); /* XXX temporary hack until proper implementation */ +} + +static int +lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) +{ +  struct lwip_socket *sock; +  struct sockaddr_in sin; +  struct ip_addr naddr; + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  memset(&sin, 0, sizeof(sin)); +  sin.sin_len = sizeof(sin); +  sin.sin_family = AF_INET; + +  /* get the IP address and port */ +  netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); +  ip_addr_debug_print(SOCKETS_DEBUG, &naddr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); + +  sin.sin_port = htons(sin.sin_port); +  sin.sin_addr.s_addr = naddr.addr; + +  if (*namelen > sizeof(sin)) +    *namelen = sizeof(sin); + +  MEMCPY(name, &sin, *namelen); +  sock_set_errno(sock, 0); +  return 0; +} + +int +lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ +  return lwip_getaddrname(s, name, namelen, 0); +} + +int +lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) +{ +  return lwip_getaddrname(s, name, namelen, 1); +} + +int +lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ +  err_t err = ERR_OK; +  struct lwip_socket *sock = get_socket(s); +  struct lwip_setgetsockopt_data data; + +  if (!sock) +    return -1; + +  if ((NULL == optval) || (NULL == optlen)) { +    sock_set_errno(sock, EFAULT); +    return -1; +  } + +  /* Do length and type checks for the various options first, to keep it readable. */ +  switch (level) { +    +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { +        +    case SO_ACCEPTCONN: +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_ERROR: +    case SO_KEEPALIVE: +    /* UNIMPL case SO_CONTIMEO: */ +    /* UNIMPL case SO_SNDTIMEO: */ +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +#endif /* LWIP_SO_RCVBUF */ +    /* UNIMPL case SO_OOBINLINE: */ +    /* UNIMPL case SO_SNDBUF: */ +    /* UNIMPL case SO_RCVLOWAT: */ +    /* UNIMPL case SO_SNDLOWAT: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    case SO_TYPE: +    /* UNIMPL case SO_USELOOPBACK: */ +      if (*optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; + +    case SO_NO_CHECK: +      if (*optlen < sizeof(int)) { +        err = EINVAL; +      } +#if LWIP_UDP +      if ((sock->conn->type != NETCONN_UDP) || +          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { +        /* this flag is only available for UDP, not for UDP lite */ +        err = EAFNOSUPPORT; +      } +#endif /* LWIP_UDP */ +      break; + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +                      +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    /* UNIMPL case IP_HDRINCL: */ +    /* UNIMPL case IP_RCVDSTADDR: */ +    /* UNIMPL case IP_RCVIF: */ +    case IP_TTL: +    case IP_TOS: +      if (*optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      if (*optlen < sizeof(u8_t)) { +        err = EINVAL; +      } +      break; +    case IP_MULTICAST_IF: +      if (*optlen < sizeof(struct in_addr)) { +        err = EINVAL; +      } +      break; +#endif /* LWIP_IGMP */ + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +          +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    if (*optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } +     +    /* If this is no TCP socket, ignore any options. */ +    if (sock->conn->type != NETCONN_TCP) +      return 0; + +    switch (optname) { +    case TCP_NODELAY: +    case TCP_KEEPALIVE: +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +    case TCP_KEEPINTVL: +    case TCP_KEEPCNT: +#endif /* LWIP_TCP_KEEPALIVE */ +      break; +        +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    if (*optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } +     +    /* If this is no UDP lite socket, ignore any options. */ +    if (sock->conn->type != NETCONN_UDPLITE) +      return 0; + +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +    case UDPLITE_RECV_CSCOV: +      break; +        +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP && LWIP_UDPLITE*/ +/* UNDEFINED LEVEL */ +  default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", +                                  s, level, optname)); +      err = ENOPROTOOPT; +  }  /* switch */ + +    +  if (err != ERR_OK) { +    sock_set_errno(sock, err); +    return -1; +  } + +  /* Now do the actual option processing */ +  data.sock = sock; +  data.level = level; +  data.optname = optname; +  data.optval = optval; +  data.optlen = optlen; +  data.err = err; +  tcpip_callback(lwip_getsockopt_internal, &data); +  sys_arch_sem_wait(sock->conn->op_completed, 0); +  /* maybe lwip_getsockopt_internal has changed err */ +  err = data.err; + +  sock_set_errno(sock, err); +  return err ? -1 : 0; +} + +static void +lwip_getsockopt_internal(void *arg) +{ +  struct lwip_socket *sock; +#ifdef LWIP_DEBUG +  int s; +#endif /* LWIP_DEBUG */ +  int level, optname; +  void *optval; +  struct lwip_setgetsockopt_data *data; + +  LWIP_ASSERT("arg != NULL", arg != NULL); + +  data = (struct lwip_setgetsockopt_data*)arg; +  sock = data->sock; +#ifdef LWIP_DEBUG +  s = data->s; +#endif /* LWIP_DEBUG */ +  level = data->level; +  optname = data->optname; +  optval = data->optval; + +  switch (level) { +    +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { + +    /* The option flags */ +    case SO_ACCEPTCONN: +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_KEEPALIVE: +    /* UNIMPL case SO_OOBINCLUDE: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    /*case SO_USELOOPBACK: UNIMPL */ +      *(int*)optval = sock->conn->pcb.ip->so_options & optname; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", +                                  s, optname, (*(int*)optval?"on":"off"))); +      break; + +    case SO_TYPE: +      switch (NETCONNTYPE_GROUP(sock->conn->type)) { +      case NETCONN_RAW: +        *(int*)optval = SOCK_RAW; +        break; +      case NETCONN_TCP: +        *(int*)optval = SOCK_STREAM; +        break; +      case NETCONN_UDP: +        *(int*)optval = SOCK_DGRAM; +        break; +      default: /* unrecognized socket type */ +        *(int*)optval = sock->conn->type; +        LWIP_DEBUGF(SOCKETS_DEBUG, +                    ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", +                    s, *(int *)optval)); +      }  /* switch (sock->conn->type) */ +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", +                  s, *(int *)optval)); +      break; + +    case SO_ERROR: +      if (sock->err == 0) { +        sock_set_errno(sock, err_to_errno(sock->conn->err)); +      }  +      *(int *)optval = sock->err; +      sock->err = 0; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", +                  s, *(int *)optval)); +      break; + +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +      *(int *)optval = sock->conn->recv_timeout; +      break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +      *(int *)optval = sock->conn->recv_bufsize; +      break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_UDP +    case SO_NO_CHECK: +      *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; +      break; +#endif /* LWIP_UDP*/ +    }  /* switch (optname) */ +    break; + +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    case IP_TTL: +      *(int*)optval = sock->conn->pcb.ip->ttl; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", +                  s, *(int *)optval)); +      break; +    case IP_TOS: +      *(int*)optval = sock->conn->pcb.ip->tos; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", +                  s, *(int *)optval)); +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      *(u8_t*)optval = sock->conn->pcb.ip->ttl; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", +                  s, *(int *)optval)); +      break; +    case IP_MULTICAST_IF: +      ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", +                  s, *(u32_t *)optval)); +      break; +#endif /* LWIP_IGMP */ +    }  /* switch (optname) */ +    break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    switch (optname) { +    case TCP_NODELAY: +      *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", +                  s, (*(int*)optval)?"on":"off") ); +      break; +    case TCP_KEEPALIVE: +      *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", +                  s, *(int *)optval)); +      break; + +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", +                  s, *(int *)optval)); +      break; +    case TCP_KEEPINTVL: +      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", +                  s, *(int *)optval)); +      break; +    case TCP_KEEPCNT: +      *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", +                  s, *(int *)optval)); +      break; +#endif /* LWIP_TCP_KEEPALIVE */ + +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +  /* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +      *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", +                  s, (*(int*)optval)) ); +      break; +    case UDPLITE_RECV_CSCOV: +      *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", +                  s, (*(int*)optval)) ); +      break; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP */ +  } /* switch (level) */ +  sys_sem_signal(sock->conn->op_completed); +} + +int +lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ +  struct lwip_socket *sock = get_socket(s); +  int err = ERR_OK; +  struct lwip_setgetsockopt_data data; + +  if (!sock) +    return -1; + +  if (NULL == optval) { +    sock_set_errno(sock, EFAULT); +    return -1; +  } + +  /* Do length and type checks for the various options first, to keep it readable. */ +  switch (level) { + +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { + +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_KEEPALIVE: +    /* UNIMPL case case SO_CONTIMEO: */ +    /* UNIMPL case case SO_SNDTIMEO: */ +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +#endif /* LWIP_SO_RCVBUF */ +    /* UNIMPL case SO_OOBINLINE: */ +    /* UNIMPL case SO_SNDBUF: */ +    /* UNIMPL case SO_RCVLOWAT: */ +    /* UNIMPL case SO_SNDLOWAT: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    /* UNIMPL case SO_USELOOPBACK: */ +      if (optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; +    case SO_NO_CHECK: +      if (optlen < sizeof(int)) { +        err = EINVAL; +      } +#if LWIP_UDP +      if ((sock->conn->type != NETCONN_UDP) || +          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { +        /* this flag is only available for UDP, not for UDP lite */ +        err = EAFNOSUPPORT; +      } +#endif /* LWIP_UDP */ +      break; +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", +                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; + +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    /* UNIMPL case IP_HDRINCL: */ +    /* UNIMPL case IP_RCVDSTADDR: */ +    /* UNIMPL case IP_RCVIF: */ +    case IP_TTL: +    case IP_TOS: +      if (optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      if (optlen < sizeof(u8_t)) { +        err = EINVAL; +      } +      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { +        err = EAFNOSUPPORT; +      } +      break; +    case IP_MULTICAST_IF: +      if (optlen < sizeof(struct in_addr)) { +        err = EINVAL; +      } +      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { +        err = EAFNOSUPPORT; +      } +      break; +    case IP_ADD_MEMBERSHIP: +    case IP_DROP_MEMBERSHIP: +      if (optlen < sizeof(struct ip_mreq)) { +        err = EINVAL; +      } +      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { +        err = EAFNOSUPPORT; +      } +      break; +#endif /* LWIP_IGMP */ +      default: +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", +                    s, optname)); +        err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    if (optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } + +    /* If this is no TCP socket, ignore any options. */ +    if (sock->conn->type != NETCONN_TCP) +      return 0; + +    switch (optname) { +    case TCP_NODELAY: +    case TCP_KEEPALIVE: +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +    case TCP_KEEPINTVL: +    case TCP_KEEPCNT: +#endif /* LWIP_TCP_KEEPALIVE */ +      break; + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", +                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    if (optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } + +    /* If this is no UDP lite socket, ignore any options. */ +    if (sock->conn->type != NETCONN_UDPLITE) +      return 0; + +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +    case UDPLITE_RECV_CSCOV: +      break; + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", +                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP && LWIP_UDPLITE */ +/* UNDEFINED LEVEL */ +  default: +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", +                s, level, optname)); +    err = ENOPROTOOPT; +  }  /* switch (level) */ + + +  if (err != ERR_OK) { +    sock_set_errno(sock, err); +    return -1; +  } + + +  /* Now do the actual option processing */ +  data.sock = sock; +  data.level = level; +  data.optname = optname; +  data.optval = (void*)optval; +  data.optlen = &optlen; +  data.err = err; +  tcpip_callback(lwip_setsockopt_internal, &data); +  sys_arch_sem_wait(sock->conn->op_completed, 0); +  /* maybe lwip_setsockopt_internal has changed err */ +  err = data.err; + +  sock_set_errno(sock, err); +  return err ? -1 : 0; +} + +static void +lwip_setsockopt_internal(void *arg) +{ +  struct lwip_socket *sock; +#ifdef LWIP_DEBUG +  int s; +#endif /* LWIP_DEBUG */ +  int level, optname; +  const void *optval; +  struct lwip_setgetsockopt_data *data; + +  LWIP_ASSERT("arg != NULL", arg != NULL); + +  data = (struct lwip_setgetsockopt_data*)arg; +  sock = data->sock; +#ifdef LWIP_DEBUG +  s = data->s; +#endif /* LWIP_DEBUG */ +  level = data->level; +  optname = data->optname; +  optval = data->optval; + +  switch (level) { + +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { + +    /* The option flags */ +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_KEEPALIVE: +    /* UNIMPL case SO_OOBINCLUDE: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    /* UNIMPL case SO_USELOOPBACK: */ +      if (*(int*)optval) { +        sock->conn->pcb.ip->so_options |= optname; +      } else { +        sock->conn->pcb.ip->so_options &= ~optname; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", +                  s, optname, (*(int*)optval?"on":"off"))); +      break; +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +      sock->conn->recv_timeout = ( *(int*)optval ); +      break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +      sock->conn->recv_bufsize = ( *(int*)optval ); +      break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_UDP +    case SO_NO_CHECK: +      if (*(int*)optval) { +        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); +      } else { +        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); +      } +      break; +#endif /* LWIP_UDP */ +    }  /* switch (optname) */ +    break; + +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    case IP_TTL: +      sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", +                  s, sock->conn->pcb.ip->ttl)); +      break; +    case IP_TOS: +      sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", +                  s, sock->conn->pcb.ip->tos)); +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); +      break; +    case IP_MULTICAST_IF: +      sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr; +      break; +    case IP_ADD_MEMBERSHIP: +    case IP_DROP_MEMBERSHIP: +      { +        /* If this is a TCP or a RAW socket, ignore these options. */ +        struct ip_mreq *imr = (struct ip_mreq *)optval; +        if(optname == IP_ADD_MEMBERSHIP){ +          data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); +        } else { +          data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); +        } +        if(data->err != ERR_OK) { +          data->err = EADDRNOTAVAIL; +        } +      } +      break; +#endif /* LWIP_IGMP */ +    }  /* switch (optname) */ +    break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    switch (optname) { +    case TCP_NODELAY: +      if (*(int*)optval) { +        sock->conn->pcb.tcp->flags |= TF_NODELAY; +      } else { +        sock->conn->pcb.tcp->flags &= ~TF_NODELAY; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", +                  s, (*(int *)optval)?"on":"off") ); +      break; +    case TCP_KEEPALIVE: +      sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_idle)); +      break; + +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +      sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_idle)); +      break; +    case TCP_KEEPINTVL: +      sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_intvl)); +      break; +    case TCP_KEEPCNT: +      sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_cnt)); +      break; +#endif /* LWIP_TCP_KEEPALIVE */ + +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP*/ +#if LWIP_UDP && LWIP_UDPLITE +  /* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +      if ((*(int*)optval != 0) && (*(int*)optval < 8)) { +        /* don't allow illegal values! */ +        sock->conn->pcb.udp->chksum_len_tx = 8; +      } else { +        sock->conn->pcb.udp->chksum_len_tx = *(int*)optval; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", +                  s, (*(int*)optval)) ); +      break; +    case UDPLITE_RECV_CSCOV: +      if ((*(int*)optval != 0) && (*(int*)optval < 8)) { +        /* don't allow illegal values! */ +        sock->conn->pcb.udp->chksum_len_rx = 8; +      } else { +        sock->conn->pcb.udp->chksum_len_rx = *(int*)optval; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", +                  s, (*(int*)optval)) ); +      break; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP */ +  }  /* switch (level) */ +  sys_sem_signal(sock->conn->op_completed); +} + +int +lwip_ioctl(int s, long cmd, void *argp) +{ +  struct lwip_socket *sock = get_socket(s); +  u16_t buflen = 0; +  s16_t recv_avail; + +  if (!sock) +    return -1; + +  switch (cmd) { +  case FIONREAD: +    if (!argp) { +      sock_set_errno(sock, EINVAL); +      return -1; +    } + +    SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); +    if (recv_avail < 0) +      recv_avail = 0; +    *((u16_t*)argp) = (u16_t)recv_avail; + +    /* Check if there is data left from the last recv operation. /maq 041215 */ +    if (sock->lastdata) { +      buflen = netbuf_len(sock->lastdata); +      buflen -= sock->lastoffset; + +      *((u16_t*)argp) += buflen; +    } + +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); +    sock_set_errno(sock, 0); +    return 0; + +  case FIONBIO: +    if (argp && *(u32_t*)argp) +      sock->flags |= O_NONBLOCK; +    else +      sock->flags &= ~O_NONBLOCK; +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK))); +    sock_set_errno(sock, 0); +    return 0; + +  default: +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); +    sock_set_errno(sock, ENOSYS); /* not yet implemented */ +    return -1; +  } /* switch (cmd) */ +} + +#endif /* LWIP_SOCKET */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/api/tcpip.c b/firmware/microblaze/lwip/lwip-1.3.1/src/api/tcpip.c new file mode 100644 index 000000000..002df90b2 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/api/tcpip.c @@ -0,0 +1,596 @@ +/** + * @file + * Sequential API Main thread module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/ip_frag.h" +#include "lwip/tcp.h" +#include "lwip/autoip.h" +#include "lwip/dhcp.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/tcpip.h" +#include "lwip/init.h" +#include "netif/etharp.h" +#include "netif/ppp_oe.h" + +/* global variables */ +static void (* tcpip_init_done)(void *arg); +static void *tcpip_init_done_arg; +static sys_mbox_t mbox = SYS_MBOX_NULL; + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +sys_sem_t lock_tcpip_core; +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +#if LWIP_TCP +/* global variable that shows if the tcp timer is currently scheduled or not */ +static int tcpip_tcp_timer_active; + +/** + * Timer callback function that calls tcp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +tcpip_tcp_timer(void *arg) +{ +  LWIP_UNUSED_ARG(arg); + +  /* call TCP timer handler */ +  tcp_tmr(); +  /* timer still needed? */ +  if (tcp_active_pcbs || tcp_tw_pcbs) { +    /* restart timer */ +    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); +  } else { +    /* disable timer */ +    tcpip_tcp_timer_active = 0; +  } +} + +#if !NO_SYS +/** + * Called from TCP_REG when registering a new PCB: + * the reason is to have the TCP timer only running when + * there are active (or time-wait) PCBs. + */ +void +tcp_timer_needed(void) +{ +  /* timer is off but needed again? */ +  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { +    /* enable and start timer */ +    tcpip_tcp_timer_active = 1; +    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); +  } +} +#endif /* !NO_SYS */ +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +/** + * Timer callback function that calls ip_reass_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +ip_reass_timer(void *arg) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n")); +  ip_reass_tmr(); +  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); +} +#endif /* IP_REASSEMBLY */ + +#if LWIP_ARP +/** + * Timer callback function that calls etharp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +arp_timer(void *arg) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n")); +  etharp_tmr(); +  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +} +#endif /* LWIP_ARP */ + +#if LWIP_DHCP +/** + * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dhcp_timer_coarse(void *arg) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); +  dhcp_coarse_tmr(); +  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); +} + +/** + * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dhcp_timer_fine(void *arg) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); +  dhcp_fine_tmr(); +  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); +} +#endif /* LWIP_DHCP */ + +#if LWIP_AUTOIP +/** + * Timer callback function that calls autoip_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +autoip_timer(void *arg) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n")); +  autoip_tmr(); +  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); +} +#endif /* LWIP_AUTOIP */ + +#if LWIP_IGMP +/** + * Timer callback function that calls igmp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +igmp_timer(void *arg) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n")); +  igmp_tmr(); +  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Timer callback function that calls dns_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dns_timer(void *arg) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n")); +  dns_tmr(); +  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); +} +#endif /* LWIP_DNS */ + +/** + * The main lwIP thread. This thread has exclusive access to lwIP core functions + * (unless access to them is not locked). Other threads communicate with this + * thread using message boxes. + * + * It also starts all the timers to make sure they are running in the right + * thread context. + * + * @param arg unused argument + */ +static void +tcpip_thread(void *arg) +{ +  struct tcpip_msg *msg; +  LWIP_UNUSED_ARG(arg); + +#if IP_REASSEMBLY +  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); +#endif /* IP_REASSEMBLY */ +#if LWIP_ARP +  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +#endif /* LWIP_ARP */ +#if LWIP_DHCP +  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); +  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP +  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); +#endif /* LWIP_AUTOIP */ +#if LWIP_IGMP +  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); +#endif /* LWIP_IGMP */ +#if LWIP_DNS +  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); +#endif /* LWIP_DNS */ + +  if (tcpip_init_done != NULL) { +    tcpip_init_done(tcpip_init_done_arg); +  } + +  LOCK_TCPIP_CORE(); +  while (1) {                          /* MAIN Loop */ +    sys_mbox_fetch(mbox, (void *)&msg); +    switch (msg->type) { +#if LWIP_NETCONN +    case TCPIP_MSG_API: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); +      msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); +      break; +#endif /* LWIP_NETCONN */ + +    case TCPIP_MSG_INPKT: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); +#if LWIP_ARP +      if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) { +        ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); +      } else +#endif /* LWIP_ARP */ +      { ip_input(msg->msg.inp.p, msg->msg.inp.netif); +      } +      memp_free(MEMP_TCPIP_MSG_INPKT, msg); +      break; + +#if LWIP_NETIF_API +    case TCPIP_MSG_NETIFAPI: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg)); +      msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg)); +      break; +#endif /* LWIP_NETIF_API */ + +    case TCPIP_MSG_CALLBACK: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); +      msg->msg.cb.f(msg->msg.cb.ctx); +      memp_free(MEMP_TCPIP_MSG_API, msg); +      break; + +    case TCPIP_MSG_TIMEOUT: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); +      sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); +      memp_free(MEMP_TCPIP_MSG_API, msg); +      break; +    case TCPIP_MSG_UNTIMEOUT: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); +      sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); +      memp_free(MEMP_TCPIP_MSG_API, msg); +      break; + +    default: +      break; +    } +  } +} + +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, p->payload pointing to the Ethernet header or + *          to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag) + * @param inp the network interface on which the packet was received + */ +err_t +tcpip_input(struct pbuf *p, struct netif *inp) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_INPKT); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_INPKT; +    msg->msg.inp.p = p; +    msg->msg.inp.netif = inp; +    if (sys_mbox_trypost(mbox, msg) != ERR_OK) { +      memp_free(MEMP_TCPIP_MSG_INPKT, msg); +      return ERR_MEM; +    } +    return ERR_OK; +  } +  return ERR_VAL; +} + +/** + * Call a specific function in the thread context of + * tcpip_thread for easy access synchronization. + * A function called in that way may access lwIP core code + * without fearing concurrent access. + * + * @param f the function to call + * @param ctx parameter passed to f + * @param block 1 to block until the request is posted, 0 to non-blocking mode + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_API); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_CALLBACK; +    msg->msg.cb.f = f; +    msg->msg.cb.ctx = ctx; +    if (block) { +      sys_mbox_post(mbox, msg); +    } else { +      if (sys_mbox_trypost(mbox, msg) != ERR_OK) { +        memp_free(MEMP_TCPIP_MSG_API, msg); +        return ERR_MEM; +      } +    } +    return ERR_OK; +  } +  return ERR_VAL; +} + +/** + * call sys_timeout in tcpip_thread + * + * @param msec time in miliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_API); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_TIMEOUT; +    msg->msg.tmo.msecs = msecs; +    msg->msg.tmo.h = h; +    msg->msg.tmo.arg = arg; +    sys_mbox_post(mbox, msg); +    return ERR_OK; +  } +  return ERR_VAL; +} + +/** + * call sys_untimeout in tcpip_thread + * + * @param msec time in miliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_untimeout(sys_timeout_handler h, void *arg) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_API); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_UNTIMEOUT; +    msg->msg.tmo.h = h; +    msg->msg.tmo.arg = arg; +    sys_mbox_post(mbox, msg); +    return ERR_OK; +  } +  return ERR_VAL; +} + +#if LWIP_NETCONN +/** + * Call the lower part of a netconn_* function + * This function is then running in the thread context + * of tcpip_thread and has exclusive access to lwIP core code. + * + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_apimsg(struct api_msg *apimsg) +{ +  struct tcpip_msg msg; +   +  if (mbox != SYS_MBOX_NULL) { +    msg.type = TCPIP_MSG_API; +    msg.msg.apimsg = apimsg; +    sys_mbox_post(mbox, &msg); +    sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0); +    return ERR_OK; +  } +  return ERR_VAL; +} + +#if LWIP_TCPIP_CORE_LOCKING +/** + * Call the lower part of a netconn_* function + * This function has exclusive access to lwIP core code by locking it + * before the function is called. + * + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK (only for compatibility fo tcpip_apimsg()) + */ +err_t +tcpip_apimsg_lock(struct api_msg *apimsg) +{ +  LOCK_TCPIP_CORE(); +  apimsg->function(&(apimsg->msg)); +  UNLOCK_TCPIP_CORE(); +  return ERR_OK; + +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +#if LWIP_NETIF_API +#if !LWIP_TCPIP_CORE_LOCKING +/** + * Much like tcpip_apimsg, but calls the lower part of a netifapi_* + * function. + * + * @param netifapimsg a struct containing the function to call and its parameters + * @return error code given back by the function that was called + */ +err_t +tcpip_netifapi(struct netifapi_msg* netifapimsg) +{ +  struct tcpip_msg msg; +   +  if (mbox != SYS_MBOX_NULL) { +    netifapimsg->msg.sem = sys_sem_new(0); +    if (netifapimsg->msg.sem == SYS_SEM_NULL) { +      netifapimsg->msg.err = ERR_MEM; +      return netifapimsg->msg.err; +    } +     +    msg.type = TCPIP_MSG_NETIFAPI; +    msg.msg.netifapimsg = netifapimsg; +    sys_mbox_post(mbox, &msg); +    sys_sem_wait(netifapimsg->msg.sem); +    sys_sem_free(netifapimsg->msg.sem); +    return netifapimsg->msg.err; +  } +  return ERR_VAL; +} +#else /* !LWIP_TCPIP_CORE_LOCKING */ +/** + * Call the lower part of a netifapi_* function + * This function has exclusive access to lwIP core code by locking it + * before the function is called. + * + * @param netifapimsg a struct containing the function to call and its parameters + * @return ERR_OK (only for compatibility fo tcpip_netifapi()) + */ +err_t +tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) +{ +  LOCK_TCPIP_CORE();   +  netifapimsg->function(&(netifapimsg->msg)); +  UNLOCK_TCPIP_CORE(); +  return netifapimsg->msg.err; +} +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +/** + * Initialize this module: + * - initialize all sub modules + * - start the tcpip_thread + * + * @param initfunc a function to call when tcpip_thread is running and finished initializing + * @param arg argument to pass to initfunc + */ +void +tcpip_init(void (* initfunc)(void *), void *arg) +{ +  lwip_init(); + +  tcpip_init_done = initfunc; +  tcpip_init_done_arg = arg; +  mbox = sys_mbox_new(TCPIP_MBOX_SIZE); +#if LWIP_TCPIP_CORE_LOCKING +  lock_tcpip_core = sys_sem_new(1); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +  sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); +} + +/** + * Simple callback function used with tcpip_callback to free a pbuf + * (pbuf_free has a wrong signature for tcpip_callback) + * + * @param p The pbuf (chain) to be dereferenced. + */ +static void +pbuf_free_int(void *p) +{ +  struct pbuf *q = p; +  pbuf_free(q); +} + +/** + * A simple wrapper function that allows you to free a pbuf from interrupt context. + * + * @param p The pbuf (chain) to be dereferenced. + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +pbuf_free_callback(struct pbuf *p) +{ +  return tcpip_callback_with_block(pbuf_free_int, p, 0); +} + +/** + * A simple wrapper function that allows you to free heap memory from + * interrupt context. + * + * @param m the heap memory to free + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +mem_free_callback(void *m) +{ +  return tcpip_callback_with_block(mem_free, m, 0); +} + +#endif /* !NO_SYS */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/#tcp_out.c# b/firmware/microblaze/lwip/lwip-1.3.1/src/core/#tcp_out.c# new file mode 100644 index 000000000..ca72d9dcc --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/#tcp_out.c# @@ -0,0 +1,981 @@ +/** + * @file + * Transmission Control Protocol, outgoing traffic + * + * The output functions of TCP. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +#include <string.h> + +/* Forward declarations.*/ +static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); + +static struct tcp_hdr * +tcp_output_set_header(struct tcp_pcb *pcb, struct pbuf *p, int optlen, +                      u32_t seqno_be /* already in network byte order */) +{ +  struct tcp_hdr *tcphdr = p->payload; +  tcphdr->src = htons(pcb->local_port); +  tcphdr->dest = htons(pcb->remote_port); +  tcphdr->seqno = seqno_be; +  tcphdr->ackno = htonl(pcb->rcv_nxt); +  TCPH_FLAGS_SET(tcphdr, TCP_ACK); +  tcphdr->wnd = htons(pcb->rcv_ann_wnd); +  tcphdr->urgp = 0; +  TCPH_HDRLEN_SET(tcphdr, (5 + optlen / 4)); +  tcphdr->chksum = 0; + +  /* If we're sending a packet, update the announced right window edge */ +  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + +  return tcphdr; +} + +/** + * Called by tcp_close() to send a segment including flags but not data. + * + * @param pcb the tcp_pcb over which to send a segment + * @param flags the flags to set in the segment header + * @return ERR_OK if sent, another err_t otherwise + */ +err_t +tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) +{ +  /* no data, no length, flags, copy=1, no optdata */ +  return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, 0); +} + +/** + * Write data for sending (but does not send it immediately). + * + * It waits in the expectation of more data being sent soon (as + * it can send them more efficiently by combining them together). + * To prompt the system to send data now, call tcp_output() after + * calling tcp_write(). + *  + * @param pcb Protocol control block of the TCP connection to enqueue data for. + * @param data pointer to the data to send + * @param len length (in bytes) of the data to send + * @param apiflags combination of following flags : + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, + * @return ERR_OK if enqueued, another err_t on error + *  + * @see tcp_write() + */ +err_t +tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) +{ +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb, +    data, len, (u16_t)apiflags)); +  /* connection is in valid state for data transmission? */ +  if (pcb->state == ESTABLISHED || +     pcb->state == CLOSE_WAIT || +     pcb->state == SYN_SENT || +     pcb->state == SYN_RCVD) { +    if (len > 0) { +#if LWIP_TCP_TIMESTAMPS +      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags,  +                         pcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0); +#else +      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, 0); +#endif +    } +    return ERR_OK; +  } else { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | 3, ("tcp_write() called in invalid state\n")); +    return ERR_CONN; +  } +} + +/** + * Enqueue data and/or TCP options for transmission + * + * Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and tcp_write(). + * + * @param pcb Protocol control block for the TCP connection to enqueue data for. + * @param arg Pointer to the data to be enqueued for sending. + * @param len Data length in bytes + * @param flags tcp header flags to set in the outgoing segment + * @param apiflags combination of following flags : + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, + * @param optflags options to include in segment later on (see definition of struct tcp_seg) + */ +err_t +tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, +            u8_t flags, u8_t apiflags, u8_t optflags) +{ +  struct pbuf *p; +  struct tcp_seg *seg, *useg, *queue; +  u32_t seqno; +  u16_t left, seglen; +  void *ptr; +  u16_t queuelen; +  u8_t optlen; + +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG,  +              ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n", +               (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags)); +  LWIP_ERROR("tcp_enqueue: packet needs payload, options, or SYN/FIN (programmer violates API)", +             ((len != 0) || (optflags != 0) || ((flags & (TCP_SYN | TCP_FIN)) != 0)), +             return ERR_ARG;); +  LWIP_ERROR("tcp_enqueue: len != 0 || arg == NULL (programmer violates API)",  +             ((len != 0) || (arg == NULL)), return ERR_ARG;); + +  /* fail on too much data */ +  if (len > pcb->snd_buf) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf)); +    pcb->flags |= TF_NAGLEMEMERR; +    return ERR_MEM; +  } +  left = len; +  ptr = arg; + +  optlen = LWIP_TCP_OPT_LENGTH(optflags); + +  /* seqno will be the sequence number of the first segment enqueued +   * by the call to this function. */ +  seqno = pcb->snd_lbb; + +  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + +  /* If total number of pbufs on the unsent/unacked queues exceeds the +   * configured maximum, return an error */ +  queuelen = pcb->snd_queuelen; +  /* check for configured max queuelen and possible overflow */ +  if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); +    TCP_STATS_INC(tcp.memerr); +    pcb->flags |= TF_NAGLEMEMERR; +    return ERR_MEM; +  } +  if (queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty", +      pcb->unacked != NULL || pcb->unsent != NULL); +  } else { +    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty", +      pcb->unacked == NULL && pcb->unsent == NULL); +  } + +  /* First, break up the data into segments and tuck them together in +   * the local "queue" variable. */ +  useg = queue = seg = NULL; +  seglen = 0; +  while (queue == NULL || left > 0) { +    /* The segment length (including options) should be at most the MSS */ +    seglen = left > (pcb->mss - optlen) ? (pcb->mss - optlen) : left; + +    /* Allocate memory for tcp_seg, and fill in fields. */ +    seg = memp_malloc(MEMP_TCP_SEG); +    if (seg == NULL) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                  ("tcp_enqueue: could not allocate memory for tcp_seg\n")); +      goto memerr; +    } +    seg->next = NULL; +    seg->p = NULL; + +    /* first segment of to-be-queued data? */ +    if (queue == NULL) { +      queue = seg; +    } +    /* subsequent segments of to-be-queued data */ +    else { +      /* Attach the segment to the end of the queued segments */ +      LWIP_ASSERT("useg != NULL", useg != NULL); +      useg->next = seg; +    } +    /* remember last segment of to-be-queued data for next iteration */ +    useg = seg; + +    /* If copy is set, memory should be allocated +     * and data copied into pbuf, otherwise data comes from +     * ROM or other static memory, and need not be copied.  */ +    if (apiflags & TCP_WRITE_FLAG_COPY) { +      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen + optlen, PBUF_RAM)) == NULL) { +        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                    ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); +        goto memerr; +      } +      LWIP_ASSERT("check that first pbuf can hold the complete seglen", +                  (seg->p->len >= seglen + optlen)); +      queuelen += pbuf_clen(seg->p); +      if (arg != NULL) { +        MEMCPY((char *)seg->p->payload + optlen, ptr, seglen); +      } +      seg->dataptr = seg->p->payload; +    } +    /* do not copy data */ +    else { +      /* First, allocate a pbuf for the headers. */ +      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { +        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                    ("tcp_enqueue: could not allocate memory for header pbuf\n")); +        goto memerr; +      } +      queuelen += pbuf_clen(seg->p); + +      /* Second, allocate a pbuf for holding the data. +       * since the referenced data is available at least until it is sent out on the +       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM +       * instead of PBUF_REF here. +       */ +      if (left > 0) { +        if ((p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { +          /* If allocation fails, we have to deallocate the header pbuf as well. */ +          pbuf_free(seg->p); +          seg->p = NULL; +          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                      ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); +          goto memerr; +        } +        ++queuelen; +        /* reference the non-volatile payload data */ +        p->payload = ptr; +        seg->dataptr = ptr; + +        /* Concatenate the headers and data pbufs together. */ +        pbuf_cat(seg->p/*header*/, p/*data*/); +        p = NULL; +      } +    } + +    /* Now that there are more segments queued, we check again if the +    length of the queue exceeds the configured maximum or overflows. */ +    if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); +      goto memerr; +    } + +    seg->len = seglen; + +    /* build TCP header */ +    if (pbuf_header(seg->p, TCP_HLEN)) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n")); +      TCP_STATS_INC(tcp.err); +      goto memerr; +    } +    seg->tcphdr = seg->p->payload; +    seg->tcphdr->src = htons(pcb->local_port); +    seg->tcphdr->dest = htons(pcb->remote_port); +    seg->tcphdr->seqno = htonl(seqno); +    seg->tcphdr->urgp = 0; +    TCPH_FLAGS_SET(seg->tcphdr, flags); +    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */ + +    seg->flags = optflags; + +    /* Set the length of the header */ +    TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4)); +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", +      ntohl(seg->tcphdr->seqno), +      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), +      (u16_t)flags)); + +    left -= seglen; +    seqno += seglen; +    ptr = (void *)((u8_t *)ptr + seglen); +  } + +  /* Now that the data to be enqueued has been broken up into TCP +  segments in the queue variable, we add them to the end of the +  pcb->unsent queue. */ +  if (pcb->unsent == NULL) { +    useg = NULL; +  } +  else { +    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); +  } +  /* { useg is last segment on the unsent queue, NULL if list is empty } */ + +  /* If there is room in the last pbuf on the unsent queue, +  chain the first pbuf on the queue together with that. */ +  if (useg != NULL && +    TCP_TCPLEN(useg) != 0 && +    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && +    !(flags & (TCP_SYN | TCP_FIN)) && +    /* fit within max seg size */ +    (useg->len + queue->len <= pcb->mss) && +    /* only concatenate segments with the same options */ +    (useg->flags == queue->flags)) { +    /* Remove TCP header from first segment of our to-be-queued list */ +    if(pbuf_header(queue->p, -(TCP_HLEN + optlen))) { +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +      TCP_STATS_INC(tcp.err); +      goto memerr; +    } +    if (queue->p->len == 0) { +      /* free the first (header-only) pbuf if it is now empty (contained only headers) */ +      struct pbuf *old_q = queue->p; +      queue->p = queue->p->next; +      old_q->next = NULL; +      queuelen--; +      pbuf_free(old_q); +    } +    LWIP_ASSERT("zero-length pbuf", (queue->p != NULL) && (queue->p->len > 0)); +    pbuf_cat(useg->p, queue->p); +    useg->len += queue->len; +    useg->next = queue->next; + +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len)); +    if (seg == queue) { +      seg = useg; +      seglen = useg->len; +    } +    memp_free(MEMP_TCP_SEG, queue); +  } +  else { +    /* empty list */ +    if (useg == NULL) { +      /* initialize list with this segment */ +      pcb->unsent = queue; +    } +    /* enqueue segment */ +    else { +      useg->next = queue; +    } +  } +  if ((flags & TCP_SYN) || (flags & TCP_FIN)) { +    ++len; +  } +  if (flags & TCP_FIN) { +    pcb->flags |= TF_FIN; +  } +  pcb->snd_lbb += len; + +  pcb->snd_buf -= len; + +  /* update number of segments on the queues */ +  pcb->snd_queuelen = queuelen; +  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); +  if (pcb->snd_queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: valid queue length", +      pcb->unacked != NULL || pcb->unsent != NULL); +  } + +  /* Set the PSH flag in the last segment that we enqueued, but only +  if the segment has data (indicated by seglen > 0). */ +  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { +    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); +  } + +  return ERR_OK; +memerr: +  pcb->flags |= TF_NAGLEMEMERR; +  TCP_STATS_INC(tcp.memerr); + +  if (queue != NULL) { +    tcp_segs_free(queue); +  } +  if (pcb->snd_queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || +      pcb->unsent != NULL); +  } +  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); +  return ERR_MEM; +} + + +#if LWIP_TCP_TIMESTAMPS +/* Build a timestamp option (12 bytes long) at the specified options pointer) + * + * @param pcb tcp_pcb + * @param opts option pointer where to store the timestamp option + */ +static void +tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) +{ +  /* Pad with two NOP options to make everything nicely aligned */ +  opts[0] = htonl(0x0101080A); +  opts[1] = htonl(sys_now()); +  opts[2] = htonl(pcb->ts_recent); +} +#endif + + +/** + * Find out what we can send and send it + * + * @param pcb Protocol control block for the TCP connection to send data + * @return ERR_OK if data has been sent or nothing to send + *         another err_t on error + */ +err_t +tcp_output(struct tcp_pcb *pcb) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; +  struct tcp_seg *seg, *useg; +  u32_t wnd, snd_nxt; +#if TCP_CWND_DEBUG +  s16_t i = 0; +#endif /* TCP_CWND_DEBUG */ +  u8_t optlen = 0; + +  /* First, check if we are invoked by the TCP input processing +     code. If so, we do not output anything. Instead, we rely on the +     input processing code to call us when input processing is done +     with. */ +  if (tcp_input_pcb == pcb) { +    return ERR_OK; +  } + +  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); + +  seg = pcb->unsent; + +  /* useg should point to last segment on unacked queue */ +  useg = pcb->unacked; +  if (useg != NULL) { +    for (; useg->next != NULL; useg = useg->next); +  } + +  /* If the TF_ACK_NOW flag is set and no data will be sent (either +   * because the ->unsent queue is empty or because the window does +   * not allow it), construct an empty ACK segment and send it. +   * +   * If data is to be sent, we will just piggyback the ACK (see below). +   */ +  if (pcb->flags & TF_ACK_NOW && +     (seg == NULL || +      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { +#if LWIP_TCP_TIMESTAMPS +    if (pcb->flags & TF_TIMESTAMP) +      optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); +#endif +    p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM); +    if (p == NULL) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); +      return ERR_BUF; +    } +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG,  +                ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); +    /* remove ACK flags from the PCB, as we send an empty ACK now */ +    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + +    tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt)); + +    /* NB. MSS option is only sent on SYNs, so ignore it here */ +#if LWIP_TCP_TIMESTAMPS +    pcb->ts_lastacksent = pcb->rcv_nxt; + +    if (pcb->flags & TF_TIMESTAMP) +      tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); +#endif  + +#if CHECKSUM_GEN_TCP +    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), +          IP_PROTO_TCP, p->tot_len); +#endif +#if LWIP_NETIF_HWADDRHINT +    ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +        IP_PROTO_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +        IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ +    pbuf_free(p); + +    return ERR_OK; +  } + +#if TCP_OUTPUT_DEBUG +  if (seg == NULL) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", +                                   (void*)pcb->unsent)); +  } +#endif /* TCP_OUTPUT_DEBUG */ +#if TCP_CWND_DEBUG +  if (seg == NULL) { +    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F +                                 ", cwnd %"U16_F", wnd %"U32_F +                                 ", seg == NULL, ack %"U32_F"\n", +                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); +  } else { +    LWIP_DEBUGF(TCP_CWND_DEBUG,  +                ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F +                 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", +                 pcb->snd_wnd, pcb->cwnd, wnd, +                 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, +                 ntohl(seg->tcphdr->seqno), pcb->lastack)); +  } +#endif /* TCP_CWND_DEBUG */ +  /* data available and window allows it to be sent? */ +  while (seg != NULL && +         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { +    LWIP_ASSERT("RST not expected here!",  +                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); +    /* Stop sending if the nagle algorithm would prevent it +     * Don't stop: +     * - if tcp_enqueue had a memory error before (prevent delayed ACK timeout) or +     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - +     *   either seg->next != NULL or pcb->unacked == NULL; +     *   RST is no sent using tcp_enqueue/tcp_output. +     */ +    if((tcp_do_output_nagle(pcb) == 0) && +      ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){ +      break; +    } +#if TCP_CWND_DEBUG +    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", +                            pcb->snd_wnd, pcb->cwnd, wnd, +                            ntohl(seg->tcphdr->seqno) + seg->len - +                            pcb->lastack, +                            ntohl(seg->tcphdr->seqno), pcb->lastack, i)); +    ++i; +#endif /* TCP_CWND_DEBUG */ + +    pcb->unsent = seg->next; + +    if (pcb->state != SYN_SENT) { +      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); +      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); +    } + +    tcp_output_segment(seg, pcb); +    snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); +    if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { +      pcb->snd_nxt = snd_nxt; +    } +    /* put segment on unacknowledged list if length > 0 */ +    if (TCP_TCPLEN(seg) > 0) { +      seg->next = NULL; +      /* unacked list is empty? */ +      if (pcb->unacked == NULL) { +        pcb->unacked = seg; +        useg = seg; +      /* unacked list is not empty? */ +      } else { +        /* In the case of fast retransmit, the packet should not go to the tail +         * of the unacked queue, but rather somewhere before it. We need to check for +         * this case. -STJ Jul 27, 2004 */ +        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){ +          /* add segment to before tail of unacked list, keeping the list sorted */ +          struct tcp_seg **cur_seg = &(pcb->unacked); +          while (*cur_seg && +            TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { +              cur_seg = &((*cur_seg)->next ); +          } +          seg->next = (*cur_seg); +          (*cur_seg) = seg; +        } else { +          /* add segment to tail of unacked list */ +          useg->next = seg; +          useg = useg->next; +        } +      } +    /* do not queue empty segments on the unacked list */ +    } else { +      tcp_seg_free(seg); +    } +    seg = pcb->unsent; +  } + +  if (seg != NULL && pcb->persist_backoff == 0 &&  +      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { +    /* prepare for persist timer */ +    pcb->persist_cnt = 0; +    pcb->persist_backoff = 1; +  } + +  pcb->flags &= ~TF_NAGLEMEMERR; +  return ERR_OK; +} + +/** + * Called by tcp_output() to actually send a TCP segment over IP. + * + * @param seg the tcp_seg to send + * @param pcb the tcp_pcb for the TCP connection used to send the segment + */ +static void +tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) +{ +  u16_t len; +  struct netif *netif; +  u32_t *opts; + +  /** @bug Exclude retransmitted segments from this count. */ +  snmp_inc_tcpoutsegs(); + +  /* The TCP header has already been constructed, but the ackno and +   wnd fields remain. */ +  seg->tcphdr->ackno = htonl(pcb->rcv_nxt); + +  /* advertise our receive window size in this TCP segment */ +  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); + +  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + +  /* Add any requested options.  NB MSS option is only set on SYN +     packets, so ignore it here */ +  opts = (u32_t *)(seg->tcphdr + 1); +  if (seg->flags & TF_SEG_OPTS_MSS) { +    TCP_BUILD_MSS_OPTION(*opts); +    opts += 1; +  } +#if LWIP_TCP_TIMESTAMPS +  pcb->ts_lastacksent = pcb->rcv_nxt; + +  if (seg->flags & TF_SEG_OPTS_TS) { +    tcp_build_timestamp_option(pcb, opts); +    opts += 3; +  } +#endif + +  /* If we don't have a local IP address, we get one by +     calling ip_route(). */ +  if (ip_addr_isany(&(pcb->local_ip))) { +    netif = ip_route(&(pcb->remote_ip)); +    if (netif == NULL) { +      return; +    } +    ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); +  } + +  /* Set retransmission timer running if it is not currently enabled */ +  if(pcb->rtime == -1) +    pcb->rtime = 0; + +  if (pcb->rttest == 0) { +    pcb->rttest = tcp_ticks; +    pcb->rtseq = ntohl(seg->tcphdr->seqno); + +    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); +  } +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", +          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + +          seg->len)); + +  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); + +  seg->p->len -= len; +  seg->p->tot_len -= len; + +  seg->p->payload = seg->tcphdr; + +  seg->tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP +  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, +             &(pcb->local_ip), +             &(pcb->remote_ip), +             IP_PROTO_TCP, seg->p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); + +#if LWIP_NETIF_HWADDRHINT +  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +      IP_PROTO_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +      IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ +} + +/** + * Send a TCP RESET packet (empty segment with RST flag set) either to + * abort a connection or to show that there is no matching local connection + * for a received segment. + * + * Called by tcp_abort() (to abort a local connection), tcp_input() (if no + * matching local pcb was found), tcp_listen_input() (if incoming segment + * has ACK flag set) and tcp_process() (received segment in the wrong state) + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip the local IP address to send the segment from + * @param remote_ip the remote IP address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst(u32_t seqno, u32_t ackno, +  struct ip_addr *local_ip, struct ip_addr *remote_ip, +  u16_t local_port, u16_t remote_port) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; +  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); +  if (p == NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); +      return; +  } +  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", +              (p->len >= sizeof(struct tcp_hdr))); + +  tcphdr = p->payload; +  tcphdr->src = htons(local_port); +  tcphdr->dest = htons(remote_port); +  tcphdr->seqno = htonl(seqno); +  tcphdr->ackno = htonl(ackno); +  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK); +  tcphdr->wnd = htons(TCP_WND); +  tcphdr->urgp = 0; +  TCPH_HDRLEN_SET(tcphdr, 5); + +  tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP +  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, +              IP_PROTO_TCP, p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); +  snmp_inc_tcpoutrsts(); +   /* Send output with hardcoded TTL since we have no access to the pcb */ +  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); +  pbuf_free(p); +  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); +} + +/** + * Requeue all unacked segments for retransmission + * + * Called by tcp_slowtmr() for slow retransmission. + * + * @param pcb the tcp_pcb for which to re-enqueue all unacked segments + */ +void +tcp_rexmit_rto(struct tcp_pcb *pcb) +{ +  struct tcp_seg *seg; + +  if (pcb->unacked == NULL) { +    return; +  } + +  /* Move all unacked segments to the head of the unsent queue */ +  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); +  /* concatenate unsent queue after unacked queue */ +  seg->next = pcb->unsent; +  /* unsent queue is the concatenated queue (of unacked, unsent) */ +  pcb->unsent = pcb->unacked; +  /* unacked queue is now empty */ +  pcb->unacked = NULL; + +  /* increment number of retransmissions */ +  ++pcb->nrtx; + +  /* Don't take any RTT measurements after retransmitting. */ +  pcb->rttest = 0; + +  /* Do the actual retransmission */ +  tcp_output(pcb); +} + +/** + * Requeue the first unacked segment for retransmission + * + * Called by tcp_receive() for fast retramsmit. + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +void +tcp_rexmit(struct tcp_pcb *pcb) +{ +  struct tcp_seg *seg; +  struct tcp_seg **cur_seg; + +  if (pcb->unacked == NULL) { +    return; +  } + +  /* Move the first unacked segment to the unsent queue */ +  /* Keep the unsent queue sorted. */ +  seg = pcb->unacked; +  pcb->unacked = seg->next; + +  cur_seg = &(pcb->unsent); +  while (*cur_seg && +    TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { +      cur_seg = &((*cur_seg)->next ); +  } +  seg->next = *cur_seg; +  *cur_seg = seg; + +  ++pcb->nrtx; + +  /* Don't take any rtt measurements after retransmitting. */ +  pcb->rttest = 0; + +  /* Do the actual retransmission. */ +  snmp_inc_tcpretranssegs(); +  tcp_output(pcb); +} + +/** + * Send keepalive packets to keep a connection active although + * no data is sent over it. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a keepalive packet + */ +void +tcp_keepalive(struct tcp_pcb *pcb) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +                          ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +                          ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",  +                          tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); +    +  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); +    +  if(p == NULL) { +    LWIP_DEBUGF(TCP_DEBUG,  +                ("tcp_keepalive: could not allocate memory for pbuf\n")); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", +              (p->len >= sizeof(struct tcp_hdr))); + +  tcphdr = tcp_output_set_header(pcb, p, 0, htonl(pcb->snd_nxt - 1)); + +#if CHECKSUM_GEN_TCP +  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, +                                      IP_PROTO_TCP, p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); + +  /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT +  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, +    &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + +  pbuf_free(p); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", +                          pcb->snd_nxt - 1, pcb->rcv_nxt)); +} + + +/** + * Send persist timer zero-window probes to keep a connection active + * when a window update is lost. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a zero-window probe packet + */ +void +tcp_zero_window_probe(struct tcp_pcb *pcb) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; +  struct tcp_seg *seg; + +  LWIP_DEBUGF(TCP_DEBUG,  +              ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" +               U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +               ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +               ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + +  LWIP_DEBUGF(TCP_DEBUG,  +              ("tcp_zero_window_probe: tcp_ticks %"U32_F +               "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",  +               tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); + +  seg = pcb->unacked; + +  if(seg == NULL) +    seg = pcb->unsent; + +  if(seg == NULL) +    return; + +  p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM); +    +  if(p == NULL) { +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", +              (p->len >= sizeof(struct tcp_hdr))); + +  tcphdr = tcp_output_set_header(pcb, p, 0, seg->tcphdr->seqno); + +  /* Copy in one byte from the head of the unacked queue */ +  *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr; + +#if CHECKSUM_GEN_TCP +  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, +                                      IP_PROTO_TCP, p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); + +  /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT +  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, +    &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + +  pbuf_free(p); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F +                          " ackno %"U32_F".\n", +                          pcb->snd_nxt - 1, pcb->rcv_nxt)); +} +#endif /* LWIP_TCP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/dhcp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/dhcp.c new file mode 100644 index 000000000..df0f97881 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/dhcp.c @@ -0,0 +1,1633 @@ +/** + * @file + * Dynamic Host Configuration Protocol client + * + */ + +/* + * + * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net> + * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. + * + * Author: Leon Woestenberg <leon.woestenberg@gmx.net> + * + * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform + * with RFC 2131 and RFC 2132. + * + * TODO: + * - Proper parsing of DHCP messages exploiting file/sname field overloading. + * - Add JavaDoc style documentation (API, internals). + * - Support for interfaces other than Ethernet (SLIP, PPP, ...) + * + * Please coordinate changes and requests with Leon Woestenberg + * <leon.woestenberg@gmx.net> + * + * Integration with your code: + * + * In lwip/dhcp.h + * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) + * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) + * + * Then have your application call dhcp_coarse_tmr() and + * dhcp_fine_tmr() on the defined intervals. + * + * dhcp_start(struct netif *netif); + * starts a DHCP client instance which configures the interface by + * obtaining an IP address lease and maintaining it. + * + * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) + * to remove the DHCP client. + * + */ + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "lwip/sys.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/dns.h" +#include "netif/etharp.h" + +#include <string.h> + +/** Default for DHCP_GLOBAL_XID is 0xABCD0000 + * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. + *  #define DHCP_GLOBAL_XID_HEADER "stdlib.h" + *  #define DHCP_GLOBAL_XID rand() + */ +#ifdef DHCP_GLOBAL_XID_HEADER +#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ +#endif + +/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU + * MTU is checked to be big enough in dhcp_start */ +#define DHCP_MAX_MSG_LEN(netif)        (netif->mtu) +#define DHCP_MAX_MSG_LEN_MIN_REQUIRED  576 + +/* DHCP client state machine functions */ +static void dhcp_handle_ack(struct netif *netif); +static void dhcp_handle_nak(struct netif *netif); +static void dhcp_handle_offer(struct netif *netif); + +static err_t dhcp_discover(struct netif *netif); +static err_t dhcp_select(struct netif *netif); +static void dhcp_check(struct netif *netif); +static void dhcp_bind(struct netif *netif); +#if DHCP_DOES_ARP_CHECK +static err_t dhcp_decline(struct netif *netif); +#endif /* DHCP_DOES_ARP_CHECK */ +static err_t dhcp_rebind(struct netif *netif); +static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); + +/* receive, unfold, parse and free incoming messages */ +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); +static err_t dhcp_unfold_reply(struct dhcp *dhcp); +static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type); +static u8_t dhcp_get_option_byte(u8_t *ptr); +#if 0 +static u16_t dhcp_get_option_short(u8_t *ptr); +#endif +static u32_t dhcp_get_option_long(u8_t *ptr); +static void dhcp_free_reply(struct dhcp *dhcp); + +/* set the DHCP timers */ +static void dhcp_timeout(struct netif *netif); +static void dhcp_t1_timeout(struct netif *netif); +static void dhcp_t2_timeout(struct netif *netif); + +/* build outgoing messages */ +/* create a DHCP request, fill in common headers */ +static err_t dhcp_create_request(struct netif *netif); +/* free a DHCP request */ +static void dhcp_delete_request(struct netif *netif); +/* add a DHCP option (type, then length in bytes) */ +static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); +/* add option values */ +static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); +static void dhcp_option_short(struct dhcp *dhcp, u16_t value); +static void dhcp_option_long(struct dhcp *dhcp, u32_t value); +/* always add the DHCP options trailer to end and pad */ +static void dhcp_option_trailer(struct dhcp *dhcp); + +/** + * Back-off the DHCP client (because of a received NAK response). + * + * Back-off the DHCP client because of a received NAK. Receiving a + * NAK means the client asked for something non-sensible, for + * example when it tries to renew a lease obtained on another network. + * + * We clear any existing set IP address and restart DHCP negotiation + * afresh (as per RFC2131 3.2.3). + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_nak(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",  +    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); +  /* Set the interface down since the address must no longer be used, as per RFC2131 */ +  netif_set_down(netif); +  /* remove IP address from interface */ +  netif_set_ipaddr(netif, IP_ADDR_ANY); +  netif_set_gw(netif, IP_ADDR_ANY); +  netif_set_netmask(netif, IP_ADDR_ANY);  +  /* Change to a defined state */ +  dhcp_set_state(dhcp, DHCP_BACKING_OFF); +  /* We can immediately restart discovery */ +  dhcp_discover(netif); +} + +/** + * Checks if the offered IP address is already in use. + * + * It does so by sending an ARP request for the offered address and + * entering CHECKING state. If no ARP reply is received within a small + * interval, the address is assumed to be free for use by us. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_check(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  err_t result; +  u16_t msecs; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], +    (s16_t)netif->name[1])); +  dhcp_set_state(dhcp, DHCP_CHECKING); +  /* create an ARP query for the offered IP address, expecting that no host +     responds, as the IP address should not be in use. */ +  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); +  if (result != ERR_OK) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n")); +  } +  dhcp->tries++; +  msecs = 500; +  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); +} + +/** + * Remember the configuration offered by a DHCP server. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_offer(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  /* obtain the server address */ +  u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", +    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); +  if (option_ptr != NULL) { +    dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr)); +    /* remember offered address */ +    ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); + +    dhcp_select(netif); +  } +} + +/** + * Select a DHCP server offer out of all offers. + * + * Simply select the first offer received. + * + * @param netif the netif under DHCP control + * @return lwIP specific error (see error.h) + */ +static err_t +dhcp_select(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  err_t result; +  u16_t msecs; +#if LWIP_NETIF_HOSTNAME +  const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); +  dhcp_set_state(dhcp, DHCP_REQUESTING); + +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_REQUEST); + +    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); +    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +    /* MUST request the offered IP address */ +    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + +    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); + +    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); +    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); +    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); +    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); +    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); + +#if LWIP_NETIF_HOSTNAME +    p = (const char*)netif->hostname; +    if (p != NULL) { +      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); +      while (*p) { +        dhcp_option_byte(dhcp, *p++); +      } +    } +#endif /* LWIP_NETIF_HOSTNAME */ + +    dhcp_option_trailer(dhcp); +    /* shrink the pbuf to the actual content length */ +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +    /* TODO: we really should bind to a specific local interface here +       but we cannot specify an unconfigured netif as it is addressless */ +    /* send broadcast to any DHCP server */ +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    /* reconnect to any (or to server here?!) */ +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n")); +  } +  dhcp->tries++; +  msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; +  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); +  return result; +} + +/** + * The DHCP timer that checks for lease renewal/rebind timeouts. + * + */ +void +dhcp_coarse_tmr() +{ +  struct netif *netif = netif_list; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); +  /* iterate through all network interfaces */ +  while (netif != NULL) { +    /* only act on DHCP configured interfaces */ +    if (netif->dhcp != NULL) { +      /* timer is active (non zero), and triggers (zeroes) now? */ +      if (netif->dhcp->t2_timeout-- == 1) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); +        /* this clients' rebind timeout triggered */ +        dhcp_t2_timeout(netif); +      /* timer is active (non zero), and triggers (zeroes) now */ +      } else if (netif->dhcp->t1_timeout-- == 1) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); +        /* this clients' renewal timeout triggered */ +        dhcp_t1_timeout(netif); +      } +    } +    /* proceed to next netif */ +    netif = netif->next; +  } +} + +/** + * DHCP transaction timeout handling + * + * A DHCP server is expected to respond within a short period of time. + * This timer checks whether an outstanding DHCP request is timed out. + *  + */ +void +dhcp_fine_tmr() +{ +  struct netif *netif = netif_list; +  /* loop through netif's */ +  while (netif != NULL) { +    /* only act on DHCP configured interfaces */ +    if (netif->dhcp != NULL) { +      /* timer is active (non zero), and is about to trigger now */       +      if (netif->dhcp->request_timeout > 1) { +        netif->dhcp->request_timeout--; +      } +      else if (netif->dhcp->request_timeout == 1) { +        netif->dhcp->request_timeout--; +        /* { netif->dhcp->request_timeout == 0 } */ +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); +        /* this clients' request timeout triggered */ +        dhcp_timeout(netif); +      } +    } +    /* proceed to next network interface */ +    netif = netif->next; +  } +} + +/** + * A DHCP negotiation transaction, or ARP request, has timed out. + * + * The timer that was started with the DHCP or ARP request has + * timed out, indicating no response was received in time. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_timeout(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_timeout()\n")); +  /* back-off period has passed, or server selection timed out */ +  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); +    dhcp_discover(netif); +  /* receiving the requested lease timed out */ +  } else if (dhcp->state == DHCP_REQUESTING) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); +    if (dhcp->tries <= 5) { +      dhcp_select(netif); +    } else { +      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); +      dhcp_release(netif); +      dhcp_discover(netif); +    } +  /* received no ARP reply for the offered address (which is good) */ +  } else if (dhcp->state == DHCP_CHECKING) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); +    if (dhcp->tries <= 1) { +      dhcp_check(netif); +    /* no ARP replies on the offered address, +       looks like the IP address is indeed free */ +    } else { +      /* bind the interface to the offered address */ +      dhcp_bind(netif); +    } +  } +  /* did not get response to renew request? */ +  else if (dhcp->state == DHCP_RENEWING) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n")); +    /* just retry renewal */ +    /* note that the rebind timer will eventually time-out if renew does not work */ +    dhcp_renew(netif); +  /* did not get response to rebind request? */ +  } else if (dhcp->state == DHCP_REBINDING) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n")); +    if (dhcp->tries <= 8) { +      dhcp_rebind(netif); +    } else { +      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n")); +      dhcp_release(netif); +      dhcp_discover(netif); +    } +  } +} + +/** + * The renewal period has timed out. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_t1_timeout(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); +  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { +    /* just retry to renew - note that the rebind timer (t2) will +     * eventually time-out if renew tries fail. */ +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n")); +    dhcp_renew(netif); +  } +} + +/** + * The rebind period has timed out. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_t2_timeout(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); +  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { +    /* just retry to rebind */ +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n")); +    dhcp_rebind(netif); +  } +} + +/** + * Handle a DHCP ACK packet + * + * @param netif the netif under DHCP control + */ +static void +dhcp_handle_ack(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  u8_t *option_ptr; +  /* clear options we might not get from the ACK */ +  dhcp->offered_sn_mask.addr = 0; +  dhcp->offered_gw_addr.addr = 0; +  dhcp->offered_bc_addr.addr = 0; + +  /* lease time given? */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME); +  if (option_ptr != NULL) { +    /* remember offered lease time */ +    dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2); +  } +  /* renewal period given? */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1); +  if (option_ptr != NULL) { +    /* remember given renewal period */ +    dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2); +  } else { +    /* calculate safe periods for renewal */ +    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; +  } + +  /* renewal period given? */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2); +  if (option_ptr != NULL) { +    /* remember given rebind period */ +    dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2); +  } else { +    /* calculate safe periods for rebinding */ +    dhcp->offered_t2_rebind = dhcp->offered_t0_lease; +  } + +  /* (y)our internet address */ +  ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr); + +/** + * Patch #1308 + * TODO: we must check if the file field is not overloaded by DHCP options! + */ +#if 0 +  /* boot server address */ +  ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr); +  /* boot file name */ +  if (dhcp->msg_in->file[0]) { +    dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1); +    strcpy(dhcp->boot_file_name, dhcp->msg_in->file); +  } +#endif + +  /* subnet mask */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK); +  /* subnet mask given? */ +  if (option_ptr != NULL) { +    dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +  } + +  /* gateway router */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER); +  if (option_ptr != NULL) { +    dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +  } + +  /* broadcast address */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST); +  if (option_ptr != NULL) { +    dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +  } +   +  /* DNS servers */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER); +  if (option_ptr != NULL) { +    u8_t n; +    dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr); +    /* limit to at most DHCP_MAX_DNS DNS servers */ +    if (dhcp->dns_count > DHCP_MAX_DNS) +      dhcp->dns_count = DHCP_MAX_DNS; +    for (n = 0; n < dhcp->dns_count; n++) { +      dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4])); +#if LWIP_DNS +      dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr))); +#endif /* LWIP_DNS */ +    } +#if LWIP_DNS +    dns_setserver( n, (struct ip_addr *)(&ip_addr_any)); +#endif /* LWIP_DNS */ +  } +} + +/** + * Start DHCP negotiation for a network interface. + * + * If no DHCP client instance was attached to this interface, + * a new client is created first. If a DHCP client instance + * was already present, it restarts negotiation. + * + * @param netif The lwIP network interface + * @return lwIP error code + * - ERR_OK - No error + * - ERR_MEM - Out of memory + */ +err_t +dhcp_start(struct netif *netif) +{ +  struct dhcp *dhcp; +  err_t result = ERR_OK; + +  LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); +  dhcp = netif->dhcp; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); +  /* Remove the flag that says this netif is handled by DHCP, +     it is set when we succeeded starting. */ +  netif->flags &= ~NETIF_FLAG_DHCP; + +  /* check MTU of the netif */ +  if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); +    return ERR_MEM; +  } + +  /* no DHCP client attached yet? */ +  if (dhcp == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); +    dhcp = mem_malloc(sizeof(struct dhcp)); +    if (dhcp == NULL) { +      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); +      return ERR_MEM; +    } +    /* store this dhcp client in the netif */ +    netif->dhcp = dhcp; +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); +  /* already has DHCP client attached */ +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n")); +    if (dhcp->pcb != NULL) { +      udp_remove(dhcp->pcb); +    } +    if (dhcp->p != NULL) { +      pbuf_free(dhcp->p); +    } +  } +     +  /* clear data structure */ +  memset(dhcp, 0, sizeof(struct dhcp)); +  /* allocate UDP PCB */ +  dhcp->pcb = udp_new(); +  if (dhcp->pcb == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n")); +    mem_free((void *)dhcp); +    netif->dhcp = dhcp = NULL; +    return ERR_MEM; +  } +#if IP_SOF_BROADCAST +  dhcp->pcb->so_options|=SOF_BROADCAST; +#endif /* IP_SOF_BROADCAST */ +  /* set up local and remote port for the pcb */ +  udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); +  udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +  /* set up the recv callback and argument */ +  udp_recv(dhcp->pcb, dhcp_recv, netif); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); +  /* (re)start the DHCP negotiation */ +  result = dhcp_discover(netif); +  if (result != ERR_OK) { +    /* free resources allocated above */ +    dhcp_stop(netif); +    return ERR_MEM; +  } +  /* Set the flag that says this netif is handled by DHCP. */ +  netif->flags |= NETIF_FLAG_DHCP; +  return result; +} + +/** + * Inform a DHCP server of our manual configuration. + * + * This informs DHCP servers of our fixed IP address configuration + * by sending an INFORM message. It does not involve DHCP address + * configuration, it is just here to be nice to the network. + * + * @param netif The lwIP network interface + */ +void +dhcp_inform(struct netif *netif) +{ +  struct dhcp *dhcp, *old_dhcp = netif->dhcp; +  err_t result = ERR_OK; +  dhcp = mem_malloc(sizeof(struct dhcp)); +  if (dhcp == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n")); +    return; +  } +  netif->dhcp = dhcp; +  memset(dhcp, 0, sizeof(struct dhcp)); + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n")); +  dhcp->pcb = udp_new(); +  if (dhcp->pcb == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb")); +    mem_free((void *)dhcp); +    return; +  } +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { + +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_INFORM); + +    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); +    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +    dhcp_option_trailer(dhcp); + +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +#if IP_SOF_BROADCAST +    dhcp->pcb->so_options|=SOF_BROADCAST; +#endif /* IP_SOF_BROADCAST */ +    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); +    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    dhcp_delete_request(netif); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n")); +  } + +  if (dhcp->pcb != NULL) { +    udp_remove(dhcp->pcb); +  } +  dhcp->pcb = NULL; +  mem_free((void *)dhcp); +  netif->dhcp = old_dhcp; +} + +#if DHCP_DOES_ARP_CHECK +/** + * Match an ARP reply with the offered IP address. + * + * @param netif the network interface on which the reply was received + * @param addr The IP address we received a reply from + */ +void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr) +{ +  LWIP_ERROR("netif != NULL", (netif != NULL), return;); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_arp_reply()\n")); +  /* is a DHCP client doing an ARP check? */ +  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr)); +    /* did a host respond with the address we +       were offered by the DHCP server? */ +    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) { +      /* we will not accept the offered address */ +      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); +      dhcp_decline(netif); +    } +  } +} + +/** + * Decline an offered lease. + * + * Tell the DHCP server we do not accept the offered address. + * One reason to decline the lease is when we find out the address + * is already in use by another host (through ARP). + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_decline(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  err_t result = ERR_OK; +  u16_t msecs; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_decline()\n")); +  dhcp_set_state(dhcp, DHCP_BACKING_OFF); +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_DECLINE); + +    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + +    dhcp_option_trailer(dhcp); +    /* resize pbuf to reflect true size of options */ +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +    /* @todo: should we really connect here? we are performing sendto() */ +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    /* per section 4.4.4, broadcast DECLINE messages */ +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n")); +  } +  dhcp->tries++; +  msecs = 10*1000; +  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); +  return result; +} +#endif + + +/** + * Start the DHCP process, discover a DHCP server. + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_discover(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  err_t result = ERR_OK; +  u16_t msecs; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n")); +  ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY); +  dhcp_set_state(dhcp, DHCP_SELECTING); +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_DISCOVER); + +    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); +    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); +    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); +    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); +    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); +    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); + +    dhcp_option_trailer(dhcp); + +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n")); +  } +  dhcp->tries++; +#if LWIP_DHCP_AUTOIP_COOP +  if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { +    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; +    autoip_start(netif); +  } +#endif /* LWIP_DHCP_AUTOIP_COOP */ +  msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; +  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); +  return result; +} + + +/** + * Bind the interface to the offered IP address. + * + * @param netif network interface to bind to the offered address + */ +static void +dhcp_bind(struct netif *netif) +{ +  u32_t timeout; +  struct dhcp *dhcp; +  struct ip_addr sn_mask, gw_addr; +  LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); +  dhcp = netif->dhcp; +  LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); + +  /* temporary DHCP lease? */ +  if (dhcp->offered_t1_renew != 0xffffffffUL) { +    /* set renewal period timer */ +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); +    timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; +    if(timeout > 0xffff) { +      timeout = 0xffff; +    } +    dhcp->t1_timeout = (u16_t)timeout; +    if (dhcp->t1_timeout == 0) { +      dhcp->t1_timeout = 1; +    } +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); +  } +  /* set renewal period timer */ +  if (dhcp->offered_t2_rebind != 0xffffffffUL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); +    timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; +    if(timeout > 0xffff) { +      timeout = 0xffff; +    } +    dhcp->t2_timeout = (u16_t)timeout; +    if (dhcp->t2_timeout == 0) { +      dhcp->t2_timeout = 1; +    } +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); +  } +  /* copy offered network mask */ +  ip_addr_set(&sn_mask, &dhcp->offered_sn_mask); + +  /* subnet mask not given? */ +  /* TODO: this is not a valid check. what if the network mask is 0? */ +  if (sn_mask.addr == 0) { +    /* choose a safe subnet mask given the network class */ +    u8_t first_octet = ip4_addr1(&sn_mask); +    if (first_octet <= 127) { +      sn_mask.addr = htonl(0xff000000); +    } else if (first_octet >= 192) { +      sn_mask.addr = htonl(0xffffff00); +    } else { +      sn_mask.addr = htonl(0xffff0000); +    } +  } + +  ip_addr_set(&gw_addr, &dhcp->offered_gw_addr); +  /* gateway address not given? */ +  if (gw_addr.addr == 0) { +    /* copy network address */ +    gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr); +    /* use first host address on network as gateway */ +    gw_addr.addr |= htonl(0x00000001); +  } + +#if LWIP_DHCP_AUTOIP_COOP +  if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { +    autoip_stop(netif); +    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; +  } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); +  netif_set_ipaddr(netif, &dhcp->offered_ip_addr); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr)); +  netif_set_netmask(netif, &sn_mask); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr)); +  netif_set_gw(netif, &gw_addr); +  /* bring the interface up */ +  netif_set_up(netif); +  /* netif is now bound to DHCP leased address */ +  dhcp_set_state(dhcp, DHCP_BOUND); +} + +/** + * Renew an existing DHCP lease at the involved DHCP server. + * + * @param netif network interface which must renew its lease + */ +err_t +dhcp_renew(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  err_t result; +  u16_t msecs; +#if LWIP_NETIF_HOSTNAME +  const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n")); +  dhcp_set_state(dhcp, DHCP_RENEWING); + +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { + +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_REQUEST); + +    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); +    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +#if LWIP_NETIF_HOSTNAME +    p = (const char*)netif->hostname; +    if (p != NULL) { +      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); +      while (*p) { +        dhcp_option_byte(dhcp, *p++); +      } +    } +#endif /* LWIP_NETIF_HOSTNAME */ + +#if 0 +    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); +#endif + +#if 0 +    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); +#endif +    /* append DHCP message trailer */ +    dhcp_option_trailer(dhcp); + +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); +    dhcp_delete_request(netif); + +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n")); +  } +  dhcp->tries++; +  /* back-off on retries, but to a maximum of 20 seconds */ +  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; +  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); +  return result; +} + +/** + * Rebind with a DHCP server for an existing DHCP lease. + * + * @param netif network interface which must rebind with a DHCP server + */ +static err_t +dhcp_rebind(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  err_t result; +  u16_t msecs; +#if LWIP_NETIF_HOSTNAME +  const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); +  dhcp_set_state(dhcp, DHCP_REBINDING); + +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { + +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_REQUEST); + +    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); +    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); + +#if LWIP_NETIF_HOSTNAME +    p = (const char*)netif->hostname; +    if (p != NULL) { +      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); +      while (*p) { +        dhcp_option_byte(dhcp, *p++); +      } +    } +#endif /* LWIP_NETIF_HOSTNAME */ + +#if 0 +    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + +    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); +#endif + +    dhcp_option_trailer(dhcp); + +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +    /* broadcast to server */ +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n")); +  } +  dhcp->tries++; +  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; +  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); +  return result; +} + +/** + * Release a DHCP lease. + * + * @param netif network interface which must release its lease + */ +err_t +dhcp_release(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  err_t result; +  u16_t msecs; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_release()\n")); + +  /* idle DHCP client */ +  dhcp_set_state(dhcp, DHCP_OFF); +  /* clean old DHCP offer */ +  dhcp->server_ip_addr.addr = 0; +  dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0; +  dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0; +  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; +  dhcp->dns_count = 0; +   +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_RELEASE); + +    dhcp_option_trailer(dhcp); + +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n")); +  } +  dhcp->tries++; +  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; +  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs)); +  /* bring the interface down */ +  netif_set_down(netif); +  /* remove IP address from interface */ +  netif_set_ipaddr(netif, IP_ADDR_ANY); +  netif_set_gw(netif, IP_ADDR_ANY); +  netif_set_netmask(netif, IP_ADDR_ANY); +   +  /* TODO: netif_down(netif); */ +  return result; +} + +/** + * Remove the DHCP client from the interface. + * + * @param netif The network interface to stop DHCP on + */ +void +dhcp_stop(struct netif *netif) +{ +  struct dhcp *dhcp = netif->dhcp; +  LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); +  /* Remove the flag that says this netif is handled by DHCP. */ +  netif->flags &= ~NETIF_FLAG_DHCP; + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n")); +  /* netif is DHCP configured? */ +  if (dhcp != NULL) { +#if LWIP_DHCP_AUTOIP_COOP +  if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { +    autoip_stop(netif); +    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; +  } +#endif /* LWIP_DHCP_AUTOIP_COOP */ + +    if (dhcp->pcb != NULL) { +      udp_remove(dhcp->pcb); +      dhcp->pcb = NULL; +    } +    if (dhcp->p != NULL) { +      pbuf_free(dhcp->p); +      dhcp->p = NULL; +    } +    /* free unfolded reply */ +    dhcp_free_reply(dhcp); +    mem_free((void *)dhcp); +    netif->dhcp = NULL; +  } +} + +/* + * Set the DHCP state of a DHCP client. + * + * If the state changed, reset the number of tries. + * + * TODO: we might also want to reset the timeout here? + */ +static void +dhcp_set_state(struct dhcp *dhcp, u8_t new_state) +{ +  if (new_state != dhcp->state) { +    dhcp->state = new_state; +    dhcp->tries = 0; +  } +} + +/* + * Concatenate an option type and length field to the outgoing + * DHCP message. + * + */ +static void +dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) +{ +  LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); +  dhcp->msg_out->options[dhcp->options_out_len++] = option_type; +  dhcp->msg_out->options[dhcp->options_out_len++] = option_len; +} +/* + * Concatenate a single byte to the outgoing DHCP message. + * + */ +static void +dhcp_option_byte(struct dhcp *dhcp, u8_t value) +{ +  LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); +  dhcp->msg_out->options[dhcp->options_out_len++] = value; +} + +static void +dhcp_option_short(struct dhcp *dhcp, u16_t value) +{ +  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); +  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); +  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); +} + +static void +dhcp_option_long(struct dhcp *dhcp, u32_t value) +{ +  LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); +  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); +  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); +  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); +  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); +} + +/** + * Extract the DHCP message and the DHCP options. + * + * Extract the DHCP message and the DHCP options, each into a contiguous + * piece of memory. As a DHCP message is variable sized by its options, + * and also allows overriding some fields for options, the easy approach + * is to first unfold the options into a conitguous piece of memory, and + * use that further on. + * + */ +static err_t +dhcp_unfold_reply(struct dhcp *dhcp) +{ +  u16_t ret; +  LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;); +  LWIP_ERROR("dhcp->p != NULL", (dhcp->p != NULL), return ERR_VAL;); +  /* free any left-overs from previous unfolds */ +  dhcp_free_reply(dhcp); +  /* options present? */ +  if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) { +    dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +    dhcp->options_in = mem_malloc(dhcp->options_in_len); +    if (dhcp->options_in == NULL) { +      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n")); +      return ERR_MEM; +    } +  } +  dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +  if (dhcp->msg_in == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n")); +    mem_free((void *)dhcp->options_in); +    dhcp->options_in = NULL; +    return ERR_MEM; +  } + +  /** copy the DHCP message without options */ +  ret = pbuf_copy_partial(dhcp->p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0); +  LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", +     sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)); + +  if (dhcp->options_in != NULL) { +    /** copy the DHCP options */ +    ret = pbuf_copy_partial(dhcp->p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +    LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", +      dhcp->options_in_len)); +  } +  LWIP_UNUSED_ARG(ret); +  return ERR_OK; +} + +/** + * Free the incoming DHCP message including contiguous copy of + * its DHCP options. + * + */ +static void dhcp_free_reply(struct dhcp *dhcp) +{ +  if (dhcp->msg_in != NULL) { +    mem_free((void *)dhcp->msg_in); +    dhcp->msg_in = NULL; +  } +  if (dhcp->options_in) { +    mem_free((void *)dhcp->options_in); +    dhcp->options_in = NULL; +    dhcp->options_in_len = 0; +  } +  LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n")); +} + + +/** + * If an incoming DHCP message is in response to us, then trigger the state machine + */ +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +{ +  struct netif *netif = (struct netif *)arg; +  struct dhcp *dhcp = netif->dhcp; +  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; +  u8_t *options_ptr; +  u8_t msg_type; +  u8_t i; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, +    (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff), +    (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port)); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); +  /* prevent warnings about unused arguments */ +  LWIP_UNUSED_ARG(pcb); +  LWIP_UNUSED_ARG(addr); +  LWIP_UNUSED_ARG(port); +  dhcp->p = p; +  /* TODO: check packet length before reading them */ +  if (reply_msg->op != DHCP_BOOTREPLY) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); +    goto free_pbuf_and_return; +  } +  /* iterate through hardware address and match against DHCP message */ +  for (i = 0; i < netif->hwaddr_len; i++) { +    if (netif->hwaddr[i] != reply_msg->chaddr[i]) { +      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", +        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); +      goto free_pbuf_and_return; +    } +  } +  /* match transaction ID against what we expected */ +  if (ntohl(reply_msg->xid) != dhcp->xid) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid)); +    goto free_pbuf_and_return; +  } +  /* option fields could be unfold? */ +  if (dhcp_unfold_reply(dhcp) != ERR_OK) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n")); +    goto free_pbuf_and_return; +  } + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); +  /* obtain pointer to DHCP message type */ +  options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE); +  if (options_ptr == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); +    goto free_pbuf_and_return; +  } + +  /* read DHCP message type */ +  msg_type = dhcp_get_option_byte(options_ptr + 2); +  /* message type is DHCP ACK? */ +  if (msg_type == DHCP_ACK) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n")); +    /* in requesting state? */ +    if (dhcp->state == DHCP_REQUESTING) { +      dhcp_handle_ack(netif); +      dhcp->request_timeout = 0; +#if DHCP_DOES_ARP_CHECK +      /* check if the acknowledged lease address is already in use */ +      dhcp_check(netif); +#else +      /* bind interface to the acknowledged lease address */ +      dhcp_bind(netif); +#endif +    } +    /* already bound to the given lease address? */ +    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { +      dhcp->request_timeout = 0; +      dhcp_bind(netif); +    } +  } +  /* received a DHCP_NAK in appropriate state? */ +  else if ((msg_type == DHCP_NAK) && +    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || +     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_NAK received\n")); +    dhcp->request_timeout = 0; +    dhcp_handle_nak(netif); +  } +  /* received a DHCP_OFFER in DHCP_SELECTING state? */ +  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n")); +    dhcp->request_timeout = 0; +    /* remember offered lease */ +    dhcp_handle_offer(netif); +  } +free_pbuf_and_return: +  dhcp_free_reply(dhcp); +  pbuf_free(p); +  dhcp->p = NULL; +} + +/** + * Create a DHCP request, fill in common headers + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_create_request(struct netif *netif) +{ +  struct dhcp *dhcp; +  u16_t i; +#ifndef DHCP_GLOBAL_XID +  /** default global transaction identifier starting value (easy to match +   *  with a packet analyser). We simply increment for each new request. +   *  Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one +   *  at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ +  static u32_t xid = 0xABCD0000; +#else +  static u32_t xid; +  static u8_t xid_initialised = 0; +  if (!xid_initialised) { +    xid = DHCP_GLOBAL_XID; +    xid_initialised = !xid_initialised; +  } +#endif +  LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;); +  dhcp = netif->dhcp; +  LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); +  LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL); +  LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL); +  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); +  if (dhcp->p_out == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n")); +    return ERR_MEM; +  } +  LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg", +           (dhcp->p_out->len >= sizeof(struct dhcp_msg))); + +  /* reuse transaction identifier in retransmissions */ +  if (dhcp->tries==0) +      xid++; +  dhcp->xid = xid; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, +              ("transaction id xid(%"X32_F")\n", xid)); + +  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; + +  dhcp->msg_out->op = DHCP_BOOTREQUEST; +  /* TODO: make link layer independent */ +  dhcp->msg_out->htype = DHCP_HTYPE_ETH; +  /* TODO: make link layer independent */ +  dhcp->msg_out->hlen = DHCP_HLEN_ETH; +  dhcp->msg_out->hops = 0; +  dhcp->msg_out->xid = htonl(dhcp->xid); +  dhcp->msg_out->secs = 0; +  dhcp->msg_out->flags = 0; +  dhcp->msg_out->ciaddr.addr = 0; +  if (dhcp->state==DHCP_BOUND || dhcp->state==DHCP_RENEWING || dhcp->state==DHCP_REBINDING) { +    dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr; +  } +  dhcp->msg_out->yiaddr.addr = 0; +  dhcp->msg_out->siaddr.addr = 0; +  dhcp->msg_out->giaddr.addr = 0; +  for (i = 0; i < DHCP_CHADDR_LEN; i++) { +    /* copy netif hardware address, pad with zeroes */ +    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/; +  } +  for (i = 0; i < DHCP_SNAME_LEN; i++) { +    dhcp->msg_out->sname[i] = 0; +  } +  for (i = 0; i < DHCP_FILE_LEN; i++) { +    dhcp->msg_out->file[i] = 0; +  } +  dhcp->msg_out->cookie = htonl(0x63825363UL); +  dhcp->options_out_len = 0; +  /* fill options field with an incrementing array (for debugging purposes) */ +  for (i = 0; i < DHCP_OPTIONS_LEN; i++) { +    dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ +  } +  return ERR_OK; +} + +/** + * Free previously allocated memory used to send a DHCP request. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_delete_request(struct netif *netif) +{ +  struct dhcp *dhcp; +  LWIP_ERROR("dhcp_delete_request: netif != NULL", (netif != NULL), return;); +  dhcp = netif->dhcp; +  LWIP_ERROR("dhcp_delete_request: dhcp != NULL", (dhcp != NULL), return;); +  LWIP_ASSERT("dhcp_delete_request: dhcp->p_out != NULL", dhcp->p_out != NULL); +  LWIP_ASSERT("dhcp_delete_request: dhcp->msg_out != NULL", dhcp->msg_out != NULL); +  if (dhcp->p_out != NULL) { +    pbuf_free(dhcp->p_out); +  } +  dhcp->p_out = NULL; +  dhcp->msg_out = NULL; +} + +/** + * Add a DHCP message trailer + * + * Adds the END option to the DHCP message, and if + * necessary, up to three padding bytes. + * + * @param dhcp DHCP state structure + */ +static void +dhcp_option_trailer(struct dhcp *dhcp) +{ +  LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;); +  LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); +  LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); +  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; +  /* packet is too small, or not 4 byte aligned? */ +  while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) { +    /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */ +    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); +    /* add a fill/padding byte */ +    dhcp->msg_out->options[dhcp->options_out_len++] = 0; +  } +} + +/** + * Find the offset of a DHCP option inside the DHCP message. + * + * @param dhcp DHCP client + * @param option_type + * + * @return a byte offset into the UDP message where the option was found, or + * zero if the given option was not found. + */ +static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type) +{ +  u8_t overload = DHCP_OVERLOAD_NONE; + +  /* options available? */ +  if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) { +    /* start with options field */ +    u8_t *options = (u8_t *)dhcp->options_in; +    u16_t offset = 0; +    /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ +    while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) { +      /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ +      /* are the sname and/or file field overloaded with options? */ +      if (options[offset] == DHCP_OPTION_OVERLOAD) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("overloaded message detected\n")); +        /* skip option type and length */ +        offset += 2; +        overload = options[offset++]; +      } +      /* requested option found */ +      else if (options[offset] == option_type) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset)); +        return &options[offset]; +      /* skip option */ +      } else { +         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset])); +        /* skip option type */ +        offset++; +        /* skip option length, and then length bytes */ +        offset += 1 + options[offset]; +      } +    } +    /* is this an overloaded message? */ +    if (overload != DHCP_OVERLOAD_NONE) { +      u16_t field_len; +      if (overload == DHCP_OVERLOAD_FILE) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n")); +        options = (u8_t *)&dhcp->msg_in->file; +        field_len = DHCP_FILE_LEN; +      } else if (overload == DHCP_OVERLOAD_SNAME) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname field\n")); +        options = (u8_t *)&dhcp->msg_in->sname; +        field_len = DHCP_SNAME_LEN; +      /* TODO: check if else if () is necessary */ +      } else { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n")); +        options = (u8_t *)&dhcp->msg_in->sname; +        field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN; +      } +      offset = 0; + +      /* at least 1 byte to read and no end marker */ +      while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) { +        if (options[offset] == option_type) { +           LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset=%"U16_F"\n", offset)); +          return &options[offset]; +        /* skip option */ +        } else { +          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("skipping option %"U16_F"\n", options[offset])); +          /* skip option type */ +          offset++; +          offset += 1 + options[offset]; +        } +      } +    } +  } +  return NULL; +} + +/** + * Return the byte of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u8_t +dhcp_get_option_byte(u8_t *ptr) +{ +  LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr))); +  return *ptr; +} + +#if 0 /* currently unused */ +/** + * Return the 16-bit value of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u16_t +dhcp_get_option_short(u8_t *ptr) +{ +  u16_t value; +  value = *ptr++ << 8; +  value |= *ptr; +  LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value)); +  return value; +} +#endif + +/** + * Return the 32-bit value of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u32_t dhcp_get_option_long(u8_t *ptr) +{ +  u32_t value; +  value = (u32_t)(*ptr++) << 24; +  value |= (u32_t)(*ptr++) << 16; +  value |= (u32_t)(*ptr++) << 8; +  value |= (u32_t)(*ptr++); +  LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value)); +  return value; +} + +#endif /* LWIP_DHCP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/dns.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/dns.c new file mode 100644 index 000000000..62a2592e9 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/dns.c @@ -0,0 +1,980 @@ +/** + * @file + * DNS - host name to IP address resolver. + * + */ + +/** + + * This file implements a DNS host name to IP address resolver. + + * Port to lwIP from uIP + * by Jim Pettinato April 2007 + + * uIP version Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + *    products derived from this software without specific prior + *    written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * DNS.C + * + * The lwIP DNS resolver functions are used to lookup a host name and + * map it to a numerical IP address. It maintains a list of resolved + * hostnames that can be queried with the dns_lookup() function. + * New hostnames can be resolved using the dns_query() function. + * + * The lwIP version of the resolver also adds a non-blocking version of + * gethostbyname() that will work with a raw API application. This function + * checks for an IP address string first and converts it if it is valid. + * gethostbyname() then does a dns_lookup() to see if the name is  + * already in the table. If so, the IP is returned. If not, a query is  + * issued and the function returns with a ERR_INPROGRESS status. The app + * using the dns client must then go into a waiting state. + * + * Once a hostname has been resolved (or found to be non-existent), + * the resolver code calls a specified callback function (which  + * must be implemented by the module that uses the resolver). + */ + +/*----------------------------------------------------------------------------- + * RFC 1035 - Domain names - implementation and specification + * RFC 2181 - Clarifications to the DNS Specification + *----------------------------------------------------------------------------*/ + +/** @todo: define good default values (rfc compliance) */ +/** @todo: improve answer parsing, more checkings... */ +/** @todo: check RFC1035 - 7.3. Processing responses */ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "lwip/dns.h" + +#include <string.h> + +/** DNS server IP address */ +#ifndef DNS_SERVER_ADDRESS +#define DNS_SERVER_ADDRESS        inet_addr("208.67.222.222") /* resolver1.opendns.com */ +#endif + +/** DNS server port address */ +#ifndef DNS_SERVER_PORT +#define DNS_SERVER_PORT           53 +#endif + +/** DNS maximum number of retries when asking for a name, before "timeout". */ +#ifndef DNS_MAX_RETRIES +#define DNS_MAX_RETRIES           4 +#endif + +/** DNS resource record max. TTL (one week as default) */ +#ifndef DNS_MAX_TTL +#define DNS_MAX_TTL               604800 +#endif + +/* DNS protocol flags */ +#define DNS_FLAG1_RESPONSE        0x80 +#define DNS_FLAG1_OPCODE_STATUS   0x10 +#define DNS_FLAG1_OPCODE_INVERSE  0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE     0x04 +#define DNS_FLAG1_TRUNC           0x02 +#define DNS_FLAG1_RD              0x01 +#define DNS_FLAG2_RA              0x80 +#define DNS_FLAG2_ERR_MASK        0x0f +#define DNS_FLAG2_ERR_NONE        0x00 +#define DNS_FLAG2_ERR_NAME        0x03 + +/* DNS protocol states */ +#define DNS_STATE_UNUSED          0 +#define DNS_STATE_NEW             1 +#define DNS_STATE_ASKING          2 +#define DNS_STATE_DONE            3 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS message header */ +struct dns_hdr { +  PACK_STRUCT_FIELD(u16_t id); +  PACK_STRUCT_FIELD(u8_t flags1); +  PACK_STRUCT_FIELD(u8_t flags2); +  PACK_STRUCT_FIELD(u16_t numquestions); +  PACK_STRUCT_FIELD(u16_t numanswers); +  PACK_STRUCT_FIELD(u16_t numauthrr); +  PACK_STRUCT_FIELD(u16_t numextrarr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_HDR 12 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS query message structure */ +struct dns_query { +  /* DNS query record starts with either a domain name or a pointer +     to a name already present somewhere in the packet. */ +  PACK_STRUCT_FIELD(u16_t type); +  PACK_STRUCT_FIELD(u16_t class); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_QUERY 4 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS answer message structure */ +struct dns_answer { +  /* DNS answer record starts with either a domain name or a pointer +     to a name already present somewhere in the packet. */ +  PACK_STRUCT_FIELD(u16_t type); +  PACK_STRUCT_FIELD(u16_t class); +  PACK_STRUCT_FIELD(u32_t ttl); +  PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_ANSWER 10 + +/** DNS table entry */ +struct dns_table_entry { +  u8_t  state; +  u8_t  numdns; +  u8_t  tmr; +  u8_t  retries; +  u8_t  seqno; +  u8_t  err; +  u32_t ttl; +  char name[DNS_MAX_NAME_LENGTH]; +  struct ip_addr ipaddr; +  /* pointer to callback on DNS query done */ +  dns_found_callback found; +  void *arg; +}; + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { +  /** static hostname */ +  const char *name; +  /** static host address in network byteorder */ +  u32_t addr; +  struct local_hostlist_entry *next; +}; + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Local host-list. For hostnames in this list, no + *  external name resolution is performed */ +static struct local_hostlist_entry *local_hostlist_dynamic; +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE +#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ +/** Defining this allows the local_hostlist_static to be placed in a different + * linker section (e.g. FLASH) */ +#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST +#define DNS_LOCAL_HOSTLIST_STORAGE_POST +#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ +DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] +  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; + +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +static void dns_init_local(); +#endif /* DNS_LOCAL_HOSTLIST */ + + +/* forward declarations */ +static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); +static void dns_check_entries(void); + +/*----------------------------------------------------------------------------- + * Globales + *----------------------------------------------------------------------------*/ + +/* DNS variables */ +static struct udp_pcb        *dns_pcb; +static u8_t                   dns_seqno; +static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; +static struct ip_addr         dns_servers[DNS_MAX_SERVERS]; + +#if (DNS_USES_STATIC_BUF == 1) +static u8_t                   dns_payload[DNS_MSG_SIZE]; +#endif /* (DNS_USES_STATIC_BUF == 1) */ + +/** + * Initialize the resolver: set up the UDP pcb and configure the default server + * (DNS_SERVER_ADDRESS). + */ +void +dns_init() +{ +  struct ip_addr dnsserver; +   +  /* initialize default DNS server address */ +  dnsserver.addr = DNS_SERVER_ADDRESS; + +  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); + +  /* if dns client not yet initialized... */ +  if (dns_pcb == NULL) { +    dns_pcb = udp_new(); + +    if (dns_pcb != NULL) { +      /* initialize DNS table not needed (initialized to zero since it is a +       * global variable) */ +      LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", +        DNS_STATE_UNUSED == 0); + +      /* initialize DNS client */ +      udp_bind(dns_pcb, IP_ADDR_ANY, 0); +      udp_recv(dns_pcb, dns_recv, NULL); + +      /* initialize default DNS primary server */ +      dns_setserver(0, &dnsserver); +    } +  } +#if DNS_LOCAL_HOSTLIST +  dns_init_local(); +#endif +} + +/** + * Initialize one of the DNS servers. + * + * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS + * @param dnsserver IP address of the DNS server to set + */ +void +dns_setserver(u8_t numdns, struct ip_addr *dnsserver) +{ +  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) && +      (dnsserver != NULL) && (dnsserver->addr !=0 )) { +    dns_servers[numdns] = (*dnsserver); +  } +} + +/** + * Obtain one of the currently configured DNS server. + * + * @param numdns the index of the DNS server + * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS + *         server has not been configured. + */ +struct ip_addr +dns_getserver(u8_t numdns) +{ +  if (numdns < DNS_MAX_SERVERS) { +    return dns_servers[numdns]; +  } else { +    return *IP_ADDR_ANY; +  } +} + +/** + * The DNS resolver client timer - handle retries and timeouts and should + * be called every DNS_TMR_INTERVAL milliseconds (every second by default). + */ +void +dns_tmr(void) +{ +  if (dns_pcb != NULL) { +    LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); +    dns_check_entries(); +  } +} + +#if DNS_LOCAL_HOSTLIST +static void +dns_init_local() +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) +  int i; +  struct local_hostlist_entry *entry; +  /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ +  struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; +  for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { +    entry = mem_malloc(sizeof(struct local_hostlist_entry)); +    LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); +    if (entry != NULL) { +      struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; +      entry->name = init_entry->name; +      entry->addr = init_entry->addr; +      entry->next = local_hostlist_dynamic; +      local_hostlist_dynamic = entry; +    } +  } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ +} + +/** + * Scans the local host-list for a hostname. + * + * @param hostname Hostname to look for in the local host-list + * @return The first IP address for the hostname in the local host-list or + *         INADDR_NONE if not found. + */ +static u32_t +dns_lookup_local(const char *hostname) +{ +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +  struct local_hostlist_entry *entry = local_hostlist_dynamic; +  while(entry != NULL) { +    if(strcmp(entry->name, hostname) == 0) { +      return entry->addr; +    } +    entry = entry->next; +  } +#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +  int i; +  for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) { +    if(strcmp(local_hostlist_static[i].name, hostname) == 0) { +      return local_hostlist_static[i].addr; +    } +  } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +  return INADDR_NONE; +} + +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +/** Remove all entries from the local host-list for a specific hostname + * and/or IP addess + * + * @param hostname hostname for which entries shall be removed from the local + *                 host-list + * @param addr address for which entries shall be removed from the local host-list + * @return the number of removed entries + */ +int +dns_local_removehost(const char *hostname, const struct ip_addr *addr) +{ +  int removed = 0; +  struct local_hostlist_entry *entry = local_hostlist_dynamic; +  struct local_hostlist_entry *last_entry = NULL; +  while (entry != NULL) { +    if (((hostname == NULL) || !strcmp(entry->name, hostname)) && +        ((addr == NULL) || (entry->addr == addr->addr))) { +      struct local_hostlist_entry *free_entry; +      if (last_entry != NULL) { +        last_entry->next = entry->next; +      } else { +        local_hostlist_dynamic = entry->next; +      } +      free_entry = entry; +      entry = entry->next; +      mem_free(free_entry); +      removed++; +    } else { +      last_entry = entry; +      entry = entry->next; +    } +  } +  return removed; +} + +/** + * Add a hostname/IP address pair to the local host-list. + * Duplicates are not checked. + * + * @param hostname hostname of the new entry + * @param addr IP address of the new entry + * @return ERR_OK if succeeded or ERR_MEM on memory error + */ +err_t +dns_local_addhost(const char *hostname, const struct ip_addr *addr) +{ +  struct local_hostlist_entry *entry; +  entry = mem_malloc(sizeof(struct local_hostlist_entry)); +  if (entry == NULL) { +    return ERR_MEM; +  } +  entry->name = hostname; +  entry->addr = addr->addr; +  entry->next = local_hostlist_dynamic; +  local_hostlist_dynamic = entry; +  return ERR_OK; +} +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ +#endif /* DNS_LOCAL_HOSTLIST */ + +/** + * Look up a hostname in the array of known hostnames. + * + * @note This function only looks in the internal array of known + * hostnames, it does not send out a query for the hostname if none + * was found. The function dns_enqueue() can be used to send a query + * for a hostname. + * + * @param name the hostname to look up + * @return the hostname's IP address, as u32_t (instead of struct ip_addr to + *         better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname + *         was not found in the cached dns_table. + */ +static u32_t +dns_lookup(const char *name) +{ +  u8_t i; +#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) +  u32_t addr; +#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ +#if DNS_LOCAL_HOSTLIST +  if ((addr = dns_lookup_local(name)) != INADDR_NONE) { +    return addr; +  } +#endif /* DNS_LOCAL_HOSTLIST */ +#ifdef DNS_LOOKUP_LOCAL_EXTERN +  if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_NONE) { +    return addr; +  } +#endif /* DNS_LOOKUP_LOCAL_EXTERN */ + +  /* Walk through name list, return entry if found. If not, return NULL. */ +  for (i = 0; i < DNS_TABLE_SIZE; ++i) { +    if ((dns_table[i].state == DNS_STATE_DONE) && +        (strcmp(name, dns_table[i].name) == 0)) { +      LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); +      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); +      LWIP_DEBUGF(DNS_DEBUG, ("\n")); +      return dns_table[i].ipaddr.addr; +    } +  } + +  return INADDR_NONE; +} + +#if DNS_DOES_NAME_CHECK +/** + * Compare the "dotted" name "query" with the encoded name "response" + * to make sure an answer from the DNS server matches the current dns_table + * entry (otherwise, answers might arrive late for hostname not on the list + * any more). + * + * @param query hostname (not encoded) from the dns_table + * @param response encoded hostname in the DNS response + * @return 0: names equal; 1: names differ + */ +static u8_t +dns_compare_name(unsigned char *query, unsigned char *response) +{ +  unsigned char n; + +  do { +    n = *response++; +    /** @see RFC 1035 - 4.1.4. Message compression */ +    if ((n & 0xc0) == 0xc0) { +      /* Compressed name */ +      break; +    } else { +      /* Not compressed name */ +      while (n > 0) { +        if ((*query) != (*response)) { +          return 1; +        } +        ++response; +        ++query; +        --n; +      }; +      ++query; +    } +  } while (*response != 0); + +  return 0; +} +#endif /* DNS_DOES_NAME_CHECK */ + +/** + * Walk through a compact encoded DNS name and return the end of the name. + * + * @param query encoded DNS name in the DNS server response + * @return end of the name + */ +static unsigned char * +dns_parse_name(unsigned char *query) +{ +  unsigned char n; + +  do { +    n = *query++; +    /** @see RFC 1035 - 4.1.4. Message compression */ +    if ((n & 0xc0) == 0xc0) { +      /* Compressed name */ +      break; +    } else { +      /* Not compressed name */ +      while (n > 0) { +        ++query; +        --n; +      }; +    } +  } while (*query != 0); + +  return query + 1; +} + +/** + * Send a DNS query packet. + * + * @param numdns index of the DNS server in the dns_servers table + * @param name hostname to query + * @param id index of the hostname in dns_table, used as transaction ID in the + *        DNS query packet + * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise + */ +static err_t +dns_send(u8_t numdns, const char* name, u8_t id) +{ +  err_t err; +  struct dns_hdr *hdr; +  struct dns_query qry; +  struct pbuf *p; +  char *query, *nptr; +  const char *pHostname; +  u8_t n; + +  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", +              (u16_t)(numdns), name)); +  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS); +  LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0); + +  /* if here, we have either a new query or a retry on a previous query to process */ +  p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH + +                 SIZEOF_DNS_QUERY, PBUF_RAM); +  if (p != NULL) { +    LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); +    /* fill dns header */ +    hdr = (struct dns_hdr*)p->payload; +    memset(hdr, 0, SIZEOF_DNS_HDR); +    hdr->id = htons(id); +    hdr->flags1 = DNS_FLAG1_RD; +    hdr->numquestions = htons(1); +    query = (char*)hdr + SIZEOF_DNS_HDR; +    pHostname = name; +    --pHostname; + +    /* convert hostname into suitable query format. */ +    do { +      ++pHostname; +      nptr = query; +      ++query; +      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { +        *query = *pHostname; +        ++query; +        ++n; +      } +      *nptr = n; +    } while(*pHostname != 0); +    *query++='\0'; + +    /* fill dns query */ +    qry.type  = htons(DNS_RRTYPE_A); +    qry.class = htons(DNS_RRCLASS_IN); +    MEMCPY( query, &qry, SIZEOF_DNS_QUERY); + +    /* resize pbuf to the exact dns query */ +    pbuf_realloc(p, (query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))); + +    /* connect to the server for faster receiving */ +    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT); +    /* send dns packet */ +    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT); + +    /* free pbuf */ +    pbuf_free(p); +  } else { +    err = ERR_MEM; +  } + +  return err; +} + +/** + * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query. + * Check an entry in the dns_table: + * - send out query for new entries + * - retry old pending entries on timeout (also with different servers) + * - remove completed entries from the table if their TTL has expired + * + * @param i index of the dns_table entry to check + */ +static void +dns_check_entry(u8_t i) +{ +  struct dns_table_entry *pEntry = &dns_table[i]; + +  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); + +  switch(pEntry->state) { + +    case DNS_STATE_NEW: { +      /* initialize new entry */ +      pEntry->state   = DNS_STATE_ASKING; +      pEntry->numdns  = 0; +      pEntry->tmr     = 1; +      pEntry->retries = 0; +       +      /* send DNS packet for this entry */ +      dns_send(pEntry->numdns, pEntry->name, i); +      break; +    } + +    case DNS_STATE_ASKING: { +      if (--pEntry->tmr == 0) { +        if (++pEntry->retries == DNS_MAX_RETRIES) { +          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) { +            /* change of server */ +            pEntry->numdns++; +            pEntry->tmr     = 1; +            pEntry->retries = 0; +            break; +          } else { +            LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name)); +            /* call specified callback function if provided */ +            if (pEntry->found) +              (*pEntry->found)(pEntry->name, NULL, pEntry->arg); +            /* flush this entry */ +            pEntry->state   = DNS_STATE_UNUSED; +            pEntry->found   = NULL; +            break; +          } +        } + +        /* wait longer for the next retry */ +        pEntry->tmr = pEntry->retries; + +        /* send DNS packet for this entry */ +        dns_send(pEntry->numdns, pEntry->name, i); +      } +      break; +    } + +    case DNS_STATE_DONE: { +      /* if the time to live is nul */ +      if (--pEntry->ttl == 0) { +        LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name)); +        /* flush this entry */ +        pEntry->state = DNS_STATE_UNUSED; +        pEntry->found = NULL; +      } +      break; +    } +    case DNS_STATE_UNUSED: +      /* nothing to do */ +      break; +    default: +      LWIP_ASSERT("unknown dns_table entry state:", 0); +      break; +  } +} + +/** + * Call dns_check_entry for each entry in dns_table - check all entries. + */ +static void +dns_check_entries(void) +{ +  u8_t i; + +  for (i = 0; i < DNS_TABLE_SIZE; ++i) { +    dns_check_entry(i); +  } +} + +/** + * Receive input function for DNS response packets arriving for the dns UDP pcb. + * + * @params see udp.h + */ +static void +dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +{ +  u8_t i; +  char *pHostname; +  struct dns_hdr *hdr; +  struct dns_answer ans; +  struct dns_table_entry *pEntry; +  u8_t nquestions, nanswers; +#if (DNS_USES_STATIC_BUF == 0) +  u8_t dns_payload[DNS_MSG_SIZE]; +#endif /* (DNS_USES_STATIC_BUF == 0) */ +#if (DNS_USES_STATIC_BUF == 2) +  u8_t* dns_payload; +#endif /* (DNS_USES_STATIC_BUF == 2) */ + +  LWIP_UNUSED_ARG(arg); +  LWIP_UNUSED_ARG(pcb); +  LWIP_UNUSED_ARG(addr); +  LWIP_UNUSED_ARG(port); + +  /* is the dns message too big ? */ +  if (p->tot_len > DNS_MSG_SIZE) { +    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); +    /* free pbuf and return */ +    goto memerr1; +  } + +  /* is the dns message big enough ? */ +  if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { +    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); +    /* free pbuf and return */ +    goto memerr1; +  } + +#if (DNS_USES_STATIC_BUF == 2) +  dns_payload = mem_malloc(p->tot_len); +  if (dns_payload == NULL) { +    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n")); +    /* free pbuf and return */ +    goto memerr1; +  } +#endif /* (DNS_USES_STATIC_BUF == 2) */ + +  /* copy dns payload inside static buffer for processing */  +  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) { +    /* The ID in the DNS header should be our entry into the name table. */ +    hdr = (struct dns_hdr*)dns_payload; +    i = htons(hdr->id); +    if (i < DNS_TABLE_SIZE) { +      pEntry = &dns_table[i]; +      if(pEntry->state == DNS_STATE_ASKING) { +        /* This entry is now completed. */ +        pEntry->state = DNS_STATE_DONE; +        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK; + +        /* We only care about the question(s) and the answers. The authrr +           and the extrarr are simply discarded. */ +        nquestions = htons(hdr->numquestions); +        nanswers   = htons(hdr->numanswers); + +        /* Check for error. If so, call callback to inform. */ +        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) { +          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name)); +          /* call callback to indicate error, clean up memory and return */ +          goto responseerr; +        } + +#if DNS_DOES_NAME_CHECK +        /* Check if the name in the "question" part match with the name in the entry. */ +        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) { +          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name)); +          /* call callback to indicate error, clean up memory and return */ +          goto responseerr; +        } +#endif /* DNS_DOES_NAME_CHECK */ + +        /* Skip the name in the "question" part */ +        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY; + +        while(nanswers > 0) { +          /* skip answer resource record's host name */ +          pHostname = (char *) dns_parse_name((unsigned char *)pHostname); + +          /* Check for IP address type and Internet class. Others are discarded. */ +          MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); +          if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) { +            /* read the answer resource record's TTL, and maximize it if needed */ +            pEntry->ttl = ntohl(ans.ttl); +            if (pEntry->ttl > DNS_MAX_TTL) { +              pEntry->ttl = DNS_MAX_TTL; +            } +            /* read the IP address after answer resource record's header */ +            MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr)); +            LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name)); +            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr))); +            LWIP_DEBUGF(DNS_DEBUG, ("\n")); +            /* call specified callback function if provided */ +            if (pEntry->found) { +              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg); +            } +            /* deallocate memory and return */ +            goto memerr2; +          } else { +            pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len); +          } +          --nanswers; +        } +        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name)); +        /* call callback to indicate error, clean up memory and return */ +        goto responseerr; +      } +    } +  } + +  /* deallocate memory and return */ +  goto memerr2; + +responseerr: +  /* ERROR: call specified callback function with NULL as name to indicate an error */ +  if (pEntry->found) { +    (*pEntry->found)(pEntry->name, NULL, pEntry->arg); +  } +  /* flush this entry */ +  pEntry->state = DNS_STATE_UNUSED; +  pEntry->found = NULL; + +memerr2: +#if (DNS_USES_STATIC_BUF == 2) +  /* free dns buffer */ +  mem_free(dns_payload); +#endif /* (DNS_USES_STATIC_BUF == 2) */ + +memerr1: +  /* free pbuf */ +  pbuf_free(p); +  return; +} + +/** + * Queues a new hostname to resolve and sends out a DNS query for that hostname + * + * @param name the hostname that is to be queried + * @param found a callback founction to be called on success, failure or timeout + * @param callback_arg argument to pass to the callback function + * @return @return a err_t return code. + */ +static err_t +dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) +{ +  u8_t i; +  u8_t lseq, lseqi; +  struct dns_table_entry *pEntry = NULL; + +  /* search an unused entry, or the oldest one */ +  lseq = lseqi = 0; +  for (i = 0; i < DNS_TABLE_SIZE; ++i) { +    pEntry = &dns_table[i]; +    /* is it an unused entry ? */ +    if (pEntry->state == DNS_STATE_UNUSED) +      break; + +    /* check if this is the oldest completed entry */ +    if (pEntry->state == DNS_STATE_DONE) { +      if ((dns_seqno - pEntry->seqno) > lseq) { +        lseq = dns_seqno - pEntry->seqno; +        lseqi = i; +      } +    } +  } + +  /* if we don't have found an unused entry, use the oldest completed one */ +  if (i == DNS_TABLE_SIZE) { +    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { +      /* no entry can't be used now, table is full */ +      LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); +      return ERR_MEM; +    } else { +      /* use the oldest completed one */ +      i = lseqi; +      pEntry = &dns_table[i]; +    } +  } + +  /* use this entry */ +  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); + +  /* fill the entry */ +  pEntry->state = DNS_STATE_NEW; +  pEntry->seqno = dns_seqno++; +  pEntry->found = found; +  pEntry->arg   = callback_arg; +  strcpy(pEntry->name, name); + +  /* force to send query without waiting timer */ +  dns_check_entry(i); + +  /* dns query is enqueued */ +  return ERR_INPROGRESS; +} + +/** + * Resolve a hostname (string) into an IP address. + * NON-BLOCKING callback version for use with raw API!!! + * + * Returns immediately with one of err_t return codes: + * - ERR_OK if hostname is a valid IP address string or the host + *   name is already in the local names table. + * - ERR_INPROGRESS enqueue a request to be sent to the DNS server + *   for resolution if no errors are present. + * + * @param hostname the hostname that is to be queried + * @param addr pointer to a struct ip_addr where to store the address if it is already + *             cached in the dns_table (only valid if ERR_OK is returned!) + * @param found a callback function to be called on success, failure or timeout (only if + *              ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @return a err_t return code. + */ +err_t +dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found, +                  void *callback_arg) +{ +  /* not initialized or no valid server yet, or invalid addr pointer +   * or invalid hostname or invalid hostname length */ +  if ((dns_pcb == NULL) || (addr == NULL) || +      (!hostname) || (!hostname[0]) || +      (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) { +    return ERR_VAL; +  } + +#if LWIP_HAVE_LOOPIF +  if (strcmp(hostname,"localhost")==0) { +    addr->addr = INADDR_LOOPBACK; +    return ERR_OK; +  } +#endif /* LWIP_HAVE_LOOPIF */ + +  /* host name already in octet notation? set ip addr and return ERR_OK +   * already have this address cached? */ +  if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) || +      ((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) { +    return ERR_OK; +  } + +  /* queue query with specified callback */ +  return dns_enqueue(hostname, found, callback_arg); +} + +#endif /* LWIP_DNS */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/init.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/init.c new file mode 100644 index 000000000..277811a6a --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/init.c @@ -0,0 +1,269 @@ +/** + * @file + * Modules initialization + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/init.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/sockets.h" +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/snmp_msg.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "netif/etharp.h" + +/* Compile-time sanity checks for configuration errors. + * These can be done independently of LWIP_DEBUG, without penalty. + */ +#ifndef BYTE_ORDER +  #error "BYTE_ORDER is not defined, you have to define it in your cc.h" +#endif +#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) +  #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" +#endif +#if (!LWIP_ARP && ARP_QUEUEING) +  #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_UDPLITE) +  #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_SNMP) +  #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DHCP) +  #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_IGMP) +  #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (!LWIP_UDP && LWIP_DNS) +  #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) +  #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) +  #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" +#endif +#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) +  #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) +  #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) +  #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && (TCP_WND > 0xffff)) +  #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) +  #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" +#endif +#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) +  #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" +#endif +#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff)) +  #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" +#endif +#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) +  #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" +#endif +#if (PPP_SUPPORT && (NO_SYS==1)) +  #error "If you want to use PPP, you have to define NO_SYS=0 in your lwipopts.h" +#endif  +#if (LWIP_NETIF_API && (NO_SYS==1)) +  #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) +  #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" +#endif +#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) +  #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" +#endif +#if (!LWIP_NETCONN && LWIP_SOCKET) +  #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) +  #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" +#endif +#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) +  #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" +#endif +#if (!LWIP_ARP && LWIP_AUTOIP) +  #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" +#endif +#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0)) +  #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h" +#endif +#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0)) +  #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h" +#endif +#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API))) +  #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" +#endif +/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ +#if ((NO_SYS==0) && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))) +  #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" +#endif +#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) +  #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" +#endif +#if (MEM_LIBC_MALLOC && MEM_USE_POOLS) +  #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" +#endif +#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) +  #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" +#endif +#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) +  #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" +#endif +#if (TCP_QUEUE_OOSEQ && !LWIP_TCP) +  #error "TCP_QUEUE_OOSEQ requires LWIP_TCP" +#endif +#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) +  #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" +#endif + + +/* Compile-time checks for deprecated options. + */ +#ifdef MEMP_NUM_TCPIP_MSG +  #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef MEMP_NUM_API_MSG +  #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef TCP_REXMIT_DEBUG +  #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef RAW_STATS +  #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_QUEUE_FIRST +  #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." +#endif +#ifdef ETHARP_ALWAYS_INSERT +  #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." +#endif +#if SO_REUSE +/* I removed the lot since this was an ugly hack. It broke the raw-API. +   It also came with many ugly goto's, Christiaan Simons. */ +  #error "SO_REUSE currently unavailable, this was a hack" +#endif + +#ifdef LWIP_DEBUG +static void +lwip_sanity_check(void) +{ +  /* Warnings */ +#if LWIP_NETCONN +  if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n")); +#endif /* LWIP_NETCONN */ +#if LWIP_TCP +  if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n")); +  if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS))) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n")); +  if (TCP_SNDLOWAT > TCP_SND_BUF) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than or equal to TCP_SND_BUF.\n")); +  if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE)) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n")); +  if (TCP_WND < TCP_MSS) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n")); +#endif /* LWIP_TCP */ +} +#else  /* LWIP_DEBUG */ +#define lwip_sanity_check() +#endif /* LWIP_DEBUG */ + +/** + * Perform Sanity check of user-configurable values, and initialize all modules. + */ +void +lwip_init(void) +{ +  /* Sanity check user-configurable values */ +  lwip_sanity_check(); + +  /* Modules initialization */ +  stats_init(); +  sys_init(); +  mem_init(); +  memp_init(); +  pbuf_init(); +  netif_init(); +#if LWIP_SOCKET +  lwip_socket_init(); +#endif /* LWIP_SOCKET */ +  ip_init(); +#if LWIP_ARP +  etharp_init(); +#endif /* LWIP_ARP */ +#if LWIP_RAW +  raw_init(); +#endif /* LWIP_RAW */ +#if LWIP_UDP +  udp_init(); +#endif /* LWIP_UDP */ +#if LWIP_TCP +  tcp_init(); +#endif /* LWIP_TCP */ +#if LWIP_SNMP +  snmp_init(); +#endif /* LWIP_SNMP */ +#if LWIP_AUTOIP +  autoip_init(); +#endif /* LWIP_AUTOIP */ +#if LWIP_IGMP +  igmp_init(); +#endif /* LWIP_IGMP */ +#if LWIP_DNS +  dns_init(); +#endif /* LWIP_DNS */ +} diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/autoip.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/autoip.c new file mode 100644 index 000000000..367adb060 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/autoip.c @@ -0,0 +1,453 @@ +/** + * @file + * AutoIP Automatic LinkLocal IP Configuration + * + */ + +/* + * + * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies <kontakt@dspies.de> + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * <kontakt@dspies.de> + */ + +/******************************************************************************* + * USAGE: + *  + * define LWIP_AUTOIP 1  in your lwipopts.h + *  + * If you don't use tcpip.c (so, don't call, you don't call tcpip_init): + * - First, call autoip_init(). + * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces, + *   that should be defined in autoip.h. + *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0. + *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... + * + * Without DHCP: + * - Call autoip_start() after netif_add(). + *  + * With DHCP: + * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. + * - Configure your DHCP Client. + * + */ + +#include "lwip/opt.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/autoip.h" +#include "netif/etharp.h" + +#include <stdlib.h> +#include <string.h> + +/* 169.254.0.0 */ +#define AUTOIP_NET         0xA9FE0000 +/* 169.254.1.0 */ +#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) +/* 169.254.254.255 */ +#define AUTOIP_RANGE_END   (AUTOIP_NET | 0xFEFF) + + +/** Pseudo random macro based on netif informations. + * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ +#ifndef LWIP_AUTOIP_RAND +#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ +                                   ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ +                                   ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ +                                   ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ +                                   (netif->autoip?netif->autoip->tried_llipaddr:0)) +#endif /* LWIP_AUTOIP_RAND */ + +/** + * Macro that generates the initial IP address to be tried by AUTOIP. + * If you want to override this, define it to something else in lwipopts.h. + */ +#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR +#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ +  (AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ +                 ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) +#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ + +/* static functions */ +static void autoip_handle_arp_conflict(struct netif *netif); + +/* creates a pseudo random LL IP-Address for a network interface */ +static void autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr); + +/* sends an ARP announce */ +static err_t autoip_arp_announce(struct netif *netif); + +/* configure interface for use with current LL IP-Address */ +static err_t autoip_bind(struct netif *netif); + +/** + * Initialize this module + */ +void +autoip_init(void) +{ +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n")); +} + +/** + * Handle a IP address conflict after an ARP conflict detection + */ +static void +autoip_handle_arp_conflict(struct netif *netif) +{ +  /* Somehow detect if we are defending or retreating */ +  unsigned char defend = 1; /* tbd */ + +  if(defend) { +    if(netif->autoip->lastconflict > 0) { +      /* retreat, there was a conflicting ARP in the last +       * DEFEND_INTERVAL seconds +       */ +      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +        ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); + +      /* TODO: close all TCP sessions */ +      autoip_start(netif); +    } else { +      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +        ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); +      autoip_arp_announce(netif); +      netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; +    } +  } else { +    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +      ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); +    /* TODO: close all TCP sessions */ +    autoip_start(netif); +  } +} + +/** + * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 + * + * @param netif network interface on which create the IP-Address + * @param IPAddr ip address to initialize + */ +static void +autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr) +{ +  /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 +   * compliant to RFC 3927 Section 2.1 +   * We have 254 * 256 possibilities */ + +  u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); +  addr += netif->autoip->tried_llipaddr; +  addr = AUTOIP_NET | (addr & 0xffff); +  /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */  + +  if (addr < AUTOIP_RANGE_START) { +    addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; +  } +  if (addr > AUTOIP_RANGE_END) { +    addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; +  } +  LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && +	(addr <= AUTOIP_RANGE_END)); +  IPAddr->addr = htonl(addr); +   +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +    ("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n", +    (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(IPAddr->addr))); +} + +/** + * Sends an ARP announce from a network interface + * + * @param netif network interface used to send the announce + */ +static err_t +autoip_arp_announce(struct netif *netif) +{ +  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, +    (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero, +    &netif->autoip->llipaddr, ARP_REQUEST); +} + +/** + * Configure interface for use with current LL IP-Address + * + * @param netif network interface to configure with current LL IP-Address + */ +static err_t +autoip_bind(struct netif *netif) +{ +  struct autoip *autoip = netif->autoip; +  struct ip_addr sn_mask, gw_addr; + +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, +    ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n", +    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr)); + +  IP4_ADDR(&sn_mask, 255, 255, 0, 0); +  IP4_ADDR(&gw_addr, 0, 0, 0, 0); + +  netif_set_ipaddr(netif, &autoip->llipaddr); +  netif_set_netmask(netif, &sn_mask); +  netif_set_gw(netif, &gw_addr);   + +  /* bring the interface up */ +  netif_set_up(netif); + +  return ERR_OK; +} + +/** + * Start AutoIP client + * + * @param netif network interface on which start the AutoIP client + */ +err_t +autoip_start(struct netif *netif) +{ +  struct autoip *autoip = netif->autoip; +  err_t result = ERR_OK; + +  if(netif_is_up(netif)) { +    netif_set_down(netif); +  } + +  /* Set IP-Address, Netmask and Gateway to 0 to make sure that +   * ARP Packets are formed correctly +   */ +  netif->ip_addr.addr = 0; +  netif->netmask.addr = 0; +  netif->gw.addr      = 0; + +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, +    ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], +    netif->name[1], (u16_t)netif->num)); +  if(autoip == NULL) { +    /* no AutoIP client attached yet? */ +    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, +      ("autoip_start(): starting new AUTOIP client\n")); +    autoip = mem_malloc(sizeof(struct autoip)); +    if(autoip == NULL) { +      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, +        ("autoip_start(): could not allocate autoip\n")); +      return ERR_MEM; +    } +    memset( autoip, 0, sizeof(struct autoip)); +    /* store this AutoIP client in the netif */ +    netif->autoip = autoip; +    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); +  } else { +    autoip->state = AUTOIP_STATE_OFF; +    autoip->ttw = 0; +    autoip->sent_num = 0; +    memset(&autoip->llipaddr, 0, sizeof(struct ip_addr)); +    autoip->lastconflict = 0; +  } + +  autoip_create_addr(netif, &(autoip->llipaddr)); +  autoip->tried_llipaddr++; +  autoip->state = AUTOIP_STATE_PROBING; +  autoip->sent_num = 0; + +  /* time to wait to first probe, this is randomly +   * choosen out of 0 to PROBE_WAIT seconds. +   * compliant to RFC 3927 Section 2.2.1 +   */ +  autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); + +  /* +   * if we tried more then MAX_CONFLICTS we must limit our rate for +   * accquiring and probing address +   * compliant to RFC 3927 Section 2.2.1 +   */ + +  if(autoip->tried_llipaddr > MAX_CONFLICTS) { +    autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; +  } + +  return result; +} + +/** + * Stop AutoIP client + * + * @param netif network interface on which stop the AutoIP client + */ +err_t +autoip_stop(struct netif *netif) +{ +  netif->autoip->state = AUTOIP_STATE_OFF; +  netif_set_down(netif); +  return ERR_OK; +} + +/** + * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds + */ +void +autoip_tmr() +{ +  struct netif *netif = netif_list; +  /* loop through netif's */ +  while (netif != NULL) { +    /* only act on AutoIP configured interfaces */ +    if (netif->autoip != NULL) { +      if(netif->autoip->lastconflict > 0) { +        netif->autoip->lastconflict--; +      } + +      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, +        ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", +        (u16_t)(netif->autoip->state), netif->autoip->ttw)); + +      switch(netif->autoip->state) { +        case AUTOIP_STATE_PROBING: +          if(netif->autoip->ttw > 0) { +            netif->autoip->ttw--; +          } else { +            if(netif->autoip->sent_num == PROBE_NUM) { +              netif->autoip->state = AUTOIP_STATE_ANNOUNCING; +              netif->autoip->sent_num = 0; +              netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; +            } else { +              etharp_request(netif, &(netif->autoip->llipaddr)); +              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, +                ("autoip_tmr() PROBING Sent Probe\n")); +              netif->autoip->sent_num++; +              /* calculate time to wait to next probe */ +              netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % +                ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + +                PROBE_MIN * AUTOIP_TICKS_PER_SECOND); +            } +          } +          break; + +        case AUTOIP_STATE_ANNOUNCING: +          if(netif->autoip->ttw > 0) { +            netif->autoip->ttw--; +          } else { +            if(netif->autoip->sent_num == 0) { +             /* We are here the first time, so we waited ANNOUNCE_WAIT seconds +              * Now we can bind to an IP address and use it +              */ +              autoip_bind(netif); +            } + +            if(netif->autoip->sent_num == ANNOUNCE_NUM) { +              netif->autoip->state = AUTOIP_STATE_BOUND; +              netif->autoip->sent_num = 0; +              netif->autoip->ttw = 0; +            } else { +              autoip_arp_announce(netif); +              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, +                ("autoip_tmr() ANNOUNCING Sent Announce\n")); +              netif->autoip->sent_num++; +              netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; +            } +          } +          break; +      } +    } +    /* proceed to next network interface */ +    netif = netif->next; +  } +} + +/** + * Handles every incoming ARP Packet, called by etharp_arp_input. + * + * @param netif network interface to use for autoip processing + * @param hdr Incoming ARP packet + */ +void +autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) +{ +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n")); +  if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { +   /* when ip.src == llipaddr && hw.src != netif->hwaddr +    * +    * when probing  ip.dst == llipaddr && hw.src != netif->hwaddr +    * we have a conflict and must solve it +    */ +    struct ip_addr sipaddr, dipaddr; +    struct eth_addr netifaddr; +    netifaddr.addr[0] = netif->hwaddr[0]; +    netifaddr.addr[1] = netif->hwaddr[1]; +    netifaddr.addr[2] = netif->hwaddr[2]; +    netifaddr.addr[3] = netif->hwaddr[3]; +    netifaddr.addr[4] = netif->hwaddr[4]; +    netifaddr.addr[5] = netif->hwaddr[5]; + +    /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without +     * structure packing (not using structure copy which breaks strict-aliasing rules). +     */ +    SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); +    SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); +       +    if ((netif->autoip->state == AUTOIP_STATE_PROBING) || +        ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && +         (netif->autoip->sent_num == 0))) { +     /* RFC 3927 Section 2.2.1: +      * from beginning to after ANNOUNCE_WAIT +      * seconds we have a conflict if +      * ip.src == llipaddr OR +      * ip.dst == llipaddr && hw.src != own hwaddr +      */ +      if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || +          (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && +           !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { +        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +          ("autoip_arp_reply(): Probe Conflict detected\n")); +        autoip_start(netif); +      } +    } else { +     /* RFC 3927 Section 2.5: +      * in any state we have a conflict if +      * ip.src == llipaddr && hw.src != own hwaddr +      */ +      if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && +          !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { +        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +          ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); +        autoip_handle_arp_conflict(netif); +      } +    } +  } +} + +#endif /* LWIP_AUTOIP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/icmp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/icmp.c new file mode 100644 index 000000000..b97a587a7 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/icmp.c @@ -0,0 +1,331 @@ +/** + * @file + * ICMP - Internet Control Message Protocol + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This +   is not implemented. */ + +#include "lwip/opt.h" + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +#include <string.h> + +/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be + * used to modify and send a response packet (and to 1 if this is not the case, + * e.g. when link header is stripped of when receiving) */ +#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ + +/* The amount of data from the original packet to return in a dest-unreachable */ +#define ICMP_DEST_UNREACH_DATASIZE 8 + +static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); + +/** + * Processes ICMP input packets, called from ip_input(). + * + * Currently only processes icmp echo requests and sends + * out the echo response. + * + * @param p the icmp echo request packet, p->payload pointing to the ip header + * @param inp the netif on which this packet was received + */ +void +icmp_input(struct pbuf *p, struct netif *inp) +{ +  u8_t type; +#ifdef LWIP_DEBUG +  u8_t code; +#endif /* LWIP_DEBUG */ +  struct icmp_echo_hdr *iecho; +  struct ip_hdr *iphdr; +  struct ip_addr tmpaddr; +  s16_t hlen; + +  ICMP_STATS_INC(icmp.recv); +  snmp_inc_icmpinmsgs(); + + +  iphdr = p->payload; +  hlen = IPH_HL(iphdr) * 4; +  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); +    goto lenerr; +  } + +  type = *((u8_t *)p->payload); +#ifdef LWIP_DEBUG +  code = *(((u8_t *)p->payload)+1); +#endif /* LWIP_DEBUG */ +  switch (type) { +  case ICMP_ECHO: +#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING +    { +      int accepted = 1; +#if !LWIP_MULTICAST_PING +      /* multicast destination address? */ +      if (ip_addr_ismulticast(&iphdr->dest)) { +        accepted = 0; +      } +#endif /* LWIP_MULTICAST_PING */ +#if !LWIP_BROADCAST_PING +      /* broadcast destination address? */ +      if (ip_addr_isbroadcast(&iphdr->dest, inp)) { +        accepted = 0; +      } +#endif /* LWIP_BROADCAST_PING */ +      /* broadcast or multicast destination address not acceptd? */ +      if (!accepted) { +        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); +        ICMP_STATS_INC(icmp.err); +        pbuf_free(p); +        return; +      } +    } +#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); +    if (p->tot_len < sizeof(struct icmp_echo_hdr)) { +      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); +      goto lenerr; +    } +    if (inet_chksum_pbuf(p) != 0) { +      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); +      pbuf_free(p); +      ICMP_STATS_INC(icmp.chkerr); +      snmp_inc_icmpinerrors(); +      return; +    } +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +    if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { +      /* p is not big enough to contain link headers +       * allocate a new one and copy p into it +       */ +      struct pbuf *r; +      /* switch p->payload to ip header */ +      if (pbuf_header(p, hlen)) { +        LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); +        goto memerr; +      } +      /* allocate new packet buffer with space for link headers */ +      r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); +      if (r == NULL) { +        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); +        goto memerr; +      } +      LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", +                  (r->len >= hlen + sizeof(struct icmp_echo_hdr))); +      /* copy the whole packet including ip header */ +      if (pbuf_copy(r, p) != ERR_OK) { +        LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); +        goto memerr; +      } +      iphdr = r->payload; +      /* switch r->payload back to icmp header */ +      if (pbuf_header(r, -hlen)) { +        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); +        goto memerr; +      } +      /* free the original p */ +      pbuf_free(p); +      /* we now have an identical copy of p that has room for link headers */ +      p = r; +    } else { +      /* restore p->payload to point to icmp header */ +      if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { +        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); +        goto memerr; +      } +    } +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ +    /* At this point, all checks are OK. */ +    /* We generate an answer by switching the dest and src ip addresses, +     * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ +    iecho = p->payload; +    tmpaddr.addr = iphdr->src.addr; +    iphdr->src.addr = iphdr->dest.addr; +    iphdr->dest.addr = tmpaddr.addr; +    ICMPH_TYPE_SET(iecho, ICMP_ER); +    /* adjust the checksum */ +    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { +      iecho->chksum += htons(ICMP_ECHO << 8) + 1; +    } else { +      iecho->chksum += htons(ICMP_ECHO << 8); +    } + +    /* Set the correct TTL and recalculate the header checksum. */ +    IPH_TTL_SET(iphdr, ICMP_TTL); +    IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP +    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); +#endif /* CHECKSUM_GEN_IP */ + +    ICMP_STATS_INC(icmp.xmit); +    /* increase number of messages attempted to send */ +    snmp_inc_icmpoutmsgs(); +    /* increase number of echo replies attempted to send */ +    snmp_inc_icmpoutechoreps(); + +    if(pbuf_header(p, hlen)) { +      LWIP_ASSERT("Can't move over header in packet", 0); +    } else { +      err_t ret; +      ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL, +                   ICMP_TTL, 0, IP_PROTO_ICMP, inp); +      if (ret != ERR_OK) { +        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); +      } +    } +    break; +  default: +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",  +                (s16_t)type, (s16_t)code)); +    ICMP_STATS_INC(icmp.proterr); +    ICMP_STATS_INC(icmp.drop); +  } +  pbuf_free(p); +  return; +lenerr: +  pbuf_free(p); +  ICMP_STATS_INC(icmp.lenerr); +  snmp_inc_icmpinerrors(); +  return; +#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN +memerr: +  pbuf_free(p); +  ICMP_STATS_INC(icmp.err); +  snmp_inc_icmpinerrors(); +  return; +#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ +} + +/** + * Send an icmp 'destination unreachable' packet, called from ip_input() if + * the transport layer protocol is unknown and from udp_input() if the local + * port is not bound. + * + * @param p the input packet for which the 'unreachable' should be sent, + *          p->payload pointing to the IP header + * @param t type of the 'unreachable' packet + */ +void +icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +{ +  icmp_send_response(p, ICMP_DUR, t); +} + +#if IP_FORWARD || IP_REASSEMBLY +/** + * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. + * + * @param p the input packet for which the 'time exceeded' should be sent, + *          p->payload pointing to the IP header + * @param t type of the 'time exceeded' packet + */ +void +icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +{ +  icmp_send_response(p, ICMP_TE, t); +} + +#endif /* IP_FORWARD || IP_REASSEMBLY */ + +/** + * Send an icmp packet in response to an incoming packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + *          p->payload pointing to the IP header + * @param type Type of the ICMP header + * @param code Code of the ICMP header + */ +static void +icmp_send_response(struct pbuf *p, u8_t type, u8_t code) +{ +  struct pbuf *q; +  struct ip_hdr *iphdr; +  /* we can use the echo header here */ +  struct icmp_echo_hdr *icmphdr; + +  /* ICMP header + IP header + 8 bytes of data */ +  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, +                 PBUF_RAM); +  if (q == NULL) { +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold icmp message", +             (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); + +  iphdr = p->payload; +  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); +  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); +  LWIP_DEBUGF(ICMP_DEBUG, (" to ")); +  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); +  LWIP_DEBUGF(ICMP_DEBUG, ("\n")); + +  icmphdr = q->payload; +  icmphdr->type = type; +  icmphdr->code = code; +  icmphdr->id = 0; +  icmphdr->seqno = 0; + +  /* copy fields from original packet */ +  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, +          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); + +  /* calculate checksum */ +  icmphdr->chksum = 0; +  icmphdr->chksum = inet_chksum(icmphdr, q->len); +  ICMP_STATS_INC(icmp.xmit); +  /* increase number of messages attempted to send */ +  snmp_inc_icmpoutmsgs(); +  /* increase number of destination unreachable messages attempted to send */ +  snmp_inc_icmpouttimeexcds(); +  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); +  pbuf_free(q); +} + +#endif /* LWIP_ICMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/igmp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/igmp.c new file mode 100644 index 000000000..7c07bc465 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/igmp.c @@ -0,0 +1,757 @@ +/** + * @file + * IGMP - Internet Group Management Protocol + * + */ + +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without  + * modification, are permitted provided that the following conditions  + * are met:  + * 1. Redistributions of source code must retain the above copyright  + *    notice, this list of conditions and the following disclaimer.  + * 2. Redistributions in binary form must reproduce the above copyright  + *    notice, this list of conditions and the following disclaimer in the  + *    documentation and/or other materials provided with the distribution.  + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors  + *    may be used to endorse or promote products derived from this software  + *    without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  + * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE  + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  + * SUCH DAMAGE.  + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +/*------------------------------------------------------------- +Note 1) +Although the rfc requires V1 AND V2 capability +we will only support v2 since now V1 is very old (August 1989) +V1 can be added if required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 2) +A query for a specific group address (as opposed to ALLHOSTS) +has now been implemented as I am unsure if it is required + +a debug print and statistic have been implemented to +show this up. +------------------------------------------------------------- +------------------------------------------------------------- +Note 3) +The router alert rfc 2113 is implemented in outgoing packets +but not checked rigorously incoming +------------------------------------------------------------- +Steve Reynolds +------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * RFC 988  - Host extensions for IP multicasting                         - V0 + * RFC 1054 - Host extensions for IP multicasting                         - + * RFC 1112 - Host extensions for IP multicasting                         - V1 + * RFC 2236 - Internet Group Management Protocol, Version 2               - V2  <- this code is based on this RFC (it's the "de facto" standard) + * RFC 3376 - Internet Group Management Protocol, Version 3               - V3 + * RFC 4604 - Using Internet Group Management Protocol Version 3...       - V3+ + * RFC 2113 - IP Router Alert Option                                      -  + *----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + * Includes + *----------------------------------------------------------------------------*/ + +#include "lwip/opt.h" + +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/igmp.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/stats.h" + +#include "string.h" + +/*----------------------------------------------------------------------------- + * Globales + *----------------------------------------------------------------------------*/ + +static struct igmp_group* igmp_group_list; +static struct ip_addr     allsystems; +static struct ip_addr     allrouters; + +/** + * Initialize the IGMP module + */ +void +igmp_init(void) +{ +  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); + +  IP4_ADDR(&allsystems, 224, 0, 0, 1); +  IP4_ADDR(&allrouters, 224, 0, 0, 2); +} + +#ifdef LWIP_DEBUG +/** + * Dump global IGMP groups list + */ +void +igmp_dump_group_list() +{  +  struct igmp_group *group = igmp_group_list; + +  while (group != NULL) { +    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); +    ip_addr_debug_print(IGMP_DEBUG, &group->group_address); +    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface)); +    group = group->next; +  } +  LWIP_DEBUGF(IGMP_DEBUG, ("\n")); +} +#else +#define igmp_dump_group_list() +#endif /* LWIP_DEBUG */ + +/** + * Start IGMP processing on interface + * + * @param netif network interface on which start IGMP processing + */ +err_t +igmp_start(struct netif *netif) +{ +  struct igmp_group* group; + +  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); + +  group = igmp_lookup_group(netif, &allsystems); + +  if (group != NULL) { +    group->group_state = IGMP_GROUP_IDLE_MEMBER; +    group->use++; + +    /* Allow the igmp messages at the MAC level */ +    if (netif->igmp_mac_filter != NULL) { +      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); +      ip_addr_debug_print(IGMP_DEBUG, &allsystems); +      LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); +      netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER); +    } + +    return ERR_OK; +  } + +  return ERR_MEM; +} + +/** + * Stop IGMP processing on interface + * + * @param netif network interface on which stop IGMP processing + */ +err_t +igmp_stop(struct netif *netif) +{ +  struct igmp_group *group = igmp_group_list; +  struct igmp_group *prev  = NULL; +  struct igmp_group *next; + +  /* look for groups joined on this interface further down the list */ +  while (group != NULL) { +    next = group->next; +    /* is it a group joined on this interface? */ +    if (group->interface == netif) { +      /* is it the first group of the list? */ +      if (group == igmp_group_list) { +        igmp_group_list = next; +      } +      /* is there a "previous" group defined? */ +      if (prev != NULL) { +        prev->next = next; +      } +      /* disable the group at the MAC level */ +      if (netif->igmp_mac_filter != NULL) { +        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); +        ip_addr_debug_print(IGMP_DEBUG, &group->group_address); +        LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); +        netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); +      } +      /* free group */ +      memp_free(MEMP_IGMP_GROUP, group); +    } else { +      /* change the "previous" */ +      prev = group; +    } +    /* move to "next" */ +    group = next; +  } +  return ERR_OK; +} + +/** + * Report IGMP memberships for this interface + * + * @param netif network interface on which report IGMP memberships + */ +void +igmp_report_groups( struct netif *netif) +{ +  struct igmp_group *group = igmp_group_list; + +  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); + +  while (group != NULL) { +    if (group->interface == netif) { +      igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR); +    } +    group = group->next; +  } +} + +/** + * Search for a group in the global igmp_group_list + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search for + * @return a struct igmp_group* if the group has been found, + *         NULL if the group wasn't found. + */ +struct igmp_group * +igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr) +{ +  struct igmp_group *group = igmp_group_list; + +  while (group != NULL) { +    if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { +      return group; +    } +    group = group->next; +  } + +  /* to be clearer, we return NULL here instead of +   * 'group' (which is also NULL at this point). +   */ +  return NULL; +} + +/** + * Search for a specific igmp group and create a new one if not found- + * + * @param ifp the network interface for which to look + * @param addr the group ip address to search + * @return a struct igmp_group*, + *         NULL on memory error. + */ +struct igmp_group * +igmp_lookup_group(struct netif *ifp, struct ip_addr *addr) +{ +  struct igmp_group *group = igmp_group_list; +   +  /* Search if the group already exists */ +  group = igmp_lookfor_group(ifp, addr); +  if (group != NULL) { +    /* Group already exists. */ +    return group; +  } + +  /* Group doesn't exist yet, create a new one */ +  group = memp_malloc(MEMP_IGMP_GROUP); +  if (group != NULL) { +    group->interface          = ifp; +    ip_addr_set(&(group->group_address), addr); +    group->timer              = 0; /* Not running */ +    group->group_state        = IGMP_GROUP_NON_MEMBER; +    group->last_reporter_flag = 0; +    group->use                = 0; +    group->next               = igmp_group_list; +     +    igmp_group_list = group; +  } + +  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); +  ip_addr_debug_print(IGMP_DEBUG, addr); +  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); + +  return group; +} + +/** + * Remove a group in the global igmp_group_list + * + * @param group the group to remove from the global igmp_group_list + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +err_t +igmp_remove_group(struct igmp_group *group) +{ +  err_t err = ERR_OK; + +  /* Is it the first group? */ +  if (igmp_group_list == group) { +    igmp_group_list = group->next; +  } else { +    /* look for group further down the list */ +    struct igmp_group *tmpGroup; +    for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { +      if (tmpGroup->next == group) { +        tmpGroup->next = group->next; +        break; +      } +    } +    /* Group not found in the global igmp_group_list */ +    if (tmpGroup == NULL) +      err = ERR_ARG; +  } +  /* free group */ +  memp_free(MEMP_IGMP_GROUP, group); + +  return err; +} + +/** + * Called from ip_input() if a new IGMP packet is received. + * + * @param p received igmp packet, p->payload pointing to the ip header + * @param inp network interface on which the packet was received + * @param dest destination ip address of the igmp packet + */ +void +igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) +{ +  struct ip_hdr *    iphdr; +  struct igmp_msg*   igmp; +  struct igmp_group* group; +  struct igmp_group* groupref; + +  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */     +  iphdr = p->payload; +  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { +    pbuf_free(p); +    IGMP_STATS_INC(igmp.lenerr); +    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); +    return; +  } + +  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); +  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); +  LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); +  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); +  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); + +  /* Now calculate and check the checksum */ +  igmp = (struct igmp_msg *)p->payload; +  if (inet_chksum(igmp, p->len)) { +    pbuf_free(p); +    IGMP_STATS_INC(igmp.chkerr); +    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); +    return; +  } + +  /* Packet is ok so find an existing group */ +  group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */ +   +  /* If group can be found or create... */ +  if (!group) { +    pbuf_free(p); +    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); +    return; +  } + +  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ +  switch (igmp->igmp_msgtype) { +   case IGMP_MEMB_QUERY: { +     /* IGMP_MEMB_QUERY to the "all systems" address ? */ +     if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) { +       /* THIS IS THE GENERAL QUERY */ +       LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); + +       if (igmp->igmp_maxresp == 0) { +         IGMP_STATS_INC(igmp.v1_rxed); +         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); +         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; +       } + +       IGMP_STATS_INC(igmp.group_query_rxed); +       groupref = igmp_group_list; +       while (groupref) { +         /* Do not send messages on the all systems group address! */ +         if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { +           igmp_delaying_member( groupref, igmp->igmp_maxresp); +         } +         groupref = groupref->next; +       } +     } else { +       /* IGMP_MEMB_QUERY to a specific group ? */ +       if (group->group_address.addr != 0) { +         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); +         ip_addr_debug_print(IGMP_DEBUG, &group->group_address); +         if (ip_addr_cmp (dest, &allsystems)) { +           LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); +           /* we first need to re-lookfor the group since we used dest last time */ +           group = igmp_lookfor_group(inp, &igmp->igmp_group_address); +         } else { +           LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); +         } + +         if (group != NULL) { +           IGMP_STATS_INC(igmp.unicast_query); +           igmp_delaying_member( group, igmp->igmp_maxresp); +         } +       } +     } +     break; +   } +   case IGMP_V2_MEMB_REPORT: { +     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); + +     IGMP_STATS_INC(igmp.report_rxed); +     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { +       /* This is on a specific group we have already looked up */ +       group->timer = 0; /* stopped */ +       group->group_state = IGMP_GROUP_IDLE_MEMBER; +       group->last_reporter_flag = 0; +     } +     break; +   } +   default: { +     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", +       igmp->igmp_msgtype, group->group_state, &group, group->interface)); +     break; +   } +  } + +  pbuf_free(p); +  return; +} + +/** + * Join a group on one network interface. + * + * @param ifaddr ip address of the network interface which should join a new group + * @param groupaddr the ip address of the group which to join + * @return ERR_OK if group was joined on the netif(s), an err_t otherwise + */ +err_t +igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) +{ +  err_t              err = ERR_VAL; /* no matching interface */ +  struct igmp_group *group; +  struct netif      *netif; + +  /* make sure it is multicast address */ +  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); +  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + +  /* loop through netif's */ +  netif = netif_list; +  while (netif != NULL) { +    /* Should we join this interface ? */ +    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { +      /* find group or create a new one if not found */ +      group = igmp_lookup_group(netif, groupaddr); + +      if (group != NULL) { +        /* This should create a new group, check the state to make sure */ +        if (group->group_state != IGMP_GROUP_NON_MEMBER) { +          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n")); +        } else { +          /* OK - it was new group */ +          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: ")); +          ip_addr_debug_print(IGMP_DEBUG, groupaddr); +          LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + +          /* If first use of the group, allow the group at the MAC level */ +          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { +            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); +            ip_addr_debug_print(IGMP_DEBUG, groupaddr); +            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); +            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); +          } + +          IGMP_STATS_INC(igmp.join_sent); +          igmp_send(group, IGMP_V2_MEMB_REPORT); + +          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); + +          /* Need to work out where this timer comes from */ +          group->group_state = IGMP_GROUP_DELAYING_MEMBER; +        } +        /* Increment group use */ +        group->use++; +        /* Join on this interface */ +        err = ERR_OK; +      } else { +        /* Return an error even if some network interfaces are joined */ +        /** @todo undo any other netif already joined */ +        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n")); +        return ERR_MEM; +      } +    } +    /* proceed to next network interface */ +    netif = netif->next; +  } + +  return err; +} + +/** + * Leave a group on one network interface. + * + * @param ifaddr ip address of the network interface which should leave a group + * @param groupaddr the ip address of the group which to leave + * @return ERR_OK if group was left on the netif(s), an err_t otherwise + */ +err_t +igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) +{ +  err_t              err = ERR_VAL; /* no matching interface */ +  struct igmp_group *group; +  struct netif      *netif; + +  /* make sure it is multicast address */ +  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); +  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); + +  /* loop through netif's */ +  netif = netif_list; +  while (netif != NULL) { +    /* Should we leave this interface ? */ +    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { +      /* find group */ +      group = igmp_lookfor_group(netif, groupaddr); + +      if (group != NULL) { +        /* Only send a leave if the flag is set according to the state diagram */ +        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: ")); +        ip_addr_debug_print(IGMP_DEBUG, groupaddr); +        LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + +        /* If there is no other use of the group */ +        if (group->use <= 1) { +          /* If we are the last reporter for this group */ +          if (group->last_reporter_flag) { +            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); +            IGMP_STATS_INC(igmp.leave_sent); +            igmp_send(group, IGMP_LEAVE_GROUP); +          } +           +          /* Disable the group at the MAC level */ +          if (netif->igmp_mac_filter != NULL) { +            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); +            ip_addr_debug_print(IGMP_DEBUG, groupaddr); +            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); +            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); +          } +           +          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: ")); +          ip_addr_debug_print(IGMP_DEBUG, groupaddr); +          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));           +           +          /* Free the group */ +          igmp_remove_group(group); +        } else { +          /* Decrement group use */ +          group->use--; +        } +        /* Leave on this interface */ +        err = ERR_OK; +      } else { +        /* It's not a fatal error on "leavegroup" */ +        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n")); +      } +    } +    /* proceed to next network interface */ +    netif = netif->next; +  } + +  return err; +} + +/** + * The igmp timer function (both for NO_SYS=1 and =0) + * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). + */ +void +igmp_tmr(void) +{ +  struct igmp_group *group = igmp_group_list; + +  while (group != NULL) { +    if (group->timer != 0) { +      group->timer -= 1; +      if (group->timer == 0) { +        igmp_timeout(group); +      } +    } +    group = group->next; +  } +} + +/** + * Called if a timeout for one group is reached. + * Sends a report for this group. + * + * @param group an igmp_group for which a timeout is reached + */ +void +igmp_timeout(struct igmp_group *group) +{ +  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ +  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { +    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); +    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); +    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface)); + +    igmp_send(group, IGMP_V2_MEMB_REPORT); +  } +} + +/** + * Start a timer for an igmp group + * + * @param group the igmp_group for which to start a timer + * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with + *        every call to igmp_tmr()) + */ +void +igmp_start_timer(struct igmp_group *group, u8_t max_time) +{ +  /** +   * @todo Important !! this should be random 0 -> max_time. Find out how to do this +   */ +  group->timer = max_time; +} + +/** + * Stop a timer for an igmp_group + * + * @param group the igmp_group for which to stop the timer + */ +void +igmp_stop_timer(struct igmp_group *group) +{ +  group->timer = 0; +} + +/** + * Delaying membership report for a group if necessary + * + * @param group the igmp_group for which "delaying" membership report + * @param maxresp query delay + */ +void +igmp_delaying_member( struct igmp_group *group, u8_t maxresp) +{ +  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || +     ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) { +    igmp_start_timer(group, (maxresp)/2); +    group->group_state = IGMP_GROUP_DELAYING_MEMBER; +  } +} + + +/** + * Sends an IP packet on a network interface. This function constructs the IP header + * and calculates the IP header checksum. If the source IP address is NULL, + * the IP address of the outgoing network interface is filled in as source address. + * + * @param p the packet to send (p->payload points to the data, e.g. next +            protocol header; if dest == IP_HDRINCL, p already includes an IP +            header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + *         IP  address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + *         ERR_BUF if p doesn't have enough space for IP/LINK headers + *         returns errors returned by netif->output + */ +err_t +igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +                  u8_t ttl, u8_t proto, struct netif *netif) +{ +  /* This is the "router alert" option */ +  u16_t ra[2]; +  ra[0] = htons (ROUTER_ALERT); +  ra[1] = 0x0000; /* Router shall examine packet */ +  return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN); +} + +/** + * Send an igmp packet to a specific group. + * + * @param group the group to which to send the packet + * @param type the type of igmp packet to send + */ +void +igmp_send(struct igmp_group *group, u8_t type) +{ +  struct pbuf*     p    = NULL; +  struct igmp_msg* igmp = NULL; +  struct ip_addr   src  = {0}; +  struct ip_addr*  dest = NULL; + +  /* IP header + "router alert" option + IGMP header */ +  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); +   +  if (p) { +    igmp = p->payload; +    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", +               (p->len >= sizeof(struct igmp_msg))); +    ip_addr_set(&src, &((group->interface)->ip_addr)); +      +    if (type == IGMP_V2_MEMB_REPORT) { +      dest = &(group->group_address); +      IGMP_STATS_INC(igmp.report_sent); +      ip_addr_set(&(igmp->igmp_group_address), &(group->group_address)); +      group->last_reporter_flag = 1; /* Remember we were the last to report */ +    } else { +      if (type == IGMP_LEAVE_GROUP) { +        dest = &allrouters; +        ip_addr_set(&(igmp->igmp_group_address), &(group->group_address)); +      } +    } + +    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { +      igmp->igmp_msgtype  = type; +      igmp->igmp_maxresp  = 0; +      igmp->igmp_checksum = 0; +      igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN); + +      igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface); +    } + +    pbuf_free(p); +  } else { +    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); +  } +} + +#endif /* LWIP_IGMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/inet.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/inet.c new file mode 100644 index 000000000..69baf1d50 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/inet.c @@ -0,0 +1,278 @@ +/** + * @file + * Functions common to all TCP/IPv4 modules, such as the byte order functions. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/inet.h" + +/* Here for now until needed in other places in lwIP */ +#ifndef isprint +#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c)           in_range(c, 0x20, 0x7f) +#define isdigit(c)           in_range(c, '0', '9') +#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c)           in_range(c, 'a', 'z') +#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#endif     +     +/** + * Ascii internet address interpretation routine. + * The value returned is in network order. + * + * @param cp IP address in ascii represenation (e.g. "127.0.0.1") + * @return ip address in network order + */ +u32_t +inet_addr(const char *cp) +{ +  struct in_addr val; + +  if (inet_aton(cp, &val)) { +    return (val.s_addr); +  } +  return (INADDR_NONE); +} + +/** + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + * + * @param cp IP address in ascii represenation (e.g. "127.0.0.1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +inet_aton(const char *cp, struct in_addr *addr) +{ +  u32_t val; +  u8_t base; +  char c; +  u32_t parts[4]; +  u32_t *pp = parts; + +  c = *cp; +  for (;;) { +    /* +     * Collect number up to ``.''. +     * Values are specified as for C: +     * 0x=hex, 0=octal, 1-9=decimal. +     */ +    if (!isdigit(c)) +      return (0); +    val = 0; +    base = 10; +    if (c == '0') { +      c = *++cp; +      if (c == 'x' || c == 'X') { +        base = 16; +        c = *++cp; +      } else +        base = 8; +    } +    for (;;) { +      if (isdigit(c)) { +        val = (val * base) + (int)(c - '0'); +        c = *++cp; +      } else if (base == 16 && isxdigit(c)) { +        val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); +        c = *++cp; +      } else +        break; +    } +    if (c == '.') { +      /* +       * Internet format: +       *  a.b.c.d +       *  a.b.c   (with c treated as 16 bits) +       *  a.b (with b treated as 24 bits) +       */ +      if (pp >= parts + 3) +        return (0); +      *pp++ = val; +      c = *++cp; +    } else +      break; +  } +  /* +   * Check for trailing characters. +   */ +  if (c != '\0' && !isspace(c)) +    return (0); +  /* +   * Concoct the address according to +   * the number of parts specified. +   */ +  switch (pp - parts + 1) { + +  case 0: +    return (0);       /* initial nondigit */ + +  case 1:             /* a -- 32 bits */ +    break; + +  case 2:             /* a.b -- 8.24 bits */ +    if (val > 0xffffffUL) +      return (0); +    val |= parts[0] << 24; +    break; + +  case 3:             /* a.b.c -- 8.8.16 bits */ +    if (val > 0xffff) +      return (0); +    val |= (parts[0] << 24) | (parts[1] << 16); +    break; + +  case 4:             /* a.b.c.d -- 8.8.8.8 bits */ +    if (val > 0xff) +      return (0); +    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); +    break; +  } +  if (addr) +    addr->s_addr = htonl(val); +  return (1); +} + +/** + * Convert numeric IP address into decimal dotted ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + *         represenation of addr + */ +char * +inet_ntoa(struct in_addr addr) +{ +  static char str[16]; +  u32_t s_addr = addr.s_addr; +  char inv[3]; +  char *rp; +  u8_t *ap; +  u8_t rem; +  u8_t n; +  u8_t i; + +  rp = str; +  ap = (u8_t *)&s_addr; +  for(n = 0; n < 4; n++) { +    i = 0; +    do { +      rem = *ap % (u8_t)10; +      *ap /= (u8_t)10; +      inv[i++] = '0' + rem; +    } while(*ap); +    while(i--) +      *rp++ = inv[i]; +    *rp++ = '.'; +    ap++; +  } +  *--rp = 0; +  return str; +} + +/** + * These are reference implementations of the byte swapping functions. + * Again with the aim of being simple, correct and fully portable. + * Byte swapping is the second thing you would want to optimize. You will + * need to port it to your architecture and in your cc.h: + *  + * #define LWIP_PLATFORM_BYTESWAP 1 + * #define LWIP_PLATFORM_HTONS(x) <your_htons> + * #define LWIP_PLATFORM_HTONL(x) <your_htonl> + * + * Note ntohs() and ntohl() are merely references to the htonx counterparts. + */ + +#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) + +/** + * Convert an u16_t from host- to network byte order. + * + * @param n u16_t in host byte order + * @return n in network byte order + */ +u16_t +htons(u16_t n) +{ +  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); +} + +/** + * Convert an u16_t from network- to host byte order. + * + * @param n u16_t in network byte order + * @return n in host byte order + */ +u16_t +ntohs(u16_t n) +{ +  return htons(n); +} + +/** + * Convert an u32_t from host- to network byte order. + * + * @param n u32_t in host byte order + * @return n in network byte order + */ +u32_t +htonl(u32_t n) +{ +  return ((n & 0xff) << 24) | +    ((n & 0xff00) << 8) | +    ((n & 0xff0000UL) >> 8) | +    ((n & 0xff000000UL) >> 24); +} + +/** + * Convert an u32_t from network- to host byte order. + * + * @param n u32_t in network byte order + * @return n in host byte order + */ +u32_t +ntohl(u32_t n) +{ +  return htonl(n); +} + +#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/inet_chksum.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/inet_chksum.c new file mode 100644 index 000000000..185881efd --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/inet_chksum.c @@ -0,0 +1,438 @@ +/** + * @file + * Incluse internet checksum functions. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/inet_chksum.h" +#include "lwip/inet.h" + +#include <stddef.h> + +/* These are some reference implementations of the checksum algorithm, with the + * aim of being simple, correct and fully portable. Checksumming is the + * first thing you would want to optimize for your platform. If you create + * your own version, link it in and in your cc.h put: + *  + * #define LWIP_CHKSUM <your_checksum_routine>  + * + * Or you can select from the implementations below by defining + * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. + */ + +#ifndef LWIP_CHKSUM +# define LWIP_CHKSUM lwip_standard_chksum +# ifndef LWIP_CHKSUM_ALGORITHM +#  define LWIP_CHKSUM_ALGORITHM 1 +# endif +#endif +/* If none set: */ +#ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 0 +#endif + +/** Like the name says... */ +#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) +/* little endian and PLATFORM_BYTESWAP defined */ +#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) +#else +/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ +#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8) +#endif + +/** Split an u32_t in two u16_ts and add them up */ +#define FOLD_U32T(u)          ((u >> 16) + (u & 0x0000ffffUL)) + +#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ +/** + * lwip checksum + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum)  + * + * @note accumulator size limits summable length to 64k + * @note host endianess is irrelevant (p3 RFC1071) + */ +static u16_t +lwip_standard_chksum(void *dataptr, u16_t len) +{ +  u32_t acc; +  u16_t src; +  u8_t *octetptr; + +  acc = 0; +  /* dataptr may be at odd or even addresses */ +  octetptr = (u8_t*)dataptr; +  while (len > 1) { +    /* declare first octet as most significant +       thus assume network order, ignoring host order */ +    src = (*octetptr) << 8; +    octetptr++; +    /* declare second octet as least significant */ +    src |= (*octetptr); +    octetptr++; +    acc += src; +    len -= 2; +  } +  if (len > 0) { +    /* accumulate remaining octet */ +    src = (*octetptr) << 8; +    acc += src; +  } +  /* add deferred carry bits */ +  acc = (acc >> 16) + (acc & 0x0000ffffUL); +  if ((acc & 0xffff0000UL) != 0) { +    acc = (acc >> 16) + (acc & 0x0000ffffUL); +  } +  /* This maybe a little confusing: reorder sum using htons() +     instead of ntohs() since it has a little less call overhead. +     The caller must invert bits for Internet sum ! */ +  return htons((u16_t)acc); +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ +/* + * Curt McDowell + * Broadcom Corp. + * csm@broadcom.com + * + * IP checksum two bytes at a time with support for + * unaligned buffer. + * Works for len up to and including 0x20000. + * by Curt McDowell, Broadcom Corp. 12/08/2005 + * + * @param dataptr points to start of data to be summed at any boundary + * @param len length of data to be summed + * @return host order (!) lwip checksum (non-inverted Internet sum)  + */ + +static u16_t +lwip_standard_chksum(void *dataptr, int len) +{ +  u8_t *pb = dataptr; +  u16_t *ps, t = 0; +  u32_t sum = 0; +  int odd = ((u32_t)pb & 1); + +  /* Get aligned to u16_t */ +  if (odd && len > 0) { +    ((u8_t *)&t)[1] = *pb++; +    len--; +  } + +  /* Add the bulk of the data */ +  ps = (u16_t *)pb; +  while (len > 1) { +    sum += *ps++; +    len -= 2; +  } + +  /* Consume left-over byte, if any */ +  if (len > 0) { +    ((u8_t *)&t)[0] = *(u8_t *)ps;; +  } + +  /* Add end bytes */ +  sum += t; + +  /* Fold 32-bit sum to 16 bits +     calling this twice is propably faster than if statements... */ +  sum = FOLD_U32T(sum); +  sum = FOLD_U32T(sum); + +  /* Swap if alignment was odd */ +  if (odd) { +    sum = SWAP_BYTES_IN_WORD(sum); +  } + +  return sum; +} +#endif + +#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ +/** + * An optimized checksum routine. Basically, it uses loop-unrolling on + * the checksum loop, treating the head and tail bytes specially, whereas + * the inner loop acts on 8 bytes at a time.  + * + * @arg start of buffer to be checksummed. May be an odd byte address. + * @len number of bytes in the buffer to be checksummed. + * @return host order (!) lwip checksum (non-inverted Internet sum)  + *  + * by Curt McDowell, Broadcom Corp. December 8th, 2005 + */ + +static u16_t +lwip_standard_chksum(void *dataptr, int len) +{ +  u8_t *pb = dataptr; +  u16_t *ps, t = 0; +  u32_t *pl; +  u32_t sum = 0, tmp; +  /* starts at odd byte address? */ +  int odd = ((u32_t)pb & 1); + +  if (odd && len > 0) { +    ((u8_t *)&t)[1] = *pb++; +    len--; +  } + +  ps = (u16_t *)pb; + +  if (((u32_t)ps & 3) && len > 1) { +    sum += *ps++; +    len -= 2; +  } + +  pl = (u32_t *)ps; + +  while (len > 7)  { +    tmp = sum + *pl++;          /* ping */ +    if (tmp < sum) { +      tmp++;                    /* add back carry */ +    } + +    sum = tmp + *pl++;          /* pong */ +    if (sum < tmp) { +      sum++;                    /* add back carry */ +    } + +    len -= 8; +  } + +  /* make room in upper bits */ +  sum = FOLD_U32T(sum); + +  ps = (u16_t *)pl; + +  /* 16-bit aligned word remaining? */ +  while (len > 1) { +    sum += *ps++; +    len -= 2; +  } + +  /* dangling tail byte remaining? */ +  if (len > 0) {                /* include odd byte */ +    ((u8_t *)&t)[0] = *(u8_t *)ps; +  } + +  sum += t;                     /* add end bytes */ + +  /* Fold 32-bit sum to 16 bits +     calling this twice is propably faster than if statements... */ +  sum = FOLD_U32T(sum); +  sum = FOLD_U32T(sum); + +  if (odd) { +    sum = SWAP_BYTES_IN_WORD(sum); +  } + +  return sum; +} +#endif + +/* inet_chksum_pseudo: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len) +{ +  u32_t acc; +  struct pbuf *q; +  u8_t swapped; + +  acc = 0; +  swapped = 0; +  /* iterate through all pbuf in chain */ +  for(q = p; q != NULL; q = q->next) { +    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", +      (void *)q, (void *)q->next)); +    acc += LWIP_CHKSUM(q->payload, q->len); +    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ +    /* just executing this next line is probably faster that the if statement needed +       to check whether we really need to execute it, and does no harm */ +    acc = FOLD_U32T(acc); +    if (q->len % 2 != 0) { +      swapped = 1 - swapped; +      acc = SWAP_BYTES_IN_WORD(acc); +    } +    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ +  } + +  if (swapped) { +    acc = SWAP_BYTES_IN_WORD(acc); +  } +  acc += (src->addr & 0xffffUL); +  acc += ((src->addr >> 16) & 0xffffUL); +  acc += (dest->addr & 0xffffUL); +  acc += ((dest->addr >> 16) & 0xffffUL); +  acc += (u32_t)htons((u16_t)proto); +  acc += (u32_t)htons(proto_len); + +  /* Fold 32-bit sum to 16 bits +     calling this twice is propably faster than if statements... */ +  acc = FOLD_U32T(acc); +  acc = FOLD_U32T(acc); +  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); +  return (u16_t)~(acc & 0xffffUL); +} + +/* inet_chksum_pseudo: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +/* Currently only used by UDPLITE, although this could change in the future. */ +#if LWIP_UDPLITE +u16_t +inet_chksum_pseudo_partial(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len, u16_t chksum_len) +{ +  u32_t acc; +  struct pbuf *q; +  u8_t swapped; +  u16_t chklen; + +  acc = 0; +  swapped = 0; +  /* iterate through all pbuf in chain */ +  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { +    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", +      (void *)q, (void *)q->next)); +    chklen = q->len; +    if (chklen > chksum_len) { +      chklen = chksum_len; +    } +    acc += LWIP_CHKSUM(q->payload, chklen); +    chksum_len -= chklen; +    LWIP_ASSERT("delete me", chksum_len < 0x7fff); +    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ +    /* fold the upper bit down */ +    acc = FOLD_U32T(acc); +    if (q->len % 2 != 0) { +      swapped = 1 - swapped; +      acc = SWAP_BYTES_IN_WORD(acc); +    } +    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ +  } + +  if (swapped) { +    acc = SWAP_BYTES_IN_WORD(acc); +  } +  acc += (src->addr & 0xffffUL); +  acc += ((src->addr >> 16) & 0xffffUL); +  acc += (dest->addr & 0xffffUL); +  acc += ((dest->addr >> 16) & 0xffffUL); +  acc += (u32_t)htons((u16_t)proto); +  acc += (u32_t)htons(proto_len); + +  /* Fold 32-bit sum to 16 bits +     calling this twice is propably faster than if statements... */ +  acc = FOLD_U32T(acc); +  acc = FOLD_U32T(acc); +  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); +  return (u16_t)~(acc & 0xffffUL); +} +#endif /* LWIP_UDPLITE */ + +/* inet_chksum: + * + * Calculates the Internet checksum over a portion of memory. Used primarily for IP + * and ICMP. + * + * @param dataptr start of the buffer to calculate the checksum (no alignment needed) + * @param len length of the buffer to calculate the checksum + * @return checksum (as u16_t) to be saved directly in the protocol header + */ + +u16_t +inet_chksum(void *dataptr, u16_t len) +{ +  return ~LWIP_CHKSUM(dataptr, len); +} + +/** + * Calculate a checksum over a chain of pbufs (without pseudo-header, much like + * inet_chksum only pbufs are used). + * + * @param p pbuf chain over that the checksum should be calculated + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pbuf(struct pbuf *p) +{ +  u32_t acc; +  struct pbuf *q; +  u8_t swapped; + +  acc = 0; +  swapped = 0; +  for(q = p; q != NULL; q = q->next) { +    acc += LWIP_CHKSUM(q->payload, q->len); +    acc = FOLD_U32T(acc); +    if (q->len % 2 != 0) { +      swapped = 1 - swapped; +      acc = SWAP_BYTES_IN_WORD(acc); +    } +  } + +  if (swapped) { +    acc = SWAP_BYTES_IN_WORD(acc); +  } +  return (u16_t)~(acc & 0xffffUL); +} diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip.c new file mode 100644 index 000000000..7e404a9f3 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip.c @@ -0,0 +1,749 @@ +/** + * @file + * This is the IPv4 layer implementation for incoming and outgoing IP traffic. + *  + * @see ip_frag.c + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip_frag.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/igmp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/stats.h" +#include "arch/perf.h" + +#include <string.h> + +/** + * The interface that provided the packet for the current callback + * invocation. + */ +static struct netif *current_netif; + +/** + * Header of the input packet currently being processed. + */ +static const struct ip_hdr *current_header; + +/** + * Get the interface that received the current packet. + * + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. + * + * @param pcb Pointer to the pcb receiving a packet. + */ +struct netif * +ip_current_netif(void) +{ +  return current_netif; +} + +/** + * Get the IP header of the current packet. + * + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. + * + * @param pcb Pointer to the pcb receiving a packet. + */ +const struct ip_hdr * +ip_current_header(void) +{ +  return current_header; +} + +/** + * Finds the appropriate network interface for a given IP address. It + * searches the list of network interfaces linearly. A match is found + * if the masked IP address of the network interface equals the masked + * IP address given to the function. + * + * @param dest the destination IP address for which to find the route + * @return the netif on which to send to reach dest + */ +struct netif * +ip_route(struct ip_addr *dest) +{ +  struct netif *netif; + +  /* iterate through netifs */ +  for(netif = netif_list; netif != NULL; netif = netif->next) { +    /* network mask matches? */ +    if (netif_is_up(netif)) { +      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { +        /* return netif on which to forward IP packet */ +        return netif; +      } +    } +  } +  if ((netif_default == NULL) || (!netif_is_up(netif_default))) { +    LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr)); +    IP_STATS_INC(ip.rterr); +    snmp_inc_ipoutnoroutes(); +    return NULL; +  } +  /* no matching netif found, use default netif */ +  return netif_default; +} + +#if IP_FORWARD +/** + * Forwards an IP packet. It finds an appropriate route for the + * packet, decrements the TTL value of the packet, adjusts the + * checksum and outputs the packet on the appropriate interface. + * + * @param p the packet to forward (p->payload points to IP header) + * @param iphdr the IP header of the input packet + * @param inp the netif on which this packet was received + * @return the netif on which the packet was sent (NULL if it wasn't sent) + */ +static struct netif * +ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) +{ +  struct netif *netif; + +  PERF_START; +  /* Find network interface where to forward this IP packet to. */ +  netif = ip_route((struct ip_addr *)&(iphdr->dest)); +  if (netif == NULL) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n", +                      iphdr->dest.addr)); +    snmp_inc_ipoutnoroutes(); +    return (struct netif *)NULL; +  } +  /* Do not forward packets onto the same network interface on which +   * they arrived. */ +  if (netif == inp) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); +    snmp_inc_ipoutnoroutes(); +    return (struct netif *)NULL; +  } + +  /* decrement TTL */ +  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); +  /* send ICMP if TTL == 0 */ +  if (IPH_TTL(iphdr) == 0) { +    snmp_inc_ipinhdrerrors(); +#if LWIP_ICMP +    /* Don't send ICMP messages in response to ICMP messages */ +    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { +      icmp_time_exceeded(p, ICMP_TE_TTL); +    } +#endif /* LWIP_ICMP */ +    return (struct netif *)NULL; +  } + +  /* Incrementally update the IP checksum. */ +  if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { +    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); +  } else { +    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100)); +  } + +  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n", +                    iphdr->dest.addr)); + +  IP_STATS_INC(ip.fw); +  IP_STATS_INC(ip.xmit); +  snmp_inc_ipforwdatagrams(); + +  PERF_STOP("ip_forward"); +  /* transmit pbuf on chosen interface */ +  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); +  return netif; +} +#endif /* IP_FORWARD */ + +/** + * This function is called by the network interface device driver when + * an IP packet is received. The function does the basic checks of the + * IP header such as packet size being at least larger than the header + * size etc. If the packet was not destined for us, the packet is + * forwarded (using ip_forward). The IP checksum is always checked. + * + * Finally, the packet is sent to the upper layer protocol input function. + *  + * @param p the received IP packet (p->payload points to IP header) + * @param inp the netif on which this packet was received + * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't + *         processed, but currently always returns ERR_OK) + */ +err_t +ip_input(struct pbuf *p, struct netif *inp) +{ +  struct ip_hdr *iphdr; +  struct netif *netif; +  u16_t iphdr_hlen; +  u16_t iphdr_len; +#if LWIP_DHCP +  int check_ip_src=1; +#endif /* LWIP_DHCP */ + +  IP_STATS_INC(ip.recv); +  snmp_inc_ipinreceives(); + +  /* identify the IP header */ +  iphdr = p->payload; +  if (IPH_V(iphdr) != 4) { +    LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); +    ip_debug_print(p); +    pbuf_free(p); +    IP_STATS_INC(ip.err); +    IP_STATS_INC(ip.drop); +    snmp_inc_ipinhdrerrors(); +    return ERR_OK; +  } + +  /* obtain IP header length in number of 32-bit words */ +  iphdr_hlen = IPH_HL(iphdr); +  /* calculate IP header length in bytes */ +  iphdr_hlen *= 4; +  /* obtain ip length in bytes */ +  iphdr_len = ntohs(IPH_LEN(iphdr)); + +  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ +  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { +    if (iphdr_hlen > p->len) +    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", +                               iphdr_hlen, p->len)); +    if (iphdr_len > p->tot_len) +    LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), " +                               "IP packet dropped.\n", +                               iphdr_len, p->tot_len)); +    /* free (drop) packet pbufs */ +    pbuf_free(p); +    IP_STATS_INC(ip.lenerr); +    IP_STATS_INC(ip.drop); +    snmp_inc_ipindiscards(); +    return ERR_OK; +  } + +  /* verify checksum */ +#if CHECKSUM_CHECK_IP +  if (inet_chksum(iphdr, iphdr_hlen) != 0) { + +    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); +    ip_debug_print(p); +    pbuf_free(p); +    IP_STATS_INC(ip.chkerr); +    IP_STATS_INC(ip.drop); +    snmp_inc_ipinhdrerrors(); +    return ERR_OK; +  } +#endif + +  /* Trim pbuf. This should have been done at the netif layer, +   * but we'll do it anyway just to be sure that its done. */ +  pbuf_realloc(p, iphdr_len); + +  /* match packet against an interface, i.e. is this packet for us? */ +#if LWIP_IGMP +  if (ip_addr_ismulticast(&(iphdr->dest))) { +    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) { +      netif = inp; +    } else { +      netif = NULL; +    } +  } else +#endif /* LWIP_IGMP */ +  { +    /* start trying with inp. if that's not acceptable, start walking the +       list of configured netifs. +       'first' is used as a boolean to mark whether we started walking the list */ +    int first = 1; +    netif = inp; +    do { +      LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", +          iphdr->dest.addr, netif->ip_addr.addr, +          iphdr->dest.addr & netif->netmask.addr, +          netif->ip_addr.addr & netif->netmask.addr, +          iphdr->dest.addr & ~(netif->netmask.addr))); + +      /* interface is up and configured? */ +      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { +        /* unicast to this interface address? */ +        if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || +            /* or broadcast on this interface network address? */ +            ip_addr_isbroadcast(&(iphdr->dest), netif)) { +          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", +              netif->name[0], netif->name[1])); +          /* break out of for loop */ +          break; +        } +      } +      if (first) { +        first = 0; +        netif = netif_list; +      } else { +        netif = netif->next; +      } +      if (netif == inp) { +        netif = netif->next; +      } +    } while(netif != NULL); +  } + +#if LWIP_DHCP +  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed +   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. +   * According to RFC 1542 section 3.1.1, referred by RFC 2131). +   */ +  if (netif == NULL) { +    /* remote port is DHCP server? */ +    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { +      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", +        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest))); +      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) { +        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n")); +        netif = inp; +        check_ip_src = 0; +      } +    } +  } +#endif /* LWIP_DHCP */ + +  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ +#if LWIP_DHCP +  if (check_ip_src) +#endif /* LWIP_DHCP */ +  {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) || +         (ip_addr_ismulticast(&(iphdr->src)))) { +      /* packet source is not valid */ +      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n")); +      /* free (drop) packet pbufs */ +      pbuf_free(p); +      IP_STATS_INC(ip.drop); +      snmp_inc_ipinaddrerrors(); +      snmp_inc_ipindiscards(); +      return ERR_OK; +    } +  } + +  /* packet not for us? */ +  if (netif == NULL) { +    /* packet not for us, route or discard */ +    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n")); +#if IP_FORWARD +    /* non-broadcast packet? */ +    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) { +      /* try to forward IP packet on (other) interfaces */ +      ip_forward(p, iphdr, inp); +    } else +#endif /* IP_FORWARD */ +    { +      snmp_inc_ipinaddrerrors(); +      snmp_inc_ipindiscards(); +    } +    pbuf_free(p); +    return ERR_OK; +  } +  /* packet consists of multiple fragments? */ +  if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { +#if IP_REASSEMBLY /* packet fragment reassembly code present? */ +    LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", +      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); +    /* reassemble the packet*/ +    p = ip_reass(p); +    /* packet not fully reassembled yet? */ +    if (p == NULL) { +      return ERR_OK; +    } +    iphdr = p->payload; +#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ +    pbuf_free(p); +    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", +      ntohs(IPH_OFFSET(iphdr)))); +    IP_STATS_INC(ip.opterr); +    IP_STATS_INC(ip.drop); +    /* unsupported protocol feature */ +    snmp_inc_ipinunknownprotos(); +    return ERR_OK; +#endif /* IP_REASSEMBLY */ +  } + +#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ + +#if LWIP_IGMP +  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ +  if((iphdr_hlen > IP_HLEN &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { +#else +  if (iphdr_hlen > IP_HLEN) { +#endif /* LWIP_IGMP */ +    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); +    pbuf_free(p); +    IP_STATS_INC(ip.opterr); +    IP_STATS_INC(ip.drop); +    /* unsupported protocol feature */ +    snmp_inc_ipinunknownprotos(); +    return ERR_OK; +  } +#endif /* IP_OPTIONS_ALLOWED == 0 */ + +  /* send to upper layers */ +  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); +  ip_debug_print(p); +  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); + +  current_netif = inp; +  current_header = iphdr; + +#if LWIP_RAW +  /* raw input did not eat the packet? */ +  if (raw_input(p, inp) == 0) +#endif /* LWIP_RAW */ +  { + +    switch (IPH_PROTO(iphdr)) { +#if LWIP_UDP +    case IP_PROTO_UDP: +#if LWIP_UDPLITE +    case IP_PROTO_UDPLITE: +#endif /* LWIP_UDPLITE */ +      snmp_inc_ipindelivers(); +      udp_input(p, inp); +      break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +    case IP_PROTO_TCP: +      snmp_inc_ipindelivers(); +      tcp_input(p, inp); +      break; +#endif /* LWIP_TCP */ +#if LWIP_ICMP +    case IP_PROTO_ICMP: +      snmp_inc_ipindelivers(); +      icmp_input(p, inp); +      break; +#endif /* LWIP_ICMP */ +#if LWIP_IGMP +    case IP_PROTO_IGMP: +      igmp_input(p,inp,&(iphdr->dest)); +      break; +#endif /* LWIP_IGMP */ +    default: +#if LWIP_ICMP +      /* send ICMP destination protocol unreachable unless is was a broadcast */ +      if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && +          !ip_addr_ismulticast(&(iphdr->dest))) { +        p->payload = iphdr; +        icmp_dest_unreach(p, ICMP_DUR_PROTO); +      } +#endif /* LWIP_ICMP */ +      pbuf_free(p); + +      LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); + +      IP_STATS_INC(ip.proterr); +      IP_STATS_INC(ip.drop); +      snmp_inc_ipinunknownprotos(); +    } +  } + +  current_netif = NULL; +  current_header = NULL; + +  return ERR_OK; +} + +/** + * Sends an IP packet on a network interface. This function constructs + * the IP header and calculates the IP header checksum. If the source + * IP address is NULL, the IP address of the outgoing network + * interface is filled in as source address. + * If the destination IP address is IP_HDRINCL, p is assumed to already + * include an IP header and p->payload points to it instead of the data. + * + * @param p the packet to send (p->payload points to the data, e.g. next +            protocol header; if dest == IP_HDRINCL, p already includes an IP +            header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + *         IP  address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + *         ERR_BUF if p doesn't have enough space for IP/LINK headers + *         returns errors returned by netif->output + * + * @note ip_id: RFC791 "some host may be able to simply use + *  unique identifiers independent of destination" + */ +err_t +ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +             u8_t ttl, u8_t tos, +             u8_t proto, struct netif *netif) +{ +#if IP_OPTIONS_SEND +  return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if() but with the possibility to include IP options: + * + * @ param ip_options pointer to the IP options, copied into the IP header + * @ param optlen length of ip_options + */ +err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, +       u16_t optlen) +{ +#endif /* IP_OPTIONS_SEND */ +  struct ip_hdr *iphdr; +  static u16_t ip_id = 0; + +  snmp_inc_ipoutrequests(); + +  /* Should the IP header be generated or is it already included in p? */ +  if (dest != IP_HDRINCL) { +    u16_t ip_hlen = IP_HLEN; +#if IP_OPTIONS_SEND +    u16_t optlen_aligned = 0; +    if (optlen != 0) { +      /* round up to a multiple of 4 */ +      optlen_aligned = ((optlen + 3) & ~3); +      ip_hlen += optlen_aligned; +      /* First write in the IP options */ +      if (pbuf_header(p, optlen_aligned)) { +        LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); +        IP_STATS_INC(ip.err); +        snmp_inc_ipoutdiscards(); +        return ERR_BUF; +      } +      MEMCPY(p->payload, ip_options, optlen); +      if (optlen < optlen_aligned) { +        /* zero the remaining bytes */ +        memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); +      } +    } +#endif /* IP_OPTIONS_SEND */ +    /* generate IP header */ +    if (pbuf_header(p, IP_HLEN)) { +      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n")); + +      IP_STATS_INC(ip.err); +      snmp_inc_ipoutdiscards(); +      return ERR_BUF; +    } + +    iphdr = p->payload; +    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", +               (p->len >= sizeof(struct ip_hdr))); + +    IPH_TTL_SET(iphdr, ttl); +    IPH_PROTO_SET(iphdr, proto); + +    ip_addr_set(&(iphdr->dest), dest); + +    IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); +    IPH_LEN_SET(iphdr, htons(p->tot_len)); +    IPH_OFFSET_SET(iphdr, 0); +    IPH_ID_SET(iphdr, htons(ip_id)); +    ++ip_id; + +    if (ip_addr_isany(src)) { +      ip_addr_set(&(iphdr->src), &(netif->ip_addr)); +    } else { +      ip_addr_set(&(iphdr->src), src); +    } + +    IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP +    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); +#endif +  } else { +    /* IP header already included in p */ +    iphdr = p->payload; +    dest = &(iphdr->dest); +  } + +#if IP_FRAG +  /* don't fragment if interface has mtu set to 0 [loopif] */ +  if (netif->mtu && (p->tot_len > netif->mtu)) +    return ip_frag(p,netif,dest); +#endif + +  IP_STATS_INC(ip.xmit); + +  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); +  ip_debug_print(p); + +#if (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) +  if (ip_addr_cmp(dest, &netif->ip_addr)) { +    /* Packet to self, enqueue it for loopback */ +    LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); + +    return netif_loop_output(netif, p, dest); +  } else +#endif /* (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) */ +  { +    LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); + +    return netif->output(netif, p, dest); +  } +} + +/** + * Simple interface to ip_output_if. It finds the outgoing network + * interface and calls upon ip_output_if to do the actual work. + * + * @param p the packet to send (p->payload points to the data, e.g. next +            protocol header; if dest == IP_HDRINCL, p already includes an IP +            header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + *         IP  address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * + * @return ERR_RTE if no route is found + *         see ip_output_if() for more return values + */ +err_t +ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +          u8_t ttl, u8_t tos, u8_t proto) +{ +  struct netif *netif; + +  if ((netif = ip_route(dest)) == NULL) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); +    IP_STATS_INC(ip.rterr); +    return ERR_RTE; +  } + +  return ip_output_if(p, src, dest, ttl, tos, proto, netif); +} + +#if LWIP_NETIF_HWADDRHINT +/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint + *  before calling ip_output_if. + * + * @param p the packet to send (p->payload points to the data, e.g. next +            protocol header; if dest == IP_HDRINCL, p already includes an IP +            header and p->payload points to that IP header) + * @param src the source IP address to send from (if src == IP_ADDR_ANY, the + *         IP  address of the netif used to send is used as source address) + * @param dest the destination IP address to send the packet to + * @param ttl the TTL value to be set in the IP header + * @param tos the TOS value to be set in the IP header + * @param proto the PROTOCOL to be set in the IP header + * @param addr_hint address hint pointer set to netif->addr_hint before + *        calling ip_output_if() + * + * @return ERR_RTE if no route is found + *         see ip_output_if() for more return values + */ +err_t +ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) +{ +  struct netif *netif; +  err_t err; + +  if ((netif = ip_route(dest)) == NULL) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); +    IP_STATS_INC(ip.rterr); +    return ERR_RTE; +  } + +  netif->addr_hint = addr_hint; +  err = ip_output_if(p, src, dest, ttl, tos, proto, netif); +  netif->addr_hint = NULL; + +  return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + +#if IP_DEBUG +/* Print an IP header by using LWIP_DEBUGF + * @param p an IP packet, p->payload pointing to the IP header + */ +void +ip_debug_print(struct pbuf *p) +{ +  struct ip_hdr *iphdr = p->payload; +  u8_t *payload; + +  payload = (u8_t *)iphdr + IP_HLEN; + +  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n", +                    IPH_V(iphdr), +                    IPH_HL(iphdr), +                    IPH_TOS(iphdr), +                    ntohs(IPH_LEN(iphdr)))); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n", +                    ntohs(IPH_ID(iphdr)), +                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, +                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, +                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, +                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n", +                    IPH_TTL(iphdr), +                    IPH_PROTO(iphdr), +                    ntohs(IPH_CHKSUM(iphdr)))); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n", +                    ip4_addr1(&iphdr->src), +                    ip4_addr2(&iphdr->src), +                    ip4_addr3(&iphdr->src), +                    ip4_addr4(&iphdr->src))); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n", +                    ip4_addr1(&iphdr->dest), +                    ip4_addr2(&iphdr->dest), +                    ip4_addr3(&iphdr->dest), +                    ip4_addr4(&iphdr->dest))); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip_addr.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip_addr.c new file mode 100644 index 000000000..94bf4678a --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip_addr.c @@ -0,0 +1,84 @@ +/** + * @file + * This is the IPv4 address tools implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/inet.h" +#include "lwip/netif.h" + +#define IP_ADDR_ANY_VALUE 0x00000000UL +#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL + +/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ +const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE }; +const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE }; + +/** + * Determine if an address is a broadcast address on a network interface  + *  + * @param addr address to be checked + * @param netif the network interface against which the address is checked + * @return returns non-zero if the address is a broadcast address + */ +u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif) +{ +  u32_t addr2test; + +  addr2test = addr->addr; +  /* all ones (broadcast) or all zeroes (old skool broadcast) */ +  if ((~addr2test == IP_ADDR_ANY_VALUE) || +      (addr2test == IP_ADDR_ANY_VALUE)) +    return 1; +  /* no broadcast support on this network interface? */ +  else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) +    /* the given address cannot be a broadcast address +     * nor can we check against any broadcast addresses */ +    return 0; +  /* address matches network interface address exactly? => no broadcast */ +  else if (addr2test == netif->ip_addr.addr) +    return 0; +  /*  on the same (sub) network... */ +  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask)) +         /* ...and host identifier bits are all ones? =>... */ +          && ((addr2test & ~netif->netmask.addr) == +           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr))) +    /* => network broadcast address */ +    return 1; +  else +    return 0; +} diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip_frag.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip_frag.c new file mode 100644 index 000000000..1939d831b --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv4/ip_frag.c @@ -0,0 +1,792 @@ +/** + * @file + * This is the IPv4 packet segmentation and reassembly implementation. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Jani Monoses <jani@iv.ro>  + *         Simon Goldschmidt + * original reassembly code by Adam Dunkels <adam@sics.se> + *  + */ + +#include "lwip/opt.h" +#include "lwip/ip_frag.h" +#include "lwip/ip.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/netif.h" +#include "lwip/snmp.h" +#include "lwip/stats.h" +#include "lwip/icmp.h" + +#include <string.h> + +#if IP_REASSEMBLY +/** + * The IP reassembly code currently has the following limitations: + * - IP header options are not supported + * - fragments must not overlap (e.g. due to different routes), + *   currently, overlapping or duplicate fragments are thrown away + *   if IP_REASS_CHECK_OVERLAP=1 (the default)! + * + * @todo: work with IP header options + */ + +/** Setting this to 0, you can turn off checking the fragments for overlapping + * regions. The code gets a little smaller. Only use this if you know that + * overlapping won't occur on your network! */ +#ifndef IP_REASS_CHECK_OVERLAP +#define IP_REASS_CHECK_OVERLAP 1 +#endif /* IP_REASS_CHECK_OVERLAP */ + +/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is + * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. + * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA + * is set to 1, so one datagram can be reassembled at a time, only. */ +#ifndef IP_REASS_FREE_OLDEST +#define IP_REASS_FREE_OLDEST 1 +#endif /* IP_REASS_FREE_OLDEST */ + +#define IP_REASS_FLAG_LASTFRAG 0x01 + +/** This is a helper struct which holds the starting + * offset and the ending offset of this fragment to + * easily chain the fragments. + * It has to be packed since it has to fit inside the IP header. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_reass_helper { +  PACK_STRUCT_FIELD(struct pbuf *next_pbuf); +  PACK_STRUCT_FIELD(u16_t start); +  PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB)  \ +  (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ +   ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ +   IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 + +/* global variables */ +static struct ip_reassdata *reassdatagrams; +static u16_t ip_reass_pbufcount; + +/* function prototypes */ +static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); +static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); + +/** + * Reassembly timer base function + * for both NO_SYS == 0 and 1 (!). + * + * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). + */ +void +ip_reass_tmr(void) +{ +  struct ip_reassdata *r, *prev = NULL; + +  r = reassdatagrams; +  while (r != NULL) { +    /* Decrement the timer. Once it reaches 0, +     * clean up the incomplete fragment assembly */ +    if (r->timer > 0) { +      r->timer--; +      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer)); +      prev = r; +      r = r->next; +    } else { +      /* reassembly timed out */ +      struct ip_reassdata *tmp; +      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); +      tmp = r; +      /* get the next pointer before freeing */ +      r = r->next; +      /* free the helper struct and all enqueued pbufs */ +      ip_reass_free_complete_datagram(tmp, prev); +     } +   } +} + +/** + * Free a datagram (struct ip_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip_reass_pbufcount), + * SNMP counters and sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + * @param prev the previous datagram in the linked list + * @return the number of pbufs freed + */ +static int +ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ +  int pbufs_freed = 0; +  struct pbuf *p; +  struct ip_reass_helper *iprh; + +  LWIP_ASSERT("prev != ipr", prev != ipr); +  if (prev != NULL) { +    LWIP_ASSERT("prev->next == ipr", prev->next == ipr); +  } + +  snmp_inc_ipreasmfails(); +#if LWIP_ICMP +  iprh = (struct ip_reass_helper *)ipr->p->payload; +  if (iprh->start == 0) { +    /* The first fragment was received, send ICMP time exceeded. */ +    /* First, de-queue the first pbuf from r->p. */ +    p = ipr->p; +    ipr->p = iprh->next_pbuf; +    /* Then, copy the original header into it. */ +    SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); +    icmp_time_exceeded(p, ICMP_TE_FRAG); +    pbufs_freed += pbuf_clen(p); +    pbuf_free(p); +  } +#endif /* LWIP_ICMP */ + +  /* First, free all received pbufs.  The individual pbufs need to be released  +     separately as they have not yet been chained */ +  p = ipr->p; +  while (p != NULL) { +    struct pbuf *pcur; +    iprh = (struct ip_reass_helper *)p->payload; +    pcur = p; +    /* get the next pointer before freeing */ +    p = iprh->next_pbuf; +    pbufs_freed += pbuf_clen(pcur); +    pbuf_free(pcur);     +  } +  /* Then, unchain the struct ip_reassdata from the list and free it. */ +  ip_reass_dequeue_datagram(ipr, prev); +  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed); +  ip_reass_pbufcount -= pbufs_freed; + +  return pbufs_freed; +} + +#if IP_REASS_FREE_OLDEST +/** + * Free the oldest datagram to make room for enqueueing new fragments. + * The datagram 'fraghdr' belongs to is not freed! + * + * @param fraghdr IP header of the current fragment + * @param pbufs_needed number of pbufs needed to enqueue + *        (used for freeing other datagrams if not enough space) + * @return the number of pbufs freed + */ +static int +ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed) +{ +  /* @todo Can't we simply remove the last datagram in the +   *       linked list behind reassdatagrams? +   */ +  struct ip_reassdata *r, *oldest, *prev; +  int pbufs_freed = 0, pbufs_freed_current; +  int other_datagrams; + +  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, +   * but don't free the datagram that 'fraghdr' belongs to! */ +  do { +    oldest = NULL; +    prev = NULL; +    other_datagrams = 0; +    r = reassdatagrams; +    while (r != NULL) { +      if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) { +        /* Not the same datagram as fraghdr */ +        other_datagrams++; +        if (oldest == NULL) { +          oldest = r; +        } else if (r->timer <= oldest->timer) { +          /* older than the previous oldest */ +          oldest = r; +        } +      } +      if (r->next != NULL) { +        prev = r; +      } +      r = r->next; +    } +    if (oldest != NULL) { +      pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev); +      pbufs_freed += pbufs_freed_current; +    } +  } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1)); +  return pbufs_freed; +} +#endif /* IP_REASS_FREE_OLDEST */ + +/** + * Enqueues a new fragment into the fragment queue + * @param fraghdr points to the new fragments IP hdr + * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space) + * @return A pointer to the queue location into which the fragment was enqueued + */ +static struct ip_reassdata* +ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) +{ +  struct ip_reassdata* ipr; +  /* No matching previous fragment found, allocate a new reassdata struct */ +  ipr = memp_malloc(MEMP_REASSDATA); +  if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST +    if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { +      ipr = memp_malloc(MEMP_REASSDATA); +    } +    if (ipr == NULL) +#endif /* IP_REASS_FREE_OLDEST */ +    { +      IPFRAG_STATS_INC(ip_frag.memerr); +      LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n")); +      return NULL; +    } +  } +  memset(ipr, 0, sizeof(struct ip_reassdata)); +  ipr->timer = IP_REASS_MAXAGE; + +  /* enqueue the new structure to the front of the list */ +  ipr->next = reassdatagrams; +  reassdatagrams = ipr; +  /* copy the ip header for later tests and input */ +  /* @todo: no ip options supported? */ +  SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN); +  return ipr; +} + +/** + * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs. + * @param ipr points to the queue entry to dequeue + */ +static void +ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) +{ +   +  /* dequeue the reass struct  */ +  if (reassdatagrams == ipr) { +    /* it was the first in the list */ +    reassdatagrams = ipr->next; +  } else { +    /* it wasn't the first, so it must have a valid 'prev' */ +    LWIP_ASSERT("sanity check linked list", prev != NULL); +    prev->next = ipr->next; +  } + +  /* now we can free the ip_reass struct */ +  memp_free(MEMP_REASSDATA, ipr); +} + +/** + * Chain a new pbuf into the pbuf list that composes the datagram.  The pbuf list + * will grow over time as  new pbufs are rx. + * Also checks that the datagram passes basic continuity checks (if the last + * fragment was received at least once). + * @param root_p points to the 'root' pbuf for the current datagram being assembled. + * @param new_p points to the pbuf for the current fragment + * @return 0 if invalid, >0 otherwise + */ +static int +ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) +{ +  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; +  struct pbuf *q; +  u16_t offset,len; +  struct ip_hdr *fraghdr; +  int valid = 1; + +  /* Extract length and fragment offset from current fragment */ +  fraghdr = (struct ip_hdr*)new_p->payload;  +  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; +  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; + +  /* overwrite the fragment's ip header from the pbuf with our helper struct, +   * and setup the embedded helper structure. */ +  /* make sure the struct ip_reass_helper fits into the IP header */ +  LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", +              sizeof(struct ip_reass_helper) <= IP_HLEN); +  iprh = (struct ip_reass_helper*)new_p->payload; +  iprh->next_pbuf = NULL; +  iprh->start = offset; +  iprh->end = offset + len; + +  /* Iterate through until we either get to the end of the list (append), +   * or we find on with a larger offset (insert). */ +  for (q = ipr->p; q != NULL;) { +    iprh_tmp = (struct ip_reass_helper*)q->payload; +    if (iprh->start < iprh_tmp->start) { +      /* the new pbuf should be inserted before this */ +      iprh->next_pbuf = q; +      if (iprh_prev != NULL) { +        /* not the fragment with the lowest offset */ +#if IP_REASS_CHECK_OVERLAP +        if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { +          /* fragment overlaps with previous or following, throw away */ +          goto freepbuf; +        } +#endif /* IP_REASS_CHECK_OVERLAP */ +        iprh_prev->next_pbuf = new_p; +      } else { +        /* fragment with the lowest offset */ +        ipr->p = new_p; +      } +      break; +    } else if(iprh->start == iprh_tmp->start) { +      /* received the same datagram twice: no need to keep the datagram */ +      goto freepbuf; +#if IP_REASS_CHECK_OVERLAP +    } else if(iprh->start < iprh_tmp->end) { +      /* overlap: no need to keep the new datagram */ +      goto freepbuf; +#endif /* IP_REASS_CHECK_OVERLAP */ +    } else { +      /* Check if the fragments received so far have no wholes. */ +      if (iprh_prev != NULL) { +        if (iprh_prev->end != iprh_tmp->start) { +          /* There is a fragment missing between the current +           * and the previous fragment */ +          valid = 0; +        } +      } +    } +    q = iprh_tmp->next_pbuf; +    iprh_prev = iprh_tmp; +  } + +  /* If q is NULL, then we made it to the end of the list. Determine what to do now */ +  if (q == NULL) { +    if (iprh_prev != NULL) { +      /* this is (for now), the fragment with the highest offset: +       * chain it to the last fragment */ +#if IP_REASS_CHECK_OVERLAP +      LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); +#endif /* IP_REASS_CHECK_OVERLAP */ +      iprh_prev->next_pbuf = new_p; +      if (iprh_prev->end != iprh->start) { +        valid = 0; +      } +    } else { +#if IP_REASS_CHECK_OVERLAP +      LWIP_ASSERT("no previous fragment, this must be the first fragment!", +        ipr->p == NULL); +#endif /* IP_REASS_CHECK_OVERLAP */ +      /* this is the first fragment we ever received for this ip datagram */ +      ipr->p = new_p; +    } +  } + +  /* At this point, the validation part begins: */ +  /* If we already received the last fragment */ +  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) { +    /* and had no wholes so far */ +    if (valid) { +      /* then check if the rest of the fragments is here */ +      /* Check if the queue starts with the first datagram */ +      if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) { +        valid = 0; +      } else { +        /* and check that there are no wholes after this datagram */ +        iprh_prev = iprh; +        q = iprh->next_pbuf; +        while (q != NULL) { +          iprh = (struct ip_reass_helper*)q->payload; +          if (iprh_prev->end != iprh->start) { +            valid = 0; +            break; +          } +          iprh_prev = iprh; +          q = iprh->next_pbuf; +        } +        /* if still valid, all fragments are received +         * (because to the MF==0 already arrived */ +        if (valid) { +          LWIP_ASSERT("sanity check", ipr->p != NULL); +          LWIP_ASSERT("sanity check", +            ((struct ip_reass_helper*)ipr->p->payload) != iprh); +          LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", +            iprh->next_pbuf == NULL); +          LWIP_ASSERT("validate_datagram:datagram end!=datagram len", +            iprh->end == ipr->datagram_len); +        } +      } +    } +    /* If valid is 0 here, there are some fragments missing in the middle +     * (since MF == 0 has already arrived). Such datagrams simply time out if +     * no more fragments are received... */ +    return valid; +  } +  /* If we come here, not all fragments were received, yet! */ +  return 0; /* not yet valid! */ +#if IP_REASS_CHECK_OVERLAP +freepbuf: +  ip_reass_pbufcount -= pbuf_clen(new_p); +  pbuf_free(new_p); +  return 0; +#endif /* IP_REASS_CHECK_OVERLAP */ +} + +/** + * Reassembles incoming IP fragments into an IP datagram. + * + * @param p points to a pbuf chain of the fragment + * @return NULL if reassembly is incomplete, ? otherwise + */ +struct pbuf * +ip_reass(struct pbuf *p) +{ +  struct pbuf *r; +  struct ip_hdr *fraghdr; +  struct ip_reassdata *ipr; +  struct ip_reass_helper *iprh; +  u16_t offset, len; +  u8_t clen; +  struct ip_reassdata *ipr_prev = NULL; + +  IPFRAG_STATS_INC(ip_frag.recv); +  snmp_inc_ipreasmreqds(); + +  fraghdr = (struct ip_hdr*)p->payload; + +  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { +    LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n")); +    IPFRAG_STATS_INC(ip_frag.err); +    goto nullreturn; +  } + +  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; +  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; + +  /* Check if we are allowed to enqueue more datagrams. */ +  clen = pbuf_clen(p); +  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { +#if IP_REASS_FREE_OLDEST +    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || +        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) +#endif /* IP_REASS_FREE_OLDEST */ +    { +      /* No datagram could be freed and still too many pbufs enqueued */ +      LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", +        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); +      IPFRAG_STATS_INC(ip_frag.memerr); +      /* @todo: send ICMP time exceeded here? */ +      /* drop this pbuf */ +      goto nullreturn; +    } +  } + +  /* Look for the datagram the fragment belongs to in the current datagram queue, +   * remembering the previous in the queue for later dequeueing. */ +  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { +    /* Check if the incoming fragment matches the one currently present +       in the reassembly buffer. If so, we proceed with copying the +       fragment into the buffer. */ +    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { +      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", +        ntohs(IPH_ID(fraghdr)))); +      IPFRAG_STATS_INC(ip_frag.cachehit); +      break; +    } +    ipr_prev = ipr; +  } + +  if (ipr == NULL) { +  /* Enqueue a new datagram into the datagram queue */ +    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen); +    /* Bail if unable to enqueue */ +    if(ipr == NULL) { +      goto nullreturn; +    } +  } else { +    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&  +      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { +      /* ipr->iphdr is not the header from the first fragment, but fraghdr is +       * -> copy fraghdr into ipr->iphdr since we want to have the header +       * of the first fragment (for ICMP time exceeded and later, for copying +       * all options, if supported)*/ +      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); +    } +  } +  /* Track the current number of pbufs current 'in-flight', in order to limit  +  the number of fragments that may be enqueued at any one time */ +  ip_reass_pbufcount += clen; + +  /* At this point, we have either created a new entry or pointing  +   * to an existing one */ + +  /* check for 'no more fragments', and update queue entry*/ +  if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) { +    ipr->flags |= IP_REASS_FLAG_LASTFRAG; +    ipr->datagram_len = offset + len; +    LWIP_DEBUGF(IP_REASS_DEBUG, +     ("ip_reass: last fragment seen, total len %"S16_F"\n", +      ipr->datagram_len)); +  } +  /* find the right place to insert this pbuf */ +  /* @todo: trim pbufs if fragments are overlapping */ +  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { +    /* the totally last fragment (flag more fragments = 0) was received at least +     * once AND all fragments are received */ +    ipr->datagram_len += IP_HLEN; + +    /* save the second pbuf before copying the header over the pointer */ +    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; + +    /* copy the original ip header back to the first pbuf */ +    fraghdr = (struct ip_hdr*)(ipr->p->payload); +    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); +    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len)); +    IPH_OFFSET_SET(fraghdr, 0); +    IPH_CHKSUM_SET(fraghdr, 0); +    /* @todo: do we need to set calculate the correct checksum? */ +    IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); + +    p = ipr->p; + +    /* chain together the pbufs contained within the reass_data list. */ +    while(r != NULL) { +      iprh = (struct ip_reass_helper*)r->payload; + +      /* hide the ip header for every succeding fragment */ +      pbuf_header(r, -IP_HLEN); +      pbuf_cat(p, r); +      r = iprh->next_pbuf; +    } +    /* release the sources allocate for the fragment queue entry */ +    ip_reass_dequeue_datagram(ipr, ipr_prev); + +    /* and adjust the number of pbufs currently queued for reassembly. */ +    ip_reass_pbufcount -= pbuf_clen(p); + +    /* Return the pbuf chain */ +    return p; +  } +  /* the datagram is not (yet?) reassembled completely */ +  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); +  return NULL; + +nullreturn: +  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n")); +  IPFRAG_STATS_INC(ip_frag.drop); +  pbuf_free(p); +  return NULL; +} +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +#if IP_FRAG_USES_STATIC_BUF +static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)]; +#endif /* IP_FRAG_USES_STATIC_BUF */ + +/** + * Fragment an IP datagram if too large for the netif. + * + * Chop the datagram in MTU sized chunks and send them in order + * by using a fixed size static memory buffer (PBUF_REF) or + * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). + * + * @param p ip packet to send + * @param netif the netif on which to send + * @param dest destination ip address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t  +ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) +{ +  struct pbuf *rambuf; +#if IP_FRAG_USES_STATIC_BUF +  struct pbuf *header; +#else +  struct pbuf *newpbuf; +  struct ip_hdr *original_iphdr; +#endif +  struct ip_hdr *iphdr; +  u16_t nfb; +  u16_t left, cop; +  u16_t mtu = netif->mtu; +  u16_t ofo, omf; +  u16_t last; +  u16_t poff = IP_HLEN; +  u16_t tmp; +#if !IP_FRAG_USES_STATIC_BUF +  u16_t newpbuflen = 0; +  u16_t left_to_copy; +#endif + +  /* Get a RAM based MTU sized pbuf */ +#if IP_FRAG_USES_STATIC_BUF +  /* When using a static buffer, we use a PBUF_REF, which we will +   * use to reference the packet (without link header). +   * Layer and length is irrelevant. +   */ +  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); +  if (rambuf == NULL) { +    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); +    return ERR_MEM; +  } +  rambuf->tot_len = rambuf->len = mtu; +  rambuf->payload = LWIP_MEM_ALIGN((void *)buf); + +  /* Copy the IP header in it */ +  iphdr = rambuf->payload; +  SMEMCPY(iphdr, p->payload, IP_HLEN); +#else /* IP_FRAG_USES_STATIC_BUF */ +  original_iphdr = p->payload; +  iphdr = original_iphdr; +#endif /* IP_FRAG_USES_STATIC_BUF */ + +  /* Save original offset */ +  tmp = ntohs(IPH_OFFSET(iphdr)); +  ofo = tmp & IP_OFFMASK; +  omf = tmp & IP_MF; + +  left = p->tot_len - IP_HLEN; + +  nfb = (mtu - IP_HLEN) / 8; + +  while (left) { +    last = (left <= mtu - IP_HLEN); + +    /* Set new offset and MF flag */ +    tmp = omf | (IP_OFFMASK & (ofo)); +    if (!last) +      tmp = tmp | IP_MF; + +    /* Fill this fragment */ +    cop = last ? left : nfb * 8; + +#if IP_FRAG_USES_STATIC_BUF +    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); +#else /* IP_FRAG_USES_STATIC_BUF */ +    /* When not using a static buffer, create a chain of pbufs. +     * The first will be a PBUF_RAM holding the link and IP header. +     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, +     * but limited to the size of an mtu. +     */ +    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); +    if (rambuf == NULL) { +      return ERR_MEM; +    } +    LWIP_ASSERT("this needs a pbuf in one piece!", +                (p->len >= (IP_HLEN))); +    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); +    iphdr = rambuf->payload; + +    /* Can just adjust p directly for needed offset. */ +    p->payload = (u8_t *)p->payload + poff; +    p->len -= poff; + +    left_to_copy = cop; +    while (left_to_copy) { +      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; +      /* Is this pbuf already empty? */ +      if (!newpbuflen) { +        p = p->next; +        continue; +      } +      newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF); +      if (newpbuf == NULL) { +        pbuf_free(rambuf); +        return ERR_MEM; +      } +      /* Mirror this pbuf, although we might not need all of it. */ +      newpbuf->payload = p->payload; +      newpbuf->len = newpbuf->tot_len = newpbuflen; +      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain +       * so that it is removed when pbuf_dechain is later called on rambuf. +       */ +      pbuf_cat(rambuf, newpbuf); +      left_to_copy -= newpbuflen; +      if (left_to_copy) +        p = p->next; +    } +    poff = newpbuflen; +#endif /* IP_FRAG_USES_STATIC_BUF */ + +    /* Correct header */ +    IPH_OFFSET_SET(iphdr, htons(tmp)); +    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); +    IPH_CHKSUM_SET(iphdr, 0); +    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + +#if IP_FRAG_USES_STATIC_BUF +    if (last) +      pbuf_realloc(rambuf, left + IP_HLEN); + +    /* This part is ugly: we alloc a RAM based pbuf for  +     * the link level header for each chunk and then  +     * free it.A PBUF_ROM style pbuf for which pbuf_header +     * worked would make things simpler. +     */ +    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); +    if (header != NULL) { +      pbuf_chain(header, rambuf); +      netif->output(netif, header, dest); +      IPFRAG_STATS_INC(ip_frag.xmit); +      snmp_inc_ipfragcreates(); +      pbuf_free(header); +    } else { +      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n")); +      pbuf_free(rambuf); +      return ERR_MEM; +    } +#else /* IP_FRAG_USES_STATIC_BUF */ +    /* No need for separate header pbuf - we allowed room for it in rambuf +     * when allocated. +     */ +    netif->output(netif, rambuf, dest); +    IPFRAG_STATS_INC(ip_frag.xmit); + +    /* Unfortunately we can't reuse rambuf - the hardware may still be +     * using the buffer. Instead we free it (and the ensuing chain) and +     * recreate it next time round the loop. If we're lucky the hardware +     * will have already sent the packet, the free will really free, and +     * there will be zero memory penalty. +     */ +     +    pbuf_free(rambuf); +#endif /* IP_FRAG_USES_STATIC_BUF */ +    left -= cop; +    ofo += nfb; +  } +#if IP_FRAG_USES_STATIC_BUF +  pbuf_free(rambuf); +#endif /* IP_FRAG_USES_STATIC_BUF */ +  snmp_inc_ipfragoks(); +  return ERR_OK; +} +#endif /* IP_FRAG */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/README b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/README new file mode 100644 index 000000000..362000486 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/README @@ -0,0 +1 @@ +IPv6 support in lwIP is very experimental. diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/icmp6.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/icmp6.c new file mode 100644 index 000000000..4fcc89551 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/icmp6.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +/* Some ICMP messages should be passed to the transport protocols. This +   is not implemented. */ + +#include "lwip/opt.h" + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/icmp.h" +#include "lwip/inet.h" +#include "lwip/ip.h" +#include "lwip/def.h" +#include "lwip/stats.h" + +void +icmp_input(struct pbuf *p, struct netif *inp) +{ +  u8_t type; +  struct icmp_echo_hdr *iecho; +  struct ip_hdr *iphdr; +  struct ip_addr tmpaddr; + +  ICMP_STATS_INC(icmp.recv); + +  /* TODO: check length before accessing payload! */ + +  type = ((u8_t *)p->payload)[0]; + +  switch (type) { +  case ICMP6_ECHO: +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); + +    if (p->tot_len < sizeof(struct icmp_echo_hdr)) { +      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + +      pbuf_free(p); +      ICMP_STATS_INC(icmp.lenerr); +      return; +    } +    iecho = p->payload; +    iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN); +    if (inet_chksum_pbuf(p) != 0) { +      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); +      ICMP_STATS_INC(icmp.chkerr); +    /*      return;*/ +    } +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len)); +    ip_addr_set(&tmpaddr, &(iphdr->src)); +    ip_addr_set(&(iphdr->src), &(iphdr->dest)); +    ip_addr_set(&(iphdr->dest), &tmpaddr); +    iecho->type = ICMP6_ER; +    /* adjust the checksum */ +    if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) { +      iecho->chksum += htons(ICMP6_ECHO << 8) + 1; +    } else { +      iecho->chksum += htons(ICMP6_ECHO << 8); +    } +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); +    ICMP_STATS_INC(icmp.xmit); + +    /*    LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ +    ip_output_if (p, &(iphdr->src), IP_HDRINCL, +     iphdr->hoplim, IP_PROTO_ICMP, inp); +    break; +  default: +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type)); +    ICMP_STATS_INC(icmp.proterr); +    ICMP_STATS_INC(icmp.drop); +  } + +  pbuf_free(p); +} + +void +icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +{ +  struct pbuf *q; +  struct ip_hdr *iphdr; +  struct icmp_dur_hdr *idur; + +  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ +  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); +  /* ICMP header + IP header + 8 bytes of data */ +  if (q == NULL) { +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); +    pbuf_free(p); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold icmp message", +             (q->len >= (8 + IP_HLEN + 8))); + +  iphdr = p->payload; + +  idur = q->payload; +  idur->type = (u8_t)ICMP6_DUR; +  idur->icode = (u8_t)t; + +  SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8); + +  /* calculate checksum */ +  idur->chksum = 0; +  idur->chksum = inet_chksum(idur, q->len); +  ICMP_STATS_INC(icmp.xmit); + +  ip_output(q, NULL, +      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); +  pbuf_free(q); +} + +void +icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +{ +  struct pbuf *q; +  struct ip_hdr *iphdr; +  struct icmp_te_hdr *tehdr; + +  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n")); + +  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ +  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); +  /* ICMP header + IP header + 8 bytes of data */ +  if (q == NULL) { +    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); +    pbuf_free(p); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold icmp message", +             (q->len >= (8 + IP_HLEN + 8))); + +  iphdr = p->payload; + +  tehdr = q->payload; +  tehdr->type = (u8_t)ICMP6_TE; +  tehdr->icode = (u8_t)t; + +  /* copy fields from original packet */ +  SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8); + +  /* calculate checksum */ +  tehdr->chksum = 0; +  tehdr->chksum = inet_chksum(tehdr, q->len); +  ICMP_STATS_INC(icmp.xmit); +  ip_output(q, NULL, +      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); +  pbuf_free(q); +} + +#endif /* LWIP_ICMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/inet6.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/inet6.c new file mode 100644 index 000000000..c3de85c09 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/inet6.c @@ -0,0 +1,163 @@ +/** + * @file + * Functions common to all TCP/IPv6 modules, such as the Internet checksum and the + * byte order functions. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/inet.h" + +/* chksum: + * + * Sums up all 16 bit words in a memory portion. Also includes any odd byte. + * This function is used by the other checksum functions. + * + * For now, this is not optimized. Must be optimized for the particular processor + * arcitecture on which it is to run. Preferebly coded in assembler. + */ + +static u32_t +chksum(void *dataptr, u16_t len) +{ +  u16_t *sdataptr = dataptr; +  u32_t acc; +   +   +  for(acc = 0; len > 1; len -= 2) { +    acc += *sdataptr++; +  } + +  /* add up any odd byte */ +  if (len == 1) { +    acc += htons((u16_t)(*(u8_t *)dataptr) << 8); +  } + +  return acc; + +} + +/* inet_chksum_pseudo: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + */ + +u16_t +inet_chksum_pseudo(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u32_t proto_len) +{ +  u32_t acc; +  struct pbuf *q; +  u8_t swapped, i; + +  acc = 0; +  swapped = 0; +  for(q = p; q != NULL; q = q->next) {     +    acc += chksum(q->payload, q->len); +    while (acc >> 16) { +      acc = (acc & 0xffff) + (acc >> 16); +    } +    if (q->len % 2 != 0) { +      swapped = 1 - swapped; +      acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); +    } +  } + +  if (swapped) { +    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); +  } +   +  for(i = 0; i < 8; i++) { +    acc += ((u16_t *)src->addr)[i] & 0xffff; +    acc += ((u16_t *)dest->addr)[i] & 0xffff; +    while (acc >> 16) { +      acc = (acc & 0xffff) + (acc >> 16); +    } +  } +  acc += (u16_t)htons((u16_t)proto); +  acc += ((u16_t *)&proto_len)[0] & 0xffff; +  acc += ((u16_t *)&proto_len)[1] & 0xffff; + +  while (acc >> 16) { +    acc = (acc & 0xffff) + (acc >> 16); +  } +  return ~(acc & 0xffff); +} + +/* inet_chksum: + * + * Calculates the Internet checksum over a portion of memory. Used primarely for IP + * and ICMP. + */ + +u16_t +inet_chksum(void *dataptr, u16_t len) +{ +  u32_t acc, sum; + +  acc = chksum(dataptr, len); +  sum = (acc & 0xffff) + (acc >> 16); +  sum += (sum >> 16); +  return ~(sum & 0xffff); +} + +u16_t +inet_chksum_pbuf(struct pbuf *p) +{ +  u32_t acc; +  struct pbuf *q; +  u8_t swapped; +   +  acc = 0; +  swapped = 0; +  for(q = p; q != NULL; q = q->next) { +    acc += chksum(q->payload, q->len); +    while (acc >> 16) { +      acc = (acc & 0xffff) + (acc >> 16); +    }     +    if (q->len % 2 != 0) { +      swapped = 1 - swapped; +      acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8); +    } +  } +  +  if (swapped) { +    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); +  } +  return ~(acc & 0xffff); +} diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/ip6.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/ip6.c new file mode 100644 index 000000000..7e4342001 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/ip6.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + + + +/* ip.c + * + * This is the code for the IP layer for IPv6. + * + */ + + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/ip.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include "lwip/stats.h" + +#include "arch/perf.h" + +/* ip_init: + * + * Initializes the IP layer. + */ + +void +ip_init(void) +{ +} + +/* ip_route: + * + * Finds the appropriate network interface for a given IP address. It searches the + * list of network interfaces linearly. A match is found if the masked IP address of + * the network interface equals the masked IP address given to the function. + */ + +struct netif * +ip_route(struct ip_addr *dest) +{ +  struct netif *netif; + +  for(netif = netif_list; netif != NULL; netif = netif->next) { +    if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { +      return netif; +    } +  } + +  return netif_default; +} + +/* ip_forward: + * + * Forwards an IP packet. It finds an appropriate route for the packet, decrements + * the TTL value of the packet, adjusts the checksum and outputs the packet on the + * appropriate interface. + */ + +static void +ip_forward(struct pbuf *p, struct ip_hdr *iphdr) +{ +  struct netif *netif; + +  PERF_START; + +  if ((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) { + +    LWIP_DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for ")); +#if IP_DEBUG +    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); +#endif /* IP_DEBUG */ +    LWIP_DEBUGF(IP_DEBUG, ("\n")); +    pbuf_free(p); +    return; +  } +  /* Decrement TTL and send ICMP if ttl == 0. */ +  if (--iphdr->hoplim == 0) { +#if LWIP_ICMP +    /* Don't send ICMP messages in response to ICMP messages */ +    if (iphdr->nexthdr != IP_PROTO_ICMP) { +      icmp_time_exceeded(p, ICMP_TE_TTL); +    } +#endif /* LWIP_ICMP */ +    pbuf_free(p); +    return; +  } + +  /* Incremental update of the IP checksum. */ +  /*  if (iphdr->chksum >= htons(0xffff - 0x100)) { +    iphdr->chksum += htons(0x100) + 1; +  } else { +    iphdr->chksum += htons(0x100); +    }*/ + + +  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to ")); +#if IP_DEBUG +  ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); +#endif /* IP_DEBUG */ +  LWIP_DEBUGF(IP_DEBUG, ("\n")); + +  IP_STATS_INC(ip.fw); +  IP_STATS_INC(ip.xmit); + +  PERF_STOP("ip_forward"); + +  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); +} + +/* ip_input: + * + * This function is called by the network interface device driver when an IP packet is + * received. The function does the basic checks of the IP header such as packet size + * being at least larger than the header size etc. If the packet was not destined for + * us, the packet is forwarded (using ip_forward). The IP checksum is always checked. + * + * Finally, the packet is sent to the upper layer protocol input function. + */ + +void +ip_input(struct pbuf *p, struct netif *inp) { +  struct ip_hdr *iphdr; +  struct netif *netif; + + +  PERF_START; + +#if IP_DEBUG +  ip_debug_print(p); +#endif /* IP_DEBUG */ + + +  IP_STATS_INC(ip.recv); + +  /* identify the IP header */ +  iphdr = p->payload; + + +  if (iphdr->v != 6) { +    LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n")); +#if IP_DEBUG +    ip_debug_print(p); +#endif /* IP_DEBUG */ +    pbuf_free(p); +    IP_STATS_INC(ip.err); +    IP_STATS_INC(ip.drop); +    return; +  } + +  /* is this packet for us? */ +  for(netif = netif_list; netif != NULL; netif = netif->next) { +#if IP_DEBUG +    LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest ")); +    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); +    LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr ")); +    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); +    LWIP_DEBUGF(IP_DEBUG, ("\n")); +#endif /* IP_DEBUG */ +    if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) { +      break; +    } +  } + + +  if (netif == NULL) { +    /* packet not for us, route or discard */ +#if IP_FORWARD +    ip_forward(p, iphdr); +#endif +    pbuf_free(p); +    return; +  } + +  pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len)); + +  /* send to upper layers */ +#if IP_DEBUG +  /*  LWIP_DEBUGF("ip_input: \n"); +  ip_debug_print(p); +  LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ +#endif /* IP_DEBUG */ + +  if(pbuf_header(p, -IP_HLEN)) { +    LWIP_ASSERT("Can't move over header in packet", 0); +    return; +  } + +  switch (iphdr->nexthdr) { +  case IP_PROTO_UDP: +    udp_input(p, inp); +    break; +  case IP_PROTO_TCP: +    tcp_input(p, inp); +    break; +#if LWIP_ICMP +  case IP_PROTO_ICMP: +    icmp_input(p, inp); +    break; +#endif /* LWIP_ICMP */ +  default: +#if LWIP_ICMP +    /* send ICMP destination protocol unreachable */ +    icmp_dest_unreach(p, ICMP_DUR_PROTO); +#endif /* LWIP_ICMP */ +    pbuf_free(p); +    LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n", +          iphdr->nexthdr)); + +    IP_STATS_INC(ip.proterr); +    IP_STATS_INC(ip.drop); +  } +  PERF_STOP("ip_input"); +} + + +/* ip_output_if: + * + * Sends an IP packet on a network interface. This function constructs the IP header + * and calculates the IP header checksum. If the source IP address is NULL, + * the IP address of the outgoing network interface is filled in as source address. + */ + +err_t +ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, +       u8_t proto, struct netif *netif) +{ +  struct ip_hdr *iphdr; + +  PERF_START; + +  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len)); +  if (pbuf_header(p, IP_HLEN)) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n")); +    IP_STATS_INC(ip.err); + +    return ERR_BUF; +  } +  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len)); + +  iphdr = p->payload; + + +  if (dest != IP_HDRINCL) { +    LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n")); +    iphdr->hoplim = ttl; +    iphdr->nexthdr = proto; +    iphdr->len = htons(p->tot_len - IP_HLEN); +    ip_addr_set(&(iphdr->dest), dest); + +    iphdr->v = 6; + +    if (ip_addr_isany(src)) { +      ip_addr_set(&(iphdr->src), &(netif->ip_addr)); +    } else { +      ip_addr_set(&(iphdr->src), src); +    } + +  } else { +    dest = &(iphdr->dest); +  } + +  IP_STATS_INC(ip.xmit); + +  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len)); +#if IP_DEBUG +  ip_debug_print(p); +#endif /* IP_DEBUG */ + +  PERF_STOP("ip_output_if"); +  return netif->output(netif, p, dest); +} + +/* ip_output: + * + * Simple interface to ip_output_if. It finds the outgoing network interface and + * calls upon ip_output_if to do the actual work. + */ + +err_t +ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +    u8_t ttl, u8_t proto) +{ +  struct netif *netif; +  if ((netif = ip_route(dest)) == NULL) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); +    IP_STATS_INC(ip.rterr); +    return ERR_RTE; +  } + +  return ip_output_if (p, src, dest, ttl, proto, netif); +} + +#if LWIP_NETIF_HWADDRHINT +err_t +ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) +{ +  struct netif *netif; +  err_t err; + +  if ((netif = ip_route(dest)) == NULL) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); +    IP_STATS_INC(ip.rterr); +    return ERR_RTE; +  } + +  netif->addr_hint = addr_hint; +  err = ip_output_if(p, src, dest, ttl, tos, proto, netif); +  netif->addr_hint = NULL; + +  return err; +} +#endif /* LWIP_NETIF_HWADDRHINT*/ + +#if IP_DEBUG +void +ip_debug_print(struct pbuf *p) +{ +  struct ip_hdr *iphdr = p->payload; + +  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |  %"X16_F"%"X16_F"  |      %"X16_F"%"X16_F"           | (v, traffic class, flow label)\n", +        iphdr->v, +        iphdr->tclass1, iphdr->tclass2, +        iphdr->flow1, iphdr->flow2)); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      | %2"U16_F"  |  %2"U16_F"   | (len, nexthdr, hoplim)\n", +        ntohs(iphdr->len), +        iphdr->nexthdr, +        iphdr->hoplim)); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n", +        (ntohl(iphdr->src.addr[0]) >> 16) & 0xffff, +        ntohl(iphdr->src.addr[0]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n", +        (ntohl(iphdr->src.addr[1]) >> 16) & 0xffff, +        ntohl(iphdr->src.addr[1]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n", +        (ntohl(iphdr->src.addr[2]) >> 16) & 0xffff, +        ntohl(iphdr->src.addr[2]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n", +        (ntohl(iphdr->src.addr[3]) >> 16) & 0xffff, +        ntohl(iphdr->src.addr[3]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n", +        (ntohl(iphdr->dest.addr[0]) >> 16) & 0xffff, +        ntohl(iphdr->dest.addr[0]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n", +        (ntohl(iphdr->dest.addr[1]) >> 16) & 0xffff, +        ntohl(iphdr->dest.addr[1]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n", +        (ntohl(iphdr->dest.addr[2]) >> 16) & 0xffff, +        ntohl(iphdr->dest.addr[2]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n", +        (ntohl(iphdr->dest.addr[3]) >> 16) & 0xffff, +        ntohl(iphdr->dest.addr[3]) & 0xffff)); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/ip6_addr.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/ip6_addr.c new file mode 100644 index 000000000..2da6cea42 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/ipv6/ip6_addr.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +u8_t +ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2, +                struct ip_addr *mask) +{ +  return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) && +         (addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) && +         (addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) && +         (addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3])); +         +} + +u8_t +ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2) +{ +  return(addr1->addr[0] == addr2->addr[0] && +         addr1->addr[1] == addr2->addr[1] && +         addr1->addr[2] == addr2->addr[2] && +         addr1->addr[3] == addr2->addr[3]); +} + +void +ip_addr_set(struct ip_addr *dest, struct ip_addr *src) +{ +  SMEMCPY(dest, src, sizeof(struct ip_addr)); +  /*  dest->addr[0] = src->addr[0]; +  dest->addr[1] = src->addr[1]; +  dest->addr[2] = src->addr[2]; +  dest->addr[3] = src->addr[3];*/ +} + +u8_t +ip_addr_isany(struct ip_addr *addr) +{ +  if (addr == NULL) return 1; +  return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0); +} diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/mem.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/mem.c new file mode 100644 index 000000000..b5f13ab3b --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/mem.c @@ -0,0 +1,633 @@ +/** + * @file + * Dynamic memory manager + * + * This is a lightweight replacement for the standard C library malloc(). + * + * If you want to use the standard C library malloc() instead, define + * MEM_LIBC_MALLOC to 1 in your lwipopts.h + * + * To let mem_malloc() use pools (prevents fragmentation and is much faster than + * a heap but might waste some memory), define MEM_USE_POOLS to 1, define + * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list + * of pools like this (more pools can be added between _START and _END): + * + * Define three pools with sizes 256, 512, and 1512 bytes + * LWIP_MALLOC_MEMPOOL_START + * LWIP_MALLOC_MEMPOOL(20, 256) + * LWIP_MALLOC_MEMPOOL(10, 512) + * LWIP_MALLOC_MEMPOOL(5, 1512) + * LWIP_MALLOC_MEMPOOL_END + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + *         Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/sys.h" +#include "lwip/stats.h" + +#include <string.h> + +#if MEM_USE_POOLS +/* lwIP head implemented with different sized pools */ + +/** + * Allocate memory: determine the smallest pool that is big enough + * to contain an element of 'size' and get an element from that pool. + * + * @param size the size in bytes of the memory needed + * @return a pointer to the allocated memory or NULL if the pool is empty + */ +void * +mem_malloc(mem_size_t size) +{ +  struct memp_malloc_helper *element; +  memp_t poolnr; +  mem_size_t required_size = size + sizeof(struct memp_malloc_helper); + +  for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) { +#if MEM_USE_POOLS_TRY_BIGGER_POOL +again: +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ +    /* is this pool big enough to hold an element of the required size +       plus a struct memp_malloc_helper that saves the pool this element came from? */ +    if (required_size <= memp_sizes[poolnr]) { +      break; +    } +  } +  if (poolnr > MEMP_POOL_LAST) { +    LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); +    return NULL; +  } +  element = (struct memp_malloc_helper*)memp_malloc(poolnr); +  if (element == NULL) { +    /* No need to DEBUGF or ASSERT: This error is already +       taken care of in memp.c */ +#if MEM_USE_POOLS_TRY_BIGGER_POOL +    /** Try a bigger pool if this one is empty! */ +    if (poolnr < MEMP_POOL_LAST) { +      poolnr++; +      goto again; +    } +#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ +    return NULL; +  } + +  /* save the pool number this element came from */ +  element->poolnr = poolnr; +  /* and return a pointer to the memory directly after the struct memp_malloc_helper */ +  element++; + +  return element; +} + +/** + * Free memory previously allocated by mem_malloc. Loads the pool number + * and calls memp_free with that pool number to put the element back into + * its pool + * + * @param rmem the memory element to free + */ +void +mem_free(void *rmem) +{ +  struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem; + +  LWIP_ASSERT("rmem != NULL", (rmem != NULL)); +  LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); + +  /* get the original struct memp_malloc_helper */ +  hmem--; + +  LWIP_ASSERT("hmem != NULL", (hmem != NULL)); +  LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); +  LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); + +  /* and put it in the pool we saved earlier */ +  memp_free(hmem->poolnr, hmem); +} + +#else /* MEM_USE_POOLS */ +/* lwIP replacement for your libc malloc() */ + +/** + * The heap is made up as a list of structs of this type. + * This does not have to be aligned since for getting its size, + * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes. + */ +struct mem { +  /** index (-> ram[next]) of the next struct */ +  mem_size_t next; +  /** index (-> ram[next]) of the next struct */ +  mem_size_t prev; +  /** 1: this area is used; 0: this area is unused */ +  u8_t used; +}; + +/** All allocated blocks will be MIN_SIZE bytes big, at least! + * MIN_SIZE can be overridden to suit your needs. Smaller values save space, + * larger values could prevent too small blocks to fragment the RAM too much. */ +#ifndef MIN_SIZE +#define MIN_SIZE             12 +#endif /* MIN_SIZE */ +/* some alignment macros: we define them here for better source code layout */ +#define MIN_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MIN_SIZE) +#define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) +#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE) + +/** the heap. we need one struct mem at the end and some room for alignment */ +static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; +/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ +static u8_t *ram; +/** the last entry, always unused! */ +static struct mem *ram_end; +/** pointer to the lowest free block, this is used for faster search */ +static struct mem *lfree; + +/** concurrent access protection */ +static sys_sem_t mem_sem; + +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + +static volatile u8_t mem_free_count; + +/* Allow mem_free from other (e.g. interrupt) context */ +#define LWIP_MEM_FREE_DECL_PROTECT()  SYS_ARCH_DECL_PROTECT(lev_free) +#define LWIP_MEM_FREE_PROTECT()       SYS_ARCH_PROTECT(lev_free) +#define LWIP_MEM_FREE_UNPROTECT()     SYS_ARCH_UNPROTECT(lev_free) +#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_PROTECT()      SYS_ARCH_PROTECT(lev_alloc) +#define LWIP_MEM_ALLOC_UNPROTECT()    SYS_ARCH_UNPROTECT(lev_alloc) + +#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +/* Protect the heap only by using a semaphore */ +#define LWIP_MEM_FREE_DECL_PROTECT() +#define LWIP_MEM_FREE_PROTECT()    sys_arch_sem_wait(mem_sem, 0) +#define LWIP_MEM_FREE_UNPROTECT()  sys_sem_signal(mem_sem) +/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ +#define LWIP_MEM_ALLOC_DECL_PROTECT() +#define LWIP_MEM_ALLOC_PROTECT() +#define LWIP_MEM_ALLOC_UNPROTECT() + +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + + +/** + * "Plug holes" by combining adjacent empty struct mems. + * After this function is through, there should not exist + * one empty struct mem pointing to another empty struct mem. + * + * @param mem this points to a struct mem which just has been freed + * @internal this function is only called by mem_free() and mem_realloc() + * + * This assumes access to the heap is protected by the calling function + * already. + */ +static void +plug_holes(struct mem *mem) +{ +  struct mem *nmem; +  struct mem *pmem; + +  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); +  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); +  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); + +  /* plug hole forward */ +  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); + +  nmem = (struct mem *)&ram[mem->next]; +  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { +    /* if mem->next is unused and not end of ram, combine mem and mem->next */ +    if (lfree == nmem) { +      lfree = mem; +    } +    mem->next = nmem->next; +    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram; +  } + +  /* plug hole backward */ +  pmem = (struct mem *)&ram[mem->prev]; +  if (pmem != mem && pmem->used == 0) { +    /* if mem->prev is unused, combine mem and mem->prev */ +    if (lfree == mem) { +      lfree = pmem; +    } +    pmem->next = mem->next; +    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram; +  } +} + +/** + * Zero the heap and initialize start, end and lowest-free + */ +void +mem_init(void) +{ +  struct mem *mem; + +  LWIP_ASSERT("Sanity check alignment", +    (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); + +  /* align the heap */ +  ram = LWIP_MEM_ALIGN(ram_heap); +  /* initialize the start of the heap */ +  mem = (struct mem *)ram; +  mem->next = MEM_SIZE_ALIGNED; +  mem->prev = 0; +  mem->used = 0; +  /* initialize the end of the heap */ +  ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; +  ram_end->used = 1; +  ram_end->next = MEM_SIZE_ALIGNED; +  ram_end->prev = MEM_SIZE_ALIGNED; + +  mem_sem = sys_sem_new(1); + +  /* initialize the lowest-free pointer to the start of the heap */ +  lfree = (struct mem *)ram; + +  MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); +} + +/** + * Put a struct mem back on the heap + * + * @param rmem is the data portion of a struct mem as returned by a previous + *             call to mem_malloc() + */ +void +mem_free(void *rmem) +{ +  struct mem *mem; +  LWIP_MEM_FREE_DECL_PROTECT(); + +  if (rmem == NULL) { +    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n")); +    return; +  } +  LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); + +  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && +    (u8_t *)rmem < (u8_t *)ram_end); + +  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { +    SYS_ARCH_DECL_PROTECT(lev); +    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n")); +    /* protect mem stats from concurrent access */ +    SYS_ARCH_PROTECT(lev); +    MEM_STATS_INC(illegal); +    SYS_ARCH_UNPROTECT(lev); +    return; +  } +  /* protect the heap from concurrent access */ +  LWIP_MEM_FREE_PROTECT(); +  /* Get the corresponding struct mem ... */ +  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); +  /* ... which has to be in a used state ... */ +  LWIP_ASSERT("mem_free: mem->used", mem->used); +  /* ... and is now unused. */ +  mem->used = 0; + +  if (mem < lfree) { +    /* the newly freed struct is now the lowest */ +    lfree = mem; +  } + +  MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram)); + +  /* finally, see if prev or next are free also */ +  plug_holes(mem); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +  mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ +  LWIP_MEM_FREE_UNPROTECT(); +} + +/** + * In contrast to its name, mem_realloc can only shrink memory, not expand it. + * Since the only use (for now) is in pbuf_realloc (which also can only shrink), + * this shouldn't be a problem! + * + * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked + * @param newsize required size after shrinking (needs to be smaller than or + *                equal to the previous size) + * @return for compatibility reasons: is always == rmem, at the moment + *         or NULL if newsize is > old size, in which case rmem is NOT touched + *         or freed! + */ +void * +mem_realloc(void *rmem, mem_size_t newsize) +{ +  mem_size_t size; +  mem_size_t ptr, ptr2; +  struct mem *mem, *mem2; +  /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ +  LWIP_MEM_FREE_DECL_PROTECT(); + +  /* Expand the size of the allocated memory region so that we can +     adjust for alignment. */ +  newsize = LWIP_MEM_ALIGN_SIZE(newsize); + +  if(newsize < MIN_SIZE_ALIGNED) { +    /* every data block must be at least MIN_SIZE_ALIGNED long */ +    newsize = MIN_SIZE_ALIGNED; +  } + +  if (newsize > MEM_SIZE_ALIGNED) { +    return NULL; +  } + +  LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram && +   (u8_t *)rmem < (u8_t *)ram_end); + +  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { +    SYS_ARCH_DECL_PROTECT(lev); +    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n")); +    /* protect mem stats from concurrent access */ +    SYS_ARCH_PROTECT(lev); +    MEM_STATS_INC(illegal); +    SYS_ARCH_UNPROTECT(lev); +    return rmem; +  } +  /* Get the corresponding struct mem ... */ +  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); +  /* ... and its offset pointer */ +  ptr = (u8_t *)mem - ram; + +  size = mem->next - ptr - SIZEOF_STRUCT_MEM; +  LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size); +  if (newsize > size) { +    /* not supported */ +    return NULL; +  } +  if (newsize == size) { +    /* No change in size, simply return */ +    return rmem; +  } + +  /* protect the heap from concurrent access */ +  LWIP_MEM_FREE_PROTECT(); + +  MEM_STATS_DEC_USED(used, (size - newsize)); + +  mem2 = (struct mem *)&ram[mem->next]; +  if(mem2->used == 0) { +    /* The next struct is unused, we can simply move it at little */ +    mem_size_t next; +    /* remember the old next pointer */ +    next = mem2->next; +    /* create new struct mem which is moved directly after the shrinked mem */ +    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; +    if (lfree == mem2) { +      lfree = (struct mem *)&ram[ptr2]; +    } +    mem2 = (struct mem *)&ram[ptr2]; +    mem2->used = 0; +    /* restore the next pointer */ +    mem2->next = next; +    /* link it back to mem */ +    mem2->prev = ptr; +    /* link mem to it */ +    mem->next = ptr2; +    /* last thing to restore linked list: as we have moved mem2, +     * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not +     * the end of the heap */ +    if (mem2->next != MEM_SIZE_ALIGNED) { +      ((struct mem *)&ram[mem2->next])->prev = ptr2; +    } +    /* no need to plug holes, we've already done that */ +  } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { +    /* Next struct is used but there's room for another struct mem with +     * at least MIN_SIZE_ALIGNED of data. +     * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem +     * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). +     * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty +     *       region that couldn't hold data, but when mem->next gets freed, +     *       the 2 regions would be combined, resulting in more free memory */ +    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; +    mem2 = (struct mem *)&ram[ptr2]; +    if (mem2 < lfree) { +      lfree = mem2; +    } +    mem2->used = 0; +    mem2->next = mem->next; +    mem2->prev = ptr; +    mem->next = ptr2; +    if (mem2->next != MEM_SIZE_ALIGNED) { +      ((struct mem *)&ram[mem2->next])->prev = ptr2; +    } +    /* the original mem->next is used, so no need to plug holes! */ +  } +  /* else { +    next struct mem is used but size between mem and mem2 is not big enough +    to create another struct mem +    -> don't do anyhting.  +    -> the remaining space stays unused since it is too small +  } */ +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +  mem_free_count = 1; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ +  LWIP_MEM_FREE_UNPROTECT(); +  return rmem; +} + +/** + * Adam's mem_malloc() plus solution for bug #17922 + * Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size is the minimum size of the requested block in bytes. + * @return pointer to allocated memory or NULL if no free memory was found. + * + * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). + */ +void * +mem_malloc(mem_size_t size) +{ +  mem_size_t ptr, ptr2; +  struct mem *mem, *mem2; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +  u8_t local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ +  LWIP_MEM_ALLOC_DECL_PROTECT(); + +  if (size == 0) { +    return NULL; +  } + +  /* Expand the size of the allocated memory region so that we can +     adjust for alignment. */ +  size = LWIP_MEM_ALIGN_SIZE(size); + +  if(size < MIN_SIZE_ALIGNED) { +    /* every data block must be at least MIN_SIZE_ALIGNED long */ +    size = MIN_SIZE_ALIGNED; +  } + +  if (size > MEM_SIZE_ALIGNED) { +    return NULL; +  } + +  /* protect the heap from concurrent access */ +  sys_arch_sem_wait(mem_sem, 0); +  LWIP_MEM_ALLOC_PROTECT(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +  /* run as long as a mem_free disturbed mem_malloc */ +  do { +    local_mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +    /* Scan through the heap searching for a free block that is big enough, +     * beginning with the lowest free block. +     */ +    for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; +         ptr = ((struct mem *)&ram[ptr])->next) { +      mem = (struct mem *)&ram[ptr]; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +      mem_free_count = 0; +      LWIP_MEM_ALLOC_UNPROTECT(); +      /* allow mem_free to run */ +      LWIP_MEM_ALLOC_PROTECT(); +      if (mem_free_count != 0) { +        local_mem_free_count = mem_free_count; +      } +      mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +      if ((!mem->used) && +          (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { +        /* mem is not used and at least perfect fit is possible: +         * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ + +        if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { +          /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing +           * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') +           * -> split large block, create empty remainder, +           * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if +           * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, +           * struct mem would fit in but no data between mem2 and mem2->next +           * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty +           *       region that couldn't hold data, but when mem->next gets freed, +           *       the 2 regions would be combined, resulting in more free memory +           */ +          ptr2 = ptr + SIZEOF_STRUCT_MEM + size; +          /* create mem2 struct */ +          mem2 = (struct mem *)&ram[ptr2]; +          mem2->used = 0; +          mem2->next = mem->next; +          mem2->prev = ptr; +          /* and insert it between mem and mem->next */ +          mem->next = ptr2; +          mem->used = 1; + +          if (mem2->next != MEM_SIZE_ALIGNED) { +            ((struct mem *)&ram[mem2->next])->prev = ptr2; +          } +          MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); +        } else { +          /* (a mem2 struct does no fit into the user data space of mem and mem->next will always +           * be used at this point: if not we have 2 unused structs in a row, plug_holes should have +           * take care of this). +           * -> near fit or excact fit: do not split, no mem2 creation +           * also can't move mem->next directly behind mem, since mem->next +           * will always be used at this point! +           */ +          mem->used = 1; +          MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram)); +        } + +        if (mem == lfree) { +          /* Find next free block after mem and update lowest free pointer */ +          while (lfree->used && lfree != ram_end) { +            LWIP_MEM_ALLOC_UNPROTECT(); +            /* prevent high interrupt latency... */ +            LWIP_MEM_ALLOC_PROTECT(); +            lfree = (struct mem *)&ram[lfree->next]; +          } +          LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); +        } +        LWIP_MEM_ALLOC_UNPROTECT(); +        sys_sem_signal(mem_sem); +        LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", +         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); +        LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", +         ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); +        LWIP_ASSERT("mem_malloc: sanity check alignment", +          (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); + +        return (u8_t *)mem + SIZEOF_STRUCT_MEM; +      } +    } +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +    /* if we got interrupted by a mem_free, try again */ +  } while(local_mem_free_count != 0); +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ +  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); +  MEM_STATS_INC(err); +  LWIP_MEM_ALLOC_UNPROTECT(); +  sys_sem_signal(mem_sem); +  return NULL; +} + +#endif /* MEM_USE_POOLS */ +/** + * Contiguously allocates enough space for count objects that are size bytes + * of memory each and returns a pointer to the allocated memory. + * + * The allocated memory is filled with bytes of value zero. + * + * @param count number of objects to allocate + * @param size size of the objects to allocate + * @return pointer to allocated memory / NULL pointer if there is an error + */ +void *mem_calloc(mem_size_t count, mem_size_t size) +{ +  void *p; + +  /* allocate 'count' objects of size 'size' */ +  p = mem_malloc(count * size); +  if (p) { +    /* zero the memory */ +    memset(p, 0, count * size); +  } +  return p; +} + +#endif /* !MEM_LIBC_MALLOC */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/memp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/memp.c new file mode 100644 index 000000000..dfc32213d --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/memp.c @@ -0,0 +1,386 @@ +/** + * @file + * Dynamic pool memory manager + * + * lwIP has dedicated pools for many structures (netconn, protocol control blocks, + * packet buffers, ...). All these pools are managed here. + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/udp.h" +#include "lwip/raw.h" +#include "lwip/tcp.h" +#include "lwip/igmp.h" +#include "lwip/api.h" +#include "lwip/api_msg.h" +#include "lwip/tcpip.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "netif/etharp.h" +#include "lwip/ip_frag.h" + +#include <string.h> + +#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ + +struct memp { +  struct memp *next; +#if MEMP_OVERFLOW_CHECK +  const char *file; +  int line; +#endif /* MEMP_OVERFLOW_CHECK */ +}; + +#if MEMP_OVERFLOW_CHECK +/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning + * and at the end of each element, initialize them as 0xcd and check + * them later. */ +/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, + * every single element in each pool is checked! + * This is VERY SLOW but also very helpful. */ +/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in + * lwipopts.h to change the amount reserved for checking. */ +#ifndef MEMP_SANITY_REGION_BEFORE +#define MEMP_SANITY_REGION_BEFORE  16 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#if MEMP_SANITY_REGION_BEFORE > 0 +#define MEMP_SANITY_REGION_BEFORE_ALIGNED    LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE) +#else +#define MEMP_SANITY_REGION_BEFORE_ALIGNED    0 +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#ifndef MEMP_SANITY_REGION_AFTER +#define MEMP_SANITY_REGION_AFTER   16 +#endif /* MEMP_SANITY_REGION_AFTER*/ +#if MEMP_SANITY_REGION_AFTER > 0 +#define MEMP_SANITY_REGION_AFTER_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER) +#else +#define MEMP_SANITY_REGION_AFTER_ALIGNED     0 +#endif /* MEMP_SANITY_REGION_AFTER*/ + +/* MEMP_SIZE: save space for struct memp and for sanity check */ +#define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED) +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED) + +#else /* MEMP_OVERFLOW_CHECK */ + +/* No sanity checks + * We don't need to preserve the struct memp while not allocated, so we + * can save a little space and set MEMP_SIZE to 0. + */ +#define MEMP_SIZE           0 +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_OVERFLOW_CHECK */ + +/** This array holds the first free element of each pool. + *  Elements form a linked list. */ +static struct memp *memp_tab[MEMP_MAX]; + +#else /* MEMP_MEM_MALLOC */ + +#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_MEM_MALLOC */ + +/** This array holds the element sizes of each pool. */ +#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC +static +#endif +const u16_t memp_sizes[MEMP_MAX] = { +#define LWIP_MEMPOOL(name,num,size,desc)  LWIP_MEM_ALIGN_SIZE(size), +#include "lwip/memp_std.h" +}; + +#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ + +/** This array holds the number of elements in each pool. */ +static const u16_t memp_num[MEMP_MAX] = { +#define LWIP_MEMPOOL(name,num,size,desc)  (num), +#include "lwip/memp_std.h" +}; + +/** This array holds a textual description of each pool. */ +#ifdef LWIP_DEBUG +static const char *memp_desc[MEMP_MAX] = { +#define LWIP_MEMPOOL(name,num,size,desc)  (desc), +#include "lwip/memp_std.h" +}; +#endif /* LWIP_DEBUG */ + +/** This is the actual memory used by the pools. */ +static u8_t memp_memory[MEM_ALIGNMENT - 1  +#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) ) +#include "lwip/memp_std.h" +]; + +#if MEMP_SANITY_CHECK +/** + * Check that memp-lists don't form a circle + */ +static int +memp_sanity(void) +{ +  s16_t i, c; +  struct memp *m, *n; + +  for (i = 0; i < MEMP_MAX; i++) { +    for (m = memp_tab[i]; m != NULL; m = m->next) { +      c = 1; +      for (n = memp_tab[i]; n != NULL; n = n->next) { +        if (n == m && --c < 0) { +          return 0; +        } +      } +    } +  } +  return 1; +} +#endif /* MEMP_SANITY_CHECK*/ +#if MEMP_OVERFLOW_CHECK +/** + * Check if a memp element was victim of an overflow + * (e.g. the restricted area after it has been altered) + * + * @param p the memp element to check + * @param memp_size the element size of the pool p comes from + */ +static void +memp_overflow_check_element(struct memp *p, u16_t memp_size) +{ +  u16_t k; +  u8_t *m; +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 +  m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; +  for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { +    if (m[k] != 0xcd) { +      LWIP_ASSERT("detected memp underflow!", 0); +    } +  } +#endif +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 +  m = (u8_t*)p + MEMP_SIZE + memp_size; +  for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { +    if (m[k] != 0xcd) { +      LWIP_ASSERT("detected memp overflow!", 0); +    } +  } +#endif +} + +/** + * Do an overflow check for all elements in every pool. + * + * @see memp_overflow_check_element for a description of the check + */ +static void +memp_overflow_check_all(void) +{ +  u16_t i, j; +  struct memp *p; + +  p = LWIP_MEM_ALIGN(memp_memory); +  for (i = 0; i < MEMP_MAX; ++i) { +    p = p; +    for (j = 0; j < memp_num[i]; ++j) { +      memp_overflow_check_element(p, memp_sizes[i]); +      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); +    } +  } +} + +/** + * Initialize the restricted areas of all memp elements in every pool. + */ +static void +memp_overflow_init(void) +{ +  u16_t i, j; +  struct memp *p; +  u8_t *m; + +  p = LWIP_MEM_ALIGN(memp_memory); +  for (i = 0; i < MEMP_MAX; ++i) { +    p = p; +    for (j = 0; j < memp_num[i]; ++j) { +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 +      m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; +      memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); +#endif +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 +      m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; +      memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); +#endif +      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); +    } +  } +} +#endif /* MEMP_OVERFLOW_CHECK */ + +/** + * Initialize this module. + *  + * Carves out memp_memory into linked lists for each pool-type. + */ +void +memp_init(void) +{ +  struct memp *memp; +  u16_t i, j; + +  for (i = 0; i < MEMP_MAX; ++i) { +    MEMP_STATS_AVAIL(used, i, 0); +    MEMP_STATS_AVAIL(max, i, 0); +    MEMP_STATS_AVAIL(err, i, 0); +    MEMP_STATS_AVAIL(avail, i, memp_num[i]); +  } + +  memp = LWIP_MEM_ALIGN(memp_memory); +  /* for every pool: */ +  for (i = 0; i < MEMP_MAX; ++i) { +    memp_tab[i] = NULL; +    /* create a linked list of memp elements */ +    for (j = 0; j < memp_num[i]; ++j) { +      memp->next = memp_tab[i]; +      memp_tab[i] = memp; +      memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] +#if MEMP_OVERFLOW_CHECK +        + MEMP_SANITY_REGION_AFTER_ALIGNED +#endif +      ); +    } +  } +#if MEMP_OVERFLOW_CHECK +  memp_overflow_init(); +  /* check everything a first time to see if it worked */ +  memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK */ +} + +/** + * Get an element from a specific pool. + * + * @param type the pool to get an element from + * + * the debug version has two more parameters: + * @param file file name calling this function + * @param line number of line where this function is called + * + * @return a pointer to the allocated memory or a NULL pointer on error + */ +void * +#if !MEMP_OVERFLOW_CHECK +memp_malloc(memp_t type) +#else +memp_malloc_fn(memp_t type, const char* file, const int line) +#endif +{ +  struct memp *memp; +  SYS_ARCH_DECL_PROTECT(old_level); +  +  LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); + +  SYS_ARCH_PROTECT(old_level); +#if MEMP_OVERFLOW_CHECK >= 2 +  memp_overflow_check_all(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ + +  memp = memp_tab[type]; +   +  if (memp != NULL) { +    memp_tab[type] = memp->next; +#if MEMP_OVERFLOW_CHECK +    memp->next = NULL; +    memp->file = file; +    memp->line = line; +#endif /* MEMP_OVERFLOW_CHECK */ +    MEMP_STATS_INC_USED(used, type); +    LWIP_ASSERT("memp_malloc: memp properly aligned", +                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); +    memp = (struct memp*)((u8_t*)memp + MEMP_SIZE); +  } else { +    LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type])); +    MEMP_STATS_INC(err, type); +  } + +  SYS_ARCH_UNPROTECT(old_level); + +  return memp; +} + +/** + * Put an element back into its pool. + * + * @param type the pool where to put mem + * @param mem the memp element to free + */ +void +memp_free(memp_t type, void *mem) +{ +  struct memp *memp; +  SYS_ARCH_DECL_PROTECT(old_level); + +  if (mem == NULL) { +    return; +  } +  LWIP_ASSERT("memp_free: mem properly aligned", +                ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); + +  memp = (struct memp *)((u8_t*)mem - MEMP_SIZE); + +  SYS_ARCH_PROTECT(old_level); +#if MEMP_OVERFLOW_CHECK +#if MEMP_OVERFLOW_CHECK >= 2 +  memp_overflow_check_all(); +#else +  memp_overflow_check_element(memp, memp_sizes[type]); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ +#endif /* MEMP_OVERFLOW_CHECK */ + +  MEMP_STATS_DEC(used, type);  +   +  memp->next = memp_tab[type];  +  memp_tab[type] = memp; + +#if MEMP_SANITY_CHECK +  LWIP_ASSERT("memp sanity", memp_sanity()); +#endif /* MEMP_SANITY_CHECK */ + +  SYS_ARCH_UNPROTECT(old_level); +} + +#endif /* MEMP_MEM_MALLOC */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/netif.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/netif.c new file mode 100644 index 000000000..c9b6b9b5e --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/netif.c @@ -0,0 +1,655 @@ +/** + * @file + * lwIP network interface abstraction + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/tcp.h" +#include "lwip/snmp.h" +#include "lwip/igmp.h" +#include "netif/etharp.h" +#if ENABLE_LOOPBACK +#include "lwip/sys.h" +#if LWIP_NETIF_LOOPBACK_MULTITHREADING +#include "lwip/tcpip.h" +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#if LWIP_NETIF_STATUS_CALLBACK +#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); } +#else +#define NETIF_STATUS_CALLBACK(n) { /* NOP */ } +#endif /* LWIP_NETIF_STATUS_CALLBACK */  + +#if LWIP_NETIF_LINK_CALLBACK +#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); } +#else +#define NETIF_LINK_CALLBACK(n) { /* NOP */ } +#endif /* LWIP_NETIF_LINK_CALLBACK */  + +struct netif *netif_list; +struct netif *netif_default; + +/** + * Add a network interface to the list of lwIP netifs. + * + * @param netif a pre-allocated netif structure + * @param ipaddr IP address for the new netif + * @param netmask network mask for the new netif + * @param gw default gateway IP address for the new netif + * @param state opaque data passed to the new netif + * @param init callback function that initializes the interface + * @param input callback function that is called to pass + * ingress packets up in the protocol layer stack. + * + * @return netif, or NULL if failed. + */ +struct netif * +netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, +  struct ip_addr *gw, +  void *state, +  err_t (* init)(struct netif *netif), +  err_t (* input)(struct pbuf *p, struct netif *netif)) +{ +  static u8_t netifnum = 0; + +  /* reset new interface configuration state */ +  netif->ip_addr.addr = 0; +  netif->netmask.addr = 0; +  netif->gw.addr = 0; +  netif->flags = 0; +#if LWIP_DHCP +  /* netif not under DHCP control by default */ +  netif->dhcp = NULL; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP +  /* netif not under AutoIP control by default */ +  netif->autoip = NULL; +#endif /* LWIP_AUTOIP */ +#if LWIP_NETIF_STATUS_CALLBACK +  netif->status_callback = NULL; +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK +  netif->link_callback = NULL; +#endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_IGMP +  netif->igmp_mac_filter = NULL; +#endif /* LWIP_IGMP */ +#if ENABLE_LOOPBACK +  netif->loop_first = NULL; +  netif->loop_last = NULL; +#endif /* ENABLE_LOOPBACK */ + +  /* remember netif specific state information data */ +  netif->state = state; +  netif->num = netifnum++; +  netif->input = input; +#if LWIP_NETIF_HWADDRHINT +  netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ +#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS +  netif->loop_cnt_current = 0; +#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ + +  netif_set_addr(netif, ipaddr, netmask, gw); + +  /* call user specified initialization function for netif */ +  if (init(netif) != ERR_OK) { +    return NULL; +  } + +  /* add this netif to the list */ +  netif->next = netif_list; +  netif_list = netif; +  snmp_inc_iflist(); + +#if LWIP_IGMP +  /* start IGMP processing */ +  if (netif->flags & NETIF_FLAG_IGMP) { +    igmp_start( netif); +  } +#endif /* LWIP_IGMP */ + +  LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", +    netif->name[0], netif->name[1])); +  ip_addr_debug_print(NETIF_DEBUG, ipaddr); +  LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); +  ip_addr_debug_print(NETIF_DEBUG, netmask); +  LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); +  ip_addr_debug_print(NETIF_DEBUG, gw); +  LWIP_DEBUGF(NETIF_DEBUG, ("\n")); +  return netif; +} + +/** + * Change IP address configuration for a network interface (including netmask + * and default gateway). + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * @param netmask the new netmask + * @param gw the new default gateway + */ +void +netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, +    struct ip_addr *gw) +{ +  netif_set_ipaddr(netif, ipaddr); +  netif_set_netmask(netif, netmask); +  netif_set_gw(netif, gw); +} + +/** + * Remove a network interface from the list of lwIP netifs. + * + * @param netif the network interface to remove + */ +void netif_remove(struct netif * netif) +{ +  if ( netif == NULL ) return; + +#if LWIP_IGMP +  /* stop IGMP processing */ +  if (netif->flags & NETIF_FLAG_IGMP) { +    igmp_stop( netif); +  } +#endif /* LWIP_IGMP */ + +  snmp_delete_ipaddridx_tree(netif); + +  /*  is it the first netif? */ +  if (netif_list == netif) { +    netif_list = netif->next; +    snmp_dec_iflist(); +  } +  else { +    /*  look for netif further down the list */ +    struct netif * tmpNetif; +    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { +      if (tmpNetif->next == netif) { +        tmpNetif->next = netif->next; +        snmp_dec_iflist(); +        break; +      } +    } +    if (tmpNetif == NULL) +      return; /*  we didn't find any netif today */ +  } +  /* this netif is default? */ +  if (netif_default == netif) +    /* reset default netif */ +    netif_set_default(NULL); +  LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); +} + +/** + * Find a network interface by searching for its name + * + * @param name the name of the netif (like netif->name) plus concatenated number + * in ascii representation (e.g. 'en0') + */ +struct netif * +netif_find(char *name) +{ +  struct netif *netif; +  u8_t num; + +  if (name == NULL) { +    return NULL; +  } + +  num = name[2] - '0'; + +  for(netif = netif_list; netif != NULL; netif = netif->next) { +    if (num == netif->num && +       name[0] == netif->name[0] && +       name[1] == netif->name[1]) { +      LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); +      return netif; +    } +  } +  LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); +  return NULL; +} + +/** + * Change the IP address of a network interface + * + * @param netif the network interface to change + * @param ipaddr the new IP address + * + * @note call netif_set_addr() if you also want to change netmask and + * default gateway + */ +void +netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) +{ +  /* TODO: Handling of obsolete pcbs */ +  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ +#if LWIP_TCP +  struct tcp_pcb *pcb; +  struct tcp_pcb_listen *lpcb; + +  /* address is actually being changed? */ +  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) +  { +    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ +    LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n")); +    pcb = tcp_active_pcbs; +    while (pcb != NULL) { +      /* PCB bound to current local interface address? */ +      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { +        /* this connection must be aborted */ +        struct tcp_pcb *next = pcb->next; +        LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); +        tcp_abort(pcb); +        pcb = next; +      } else { +        pcb = pcb->next; +      } +    } +    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { +      /* PCB bound to current local interface address? */ +      if ((!(ip_addr_isany(&(lpcb->local_ip)))) && +          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) { +        /* The PCB is listening to the old ipaddr and +         * is set to listen to the new one instead */ +        ip_addr_set(&(lpcb->local_ip), ipaddr); +      } +    } +  } +#endif +  snmp_delete_ipaddridx_tree(netif); +  snmp_delete_iprteidx_tree(0,netif); +  /* set new IP address to netif */ +  ip_addr_set(&(netif->ip_addr), ipaddr); +  snmp_insert_ipaddridx_tree(netif); +  snmp_insert_iprteidx_tree(0,netif); + +  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +    netif->name[0], netif->name[1], +    ip4_addr1(&netif->ip_addr), +    ip4_addr2(&netif->ip_addr), +    ip4_addr3(&netif->ip_addr), +    ip4_addr4(&netif->ip_addr))); +} + +/** + * Change the default gateway for a network interface + * + * @param netif the network interface to change + * @param gw the new default gateway + * + * @note call netif_set_addr() if you also want to change ip address and netmask + */ +void +netif_set_gw(struct netif *netif, struct ip_addr *gw) +{ +  ip_addr_set(&(netif->gw), gw); +  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +    netif->name[0], netif->name[1], +    ip4_addr1(&netif->gw), +    ip4_addr2(&netif->gw), +    ip4_addr3(&netif->gw), +    ip4_addr4(&netif->gw))); +} + +/** + * Change the netmask of a network interface + * + * @param netif the network interface to change + * @param netmask the new netmask + * + * @note call netif_set_addr() if you also want to change ip address and + * default gateway + */ +void +netif_set_netmask(struct netif *netif, struct ip_addr *netmask) +{ +  snmp_delete_iprteidx_tree(0, netif); +  /* set new netmask to netif */ +  ip_addr_set(&(netif->netmask), netmask); +  snmp_insert_iprteidx_tree(0, netif); +  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +    netif->name[0], netif->name[1], +    ip4_addr1(&netif->netmask), +    ip4_addr2(&netif->netmask), +    ip4_addr3(&netif->netmask), +    ip4_addr4(&netif->netmask))); +} + +/** + * Set a network interface as the default network interface + * (used to output all packets for which no specific route is found) + * + * @param netif the default network interface + */ +void +netif_set_default(struct netif *netif) +{ +  if (netif == NULL) +  { +    /* remove default route */ +    snmp_delete_iprteidx_tree(1, netif); +  } +  else +  { +    /* install default route */ +    snmp_insert_iprteidx_tree(1, netif); +  } +  netif_default = netif; +  LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", +           netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); +} + +/** + * Bring an interface up, available for processing + * traffic. + *  + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + *  + * @see dhcp_start() + */  +void netif_set_up(struct netif *netif) +{ +  if ( !(netif->flags & NETIF_FLAG_UP )) { +    netif->flags |= NETIF_FLAG_UP; +     +#if LWIP_SNMP +    snmp_get_sysuptime(&netif->ts); +#endif /* LWIP_SNMP */ + +    NETIF_LINK_CALLBACK(netif); +    NETIF_STATUS_CALLBACK(netif); + +#if LWIP_ARP +    /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */  +    if (netif->flags & NETIF_FLAG_ETHARP) { +      etharp_gratuitous(netif); +    } +#endif /* LWIP_ARP */ +     +  } +} + +/** + * Bring an interface down, disabling any traffic processing. + * + * @note: Enabling DHCP on a down interface will make it come + * up once configured. + *  + * @see dhcp_start() + */  +void netif_set_down(struct netif *netif) +{ +  if ( netif->flags & NETIF_FLAG_UP ) +    { +      netif->flags &= ~NETIF_FLAG_UP; +#if LWIP_SNMP +      snmp_get_sysuptime(&netif->ts); +#endif +       +      NETIF_LINK_CALLBACK(netif); +      NETIF_STATUS_CALLBACK(netif); +    } +} + +/** + * Ask if an interface is up + */  +u8_t netif_is_up(struct netif *netif) +{ +  return (netif->flags & NETIF_FLAG_UP)?1:0; +} + +#if LWIP_NETIF_STATUS_CALLBACK +/** + * Set callback to be called when interface is brought up/down + */ +void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif )) +{ +    if ( netif ) +        netif->status_callback = status_callback; +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +/** + * Called by a driver when its link goes up + */ +void netif_set_link_up(struct netif *netif ) +{ +  netif->flags |= NETIF_FLAG_LINK_UP; + +#if LWIP_ARP +  /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */  +  if (netif->flags & NETIF_FLAG_ETHARP) { +    etharp_gratuitous(netif); +  } +#endif /* LWIP_ARP */ + +#if LWIP_IGMP +  /* resend IGMP memberships */ +  if (netif->flags & NETIF_FLAG_IGMP) { +    igmp_report_groups( netif); +  } +#endif /* LWIP_IGMP */ + +  NETIF_LINK_CALLBACK(netif); +} + +/** + * Called by a driver when its link goes down + */ +void netif_set_link_down(struct netif *netif ) +{ +  netif->flags &= ~NETIF_FLAG_LINK_UP; +  NETIF_LINK_CALLBACK(netif); +} + +/** + * Ask if a link is up + */  +u8_t netif_is_link_up(struct netif *netif) +{ +  return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0; +} + +/** + * Set callback to be called when link is brought up/down + */ +void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif )) +{ +  if (netif) { +    netif->link_callback = link_callback; +  } +} +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if ENABLE_LOOPBACK +/** + * Send an IP packet to be received on the same netif (loopif-like). + * The pbuf is simply copied and handed back to netif->input. + * In multithreaded mode, this is done directly since netif->input must put + * the packet on a queue. + * In callback mode, the packet is put on an internal queue and is fed to + * netif->input by netif_poll(). + * + * @param netif the lwip network interface structure + * @param p the (IP) packet to 'send' + * @param ipaddr the ip address to send the packet to (not used) + * @return ERR_OK if the packet has been sent + *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated + */ +err_t +netif_loop_output(struct netif *netif, struct pbuf *p, +       struct ip_addr *ipaddr) +{ +  struct pbuf *r; +  err_t err; +  struct pbuf *last; +#if LWIP_LOOPBACK_MAX_PBUFS +  u8_t clen = 0; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +  SYS_ARCH_DECL_PROTECT(lev); +  LWIP_UNUSED_ARG(ipaddr); + +  /* Allocate a new pbuf */ +  r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); +  if (r == NULL) { +    return ERR_MEM; +  } +#if LWIP_LOOPBACK_MAX_PBUFS +  clen = pbuf_clen(r); +  /* check for overflow or too many pbuf on queue */ +  if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || +    ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { +      pbuf_free(r); +      r = NULL; +      return ERR_MEM; +  } +  netif->loop_cnt_current += clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ + +  /* Copy the whole pbuf queue p into the single pbuf r */ +  if ((err = pbuf_copy(r, p)) != ERR_OK) { +    pbuf_free(r); +    r = NULL; +    return err; +  } + +  /* Put the packet on a linked list which gets emptied through calling +     netif_poll(). */ + +  /* let last point to the last pbuf in chain r */ +  for (last = r; last->next != NULL; last = last->next); + +  SYS_ARCH_PROTECT(lev); +  if(netif->loop_first != NULL) { +    LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); +    netif->loop_last->next = r; +    netif->loop_last = last; +  } else { +    netif->loop_first = r; +    netif->loop_last = last; +  } +  SYS_ARCH_UNPROTECT(lev); + +#if LWIP_NETIF_LOOPBACK_MULTITHREADING +  /* For multithreading environment, schedule a call to netif_poll */ +  tcpip_callback((void (*)(void *))(netif_poll), netif); +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + +  return ERR_OK; +} + +/** + * Call netif_poll() in the main loop of your application. This is to prevent + * reentering non-reentrant functions like tcp_input(). Packets passed to + * netif_loop_output() are put on a list that is passed to netif->input() by + * netif_poll(). + */ +void +netif_poll(struct netif *netif) +{ +  struct pbuf *in; +  SYS_ARCH_DECL_PROTECT(lev); + +  do { +    /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ +    SYS_ARCH_PROTECT(lev); +    in = netif->loop_first; +    if(in != NULL) { +      struct pbuf *in_end = in; +#if LWIP_LOOPBACK_MAX_PBUFS +      u8_t clen = pbuf_clen(in); +      /* adjust the number of pbufs on queue */ +      LWIP_ASSERT("netif->loop_cnt_current underflow", +        ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); +      netif->loop_cnt_current -= clen; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +      while(in_end->len != in_end->tot_len) { +        LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); +        in_end = in_end->next; +      } +      /* 'in_end' now points to the last pbuf from 'in' */ +      if(in_end == netif->loop_last) { +        /* this was the last pbuf in the list */ +        netif->loop_first = netif->loop_last = NULL; +      } else { +        /* pop the pbuf off the list */ +        netif->loop_first = in_end->next; +        LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); +      } +      /* De-queue the pbuf from its successors on the 'loop_' list. */ +      in_end->next = NULL; +    } +    SYS_ARCH_UNPROTECT(lev); + +    if(in != NULL) { +      /* loopback packets are always IP packets! */ +      if(ip_input(in, netif) != ERR_OK) { +        pbuf_free(in); +      } +      /* Don't reference the packet any more! */ +      in = NULL; +    } +  /* go on while there is a packet on the list */ +  } while(netif->loop_first != NULL); +} + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +/** + * Calls netif_poll() for every netif on the netif_list. + */ +void +netif_poll_all(void) +{ +  struct netif *netif = netif_list; +  /* loop through netifs */ +  while (netif != NULL) { +    netif_poll(netif); +    /* proceed to next network interface */ +    netif = netif->next; +  } +} +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/pbuf.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/pbuf.c new file mode 100644 index 000000000..50b22c354 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/pbuf.c @@ -0,0 +1,895 @@ +/** + * @file + * Packet buffer management + * + * Packets are built from the pbuf data structure. It supports dynamic + * memory allocation for packet contents or can reference externally + * managed packet contents both in RAM and ROM. Quick allocation for + * incoming packets is provided through pools with fixed sized pbufs. + * + * A packet may span over multiple pbufs, chained as a singly linked + * list. This is called a "pbuf chain". + * + * Multiple packets may be queued, also using this singly linked list. + * This is called a "packet queue". + *  + * So, a packet queue consists of one or more pbuf chains, each of + * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE + * NOT SUPPORTED!!! Use helper structs to queue multiple packets. + *  + * The differences between a pbuf chain and a packet queue are very + * precise but subtle.  + * + * The last pbuf of a packet has a ->tot_len field that equals the + * ->len field. It can be found by traversing the list. If the last + * pbuf of a packet has a ->next field other than NULL, more packets + * are on the queue. + * + * Therefore, looping through a pbuf of a single packet, has an + * loop end condition (tot_len == p->len), NOT (next == NULL). + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/stats.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "arch/perf.h" +#if TCP_QUEUE_OOSEQ +#include "lwip/tcp.h" +#endif + +#include <string.h> + +#define SIZEOF_STRUCT_PBUF        LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) +/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically +   aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ +#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) + +#if TCP_QUEUE_OOSEQ +#define ALLOC_POOL_PBUF(p) do { (p) = alloc_pool_pbuf(); } while (0) +#else +#define ALLOC_POOL_PBUF(p) do { (p) = memp_malloc(MEMP_PBUF_POOL); } while (0) +#endif + + +#if TCP_QUEUE_OOSEQ +/** + * Attempt to reclaim some memory from queued out-of-sequence TCP segments + * if we run out of pool pbufs. It's better to give priority to new packets + * if we're running out. + * + * @return the allocated pbuf. + */ +static struct pbuf * +alloc_pool_pbuf(void) +{ +  struct tcp_pcb *pcb; +  struct pbuf *p; + +retry: +  p = memp_malloc(MEMP_PBUF_POOL); +  if (NULL == p) { +    for (pcb=tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { +      if (NULL != pcb->ooseq) { +        tcp_segs_free(pcb->ooseq); +        pcb->ooseq = NULL; +        goto retry; +      } +    } +  } +  return p; +} +#endif /* TCP_QUEUE_OOSEQ */ + +/** + * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). + * + * The actual memory allocated for the pbuf is determined by the + * layer at which the pbuf is allocated and the requested size + * (from the size parameter). + * + * @param layer flag to define header size + * @param length size of the pbuf's payload + * @param type this parameter decides how and where the pbuf + * should be allocated as follows: + * + * - PBUF_RAM: buffer memory for pbuf is allocated as one large + *             chunk. This includes protocol headers as well. + * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for + *             protocol headers. Additional headers must be prepended + *             by allocating another pbuf and chain in to the front of + *             the ROM pbuf. It is assumed that the memory used is really + *             similar to ROM in that it is immutable and will not be + *             changed. Memory which is dynamic should generally not + *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead. + * - PBUF_REF: no buffer memory is allocated for the pbuf, even for + *             protocol headers. It is assumed that the pbuf is only + *             being used in a single thread. If the pbuf gets queued, + *             then pbuf_take should be called to copy the buffer. + * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from + *              the pbuf pool that is allocated during pbuf_init(). + * + * @return the allocated pbuf. If multiple pbufs where allocated, this + * is the first pbuf of a pbuf chain. + */ +struct pbuf * +pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) +{ +  struct pbuf *p, *q, *r; +  u16_t offset; +  s32_t rem_len; /* remaining length */ +  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length)); + +  /* determine header offset */ +  offset = 0; +  switch (layer) { +  case PBUF_TRANSPORT: +    /* add room for transport (often TCP) layer header */ +    offset += PBUF_TRANSPORT_HLEN; +    /* FALLTHROUGH */ +  case PBUF_IP: +    /* add room for IP layer header */ +    offset += PBUF_IP_HLEN; +    /* FALLTHROUGH */ +  case PBUF_LINK: +    /* add room for link layer header */ +    offset += PBUF_LINK_HLEN; +    break; +  case PBUF_RAW: +    break; +  default: +    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); +    return NULL; +  } + +  switch (type) { +  case PBUF_POOL: +    /* allocate head of pbuf chain into p */ +    ALLOC_POOL_PBUF(p); +    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); +    if (p == NULL) { +      return NULL; +    } +    p->type = type; +    p->next = NULL; + +    /* make the payload pointer point 'offset' bytes into pbuf data memory */ +    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); +    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", +            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); +    /* the total length of the pbuf chain is the requested size */ +    p->tot_len = length; +    /* set the length of the first pbuf in the chain */ +    p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); +    LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", +                ((u8_t*)p->payload + p->len <= +                 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); +    LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", +      (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); +    /* set reference count (needed here in case we fail) */ +    p->ref = 1; + +    /* now allocate the tail of the pbuf chain */ + +    /* remember first pbuf for linkage in next iteration */ +    r = p; +    /* remaining length to be allocated */ +    rem_len = length - p->len; +    /* any remaining pbufs to be allocated? */ +    while (rem_len > 0) { +      ALLOC_POOL_PBUF(q); +      if (q == NULL) { +        /* free chain so far allocated */ +        pbuf_free(p); +        /* bail out unsuccesfully */ +        return NULL; +      } +      q->type = type; +      q->flags = 0; +      q->next = NULL; +      /* make previous pbuf point to this pbuf */ +      r->next = q; +      /* set total length of this pbuf and next in chain */ +      LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); +      q->tot_len = (u16_t)rem_len; +      /* this pbuf length is pool size, unless smaller sized tail */ +      q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); +      q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); +      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", +              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); +      LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", +                  ((u8_t*)p->payload + p->len <= +                   (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); +      q->ref = 1; +      /* calculate remaining length to be allocated */ +      rem_len -= q->len; +      /* remember this pbuf for linkage in next iteration */ +      r = q; +    } +    /* end of chain */ +    /*r->next = NULL;*/ + +    break; +  case PBUF_RAM: +    /* If pbuf is to be allocated in RAM, allocate memory for it. */ +    p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); +    if (p == NULL) { +      return NULL; +    } +    /* Set up internal structure of the pbuf. */ +    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); +    p->len = p->tot_len = length; +    p->next = NULL; +    p->type = type; + +    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", +           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); +    break; +  /* pbuf references existing (non-volatile static constant) ROM payload? */ +  case PBUF_ROM: +  /* pbuf references existing (externally allocated) RAM payload? */ +  case PBUF_REF: +    /* only allocate memory for the pbuf structure */ +    p = memp_malloc(MEMP_PBUF); +    if (p == NULL) { +      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", +                  (type == PBUF_ROM) ? "ROM" : "REF")); +      return NULL; +    } +    /* caller must set this field properly, afterwards */ +    p->payload = NULL; +    p->len = p->tot_len = length; +    p->next = NULL; +    p->type = type; +    break; +  default: +    LWIP_ASSERT("pbuf_alloc: erroneous type", 0); +    return NULL; +  } +  /* set reference count */ +  p->ref = 1; +  /* set flags */ +  p->flags = 0; +  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); +  return p; +} + + +/** + * Shrink a pbuf chain to a desired length. + * + * @param p pbuf to shrink. + * @param new_len desired new length of pbuf chain + * + * Depending on the desired length, the first few pbufs in a chain might + * be skipped and left unchanged. The new last pbuf in the chain will be + * resized, and any remaining pbufs will be freed. + * + * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. + * @note May not be called on a packet queue. + * + * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). + */ +void +pbuf_realloc(struct pbuf *p, u16_t new_len) +{ +  struct pbuf *q; +  u16_t rem_len; /* remaining length */ +  s32_t grow; + +  LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); +  LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || +              p->type == PBUF_ROM || +              p->type == PBUF_RAM || +              p->type == PBUF_REF); + +  /* desired length larger than current length? */ +  if (new_len >= p->tot_len) { +    /* enlarging not yet supported */ +    return; +  } + +  /* the pbuf chain grows by (new_len - p->tot_len) bytes +   * (which may be negative in case of shrinking) */ +  grow = new_len - p->tot_len; + +  /* first, step over any pbufs that should remain in the chain */ +  rem_len = new_len; +  q = p; +  /* should this pbuf be kept? */ +  while (rem_len > q->len) { +    /* decrease remaining length by pbuf length */ +    rem_len -= q->len; +    /* decrease total length indicator */ +    LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); +    q->tot_len += (u16_t)grow; +    /* proceed to next pbuf in chain */ +    q = q->next; +    LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); +  } +  /* we have now reached the new last pbuf (in q) */ +  /* rem_len == desired length for pbuf q */ + +  /* shrink allocated memory for PBUF_RAM */ +  /* (other types merely adjust their length fields */ +  if ((q->type == PBUF_RAM) && (rem_len != q->len)) { +    /* reallocate and adjust the length of the pbuf that will be split */ +    q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len); +    LWIP_ASSERT("mem_realloc give q == NULL", q != NULL); +  } +  /* adjust length fields for new last pbuf */ +  q->len = rem_len; +  q->tot_len = q->len; + +  /* any remaining pbufs in chain? */ +  if (q->next != NULL) { +    /* free remaining pbufs in chain */ +    pbuf_free(q->next); +  } +  /* q is last packet in chain */ +  q->next = NULL; + +} + +/** + * Adjusts the payload pointer to hide or reveal headers in the payload. + * + * Adjusts the ->payload pointer so that space for a header + * (dis)appears in the pbuf payload. + * + * The ->payload, ->tot_len and ->len fields are adjusted. + * + * @param p pbuf to change the header size. + * @param header_size_increment Number of bytes to increment header size which + * increases the size of the pbuf. New space is on the front. + * (Using a negative value decreases the header size.) + * If hdr_size_inc is 0, this function does nothing and returns succesful. + * + * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so + * the call will fail. A check is made that the increase in header size does + * not move the payload pointer in front of the start of the buffer. + * @return non-zero on failure, zero on success. + * + */ +u8_t +pbuf_header(struct pbuf *p, s16_t header_size_increment) +{ +  u16_t type; +  void *payload; +  u16_t increment_magnitude; + +  LWIP_ASSERT("p != NULL", p != NULL); +  if ((header_size_increment == 0) || (p == NULL)) +    return 0; +  +  if (header_size_increment < 0){ +    increment_magnitude = -header_size_increment; +    /* Check that we aren't going to move off the end of the pbuf */ +    LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); +  } else { +    increment_magnitude = header_size_increment; +#if 0 +    /* Can't assert these as some callers speculatively call +         pbuf_header() to see if it's OK.  Will return 1 below instead. */ +    /* Check that we've got the correct type of pbuf to work with */ +    LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",  +                p->type == PBUF_RAM || p->type == PBUF_POOL); +    /* Check that we aren't going to move off the beginning of the pbuf */ +    LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", +                (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); +#endif +  } + +  type = p->type; +  /* remember current payload pointer */ +  payload = p->payload; + +  /* pbuf types containing payloads? */ +  if (type == PBUF_RAM || type == PBUF_POOL) { +    /* set new payload pointer */ +    p->payload = (u8_t *)p->payload - header_size_increment; +    /* boundary check fails? */ +    if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { +      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", +        (void *)p->payload, +        (void *)(p + 1)));\ +      /* restore old payload pointer */ +      p->payload = payload; +      /* bail out unsuccesfully */ +      return 1; +    } +  /* pbuf types refering to external payloads? */ +  } else if (type == PBUF_REF || type == PBUF_ROM) { +    /* hide a header in the payload? */ +    if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { +      /* increase payload pointer */ +      p->payload = (u8_t *)p->payload - header_size_increment; +    } else { +      /* cannot expand payload to front (yet!) +       * bail out unsuccesfully */ +      return 1; +    } +  } +  else { +    /* Unknown type */ +    LWIP_ASSERT("bad pbuf type", 0); +    return 1; +  } +  /* modify pbuf length fields */ +  p->len += header_size_increment; +  p->tot_len += header_size_increment; + +  LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n", +    (void *)payload, (void *)p->payload, header_size_increment)); + +  return 0; +} + +/** + * Dereference a pbuf chain or queue and deallocate any no-longer-used + * pbufs at the head of this chain or queue. + * + * Decrements the pbuf reference count. If it reaches zero, the pbuf is + * deallocated. + * + * For a pbuf chain, this is repeated for each pbuf in the chain, + * up to the first pbuf which has a non-zero reference count after + * decrementing. So, when all reference counts are one, the whole + * chain is free'd. + * + * @param p The pbuf (chain) to be dereferenced. + * + * @return the number of pbufs that were de-allocated + * from the head of the chain. + * + * @note MUST NOT be called on a packet queue (Not verified to work yet). + * @note the reference counter of a pbuf equals the number of pointers + * that refer to the pbuf (or into the pbuf). + * + * @internal examples: + * + * Assuming existing chains a->b->c with the following reference + * counts, calling pbuf_free(a) results in: + *  + * 1->2->3 becomes ...1->3 + * 3->3->3 becomes 2->3->3 + * 1->1->2 becomes ......1 + * 2->1->1 becomes 1->1->1 + * 1->1->1 becomes ....... + * + */ +u8_t +pbuf_free(struct pbuf *p) +{ +  u16_t type; +  struct pbuf *q; +  u8_t count; + +  if (p == NULL) { +    LWIP_ASSERT("p != NULL", p != NULL); +    /* if assertions are disabled, proceed with debug output */ +    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); +    return 0; +  } +  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p)); + +  PERF_START; + +  LWIP_ASSERT("pbuf_free: sane type", +    p->type == PBUF_RAM || p->type == PBUF_ROM || +    p->type == PBUF_REF || p->type == PBUF_POOL); + +  count = 0; +  /* de-allocate all consecutive pbufs from the head of the chain that +   * obtain a zero reference count after decrementing*/ +  while (p != NULL) { +    u16_t ref; +    SYS_ARCH_DECL_PROTECT(old_level); +    /* Since decrementing ref cannot be guaranteed to be a single machine operation +     * we must protect it. We put the new ref into a local variable to prevent +     * further protection. */ +    SYS_ARCH_PROTECT(old_level); +    /* all pbufs in a chain are referenced at least once */ +    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); +    /* decrease reference count (number of pointers to pbuf) */ +    ref = --(p->ref); +    SYS_ARCH_UNPROTECT(old_level); +    /* this pbuf is no longer referenced to? */ +    if (ref == 0) { +      /* remember next pbuf in chain for next iteration */ +      q = p->next; +      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p)); +      type = p->type; +      /* is this a pbuf from the pool? */ +      if (type == PBUF_POOL) { +        memp_free(MEMP_PBUF_POOL, p); +      /* is this a ROM or RAM referencing pbuf? */ +      } else if (type == PBUF_ROM || type == PBUF_REF) { +        memp_free(MEMP_PBUF, p); +      /* type == PBUF_RAM */ +      } else { +        mem_free(p); +      } +      count++; +      /* proceed to next pbuf */ +      p = q; +    /* p->ref > 0, this pbuf is still referenced to */ +    /* (and so the remaining pbufs in chain as well) */ +    } else { +      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); +      /* stop walking through the chain */ +      p = NULL; +    } +  } +  PERF_STOP("pbuf_free"); +  /* return number of de-allocated pbufs */ +  return count; +} + +/** + * Count number of pbufs in a chain + * + * @param p first pbuf of chain + * @return the number of pbufs in a chain + */ + +u8_t +pbuf_clen(struct pbuf *p) +{ +  u8_t len; + +  len = 0; +  while (p != NULL) { +    ++len; +    p = p->next; +  } +  return len; +} + +/** + * Increment the reference count of the pbuf. + * + * @param p pbuf to increase reference counter of + * + */ +void +pbuf_ref(struct pbuf *p) +{ +  SYS_ARCH_DECL_PROTECT(old_level); +  /* pbuf given? */ +  if (p != NULL) { +    SYS_ARCH_PROTECT(old_level); +    ++(p->ref); +    SYS_ARCH_UNPROTECT(old_level); +  } +} + +/** + * Concatenate two pbufs (each may be a pbuf chain) and take over + * the caller's reference of the tail pbuf. + *  + * @note The caller MAY NOT reference the tail pbuf afterwards. + * Use pbuf_chain() for that purpose. + *  + * @see pbuf_chain() + */ + +void +pbuf_cat(struct pbuf *h, struct pbuf *t) +{ +  struct pbuf *p; + +  LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", +             ((h != NULL) && (t != NULL)), return;); + +  /* proceed to last pbuf of chain */ +  for (p = h; p->next != NULL; p = p->next) { +    /* add total length of second chain to all totals of first chain */ +    p->tot_len += t->tot_len; +  } +  /* { p is last pbuf of first h chain, p->next == NULL } */ +  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); +  LWIP_ASSERT("p->next == NULL", p->next == NULL); +  /* add total length of second chain to last pbuf total of first chain */ +  p->tot_len += t->tot_len; +  /* chain last pbuf of head (p) with first of tail (t) */ +  p->next = t; +  /* p->next now references t, but the caller will drop its reference to t, +   * so netto there is no change to the reference count of t. +   */ +} + +/** + * Chain two pbufs (or pbuf chains) together. + *  + * The caller MUST call pbuf_free(t) once it has stopped + * using it. Use pbuf_cat() instead if you no longer use t. + *  + * @param h head pbuf (chain) + * @param t tail pbuf (chain) + * @note The pbufs MUST belong to the same packet. + * @note MAY NOT be called on a packet queue. + * + * The ->tot_len fields of all pbufs of the head chain are adjusted. + * The ->next field of the last pbuf of the head chain is adjusted. + * The ->ref field of the first pbuf of the tail chain is adjusted. + * + */ +void +pbuf_chain(struct pbuf *h, struct pbuf *t) +{ +  pbuf_cat(h, t); +  /* t is now referenced by h */ +  pbuf_ref(t); +  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); +} + +/** + * Dechains the first pbuf from its succeeding pbufs in the chain. + * + * Makes p->tot_len field equal to p->len. + * @param p pbuf to dechain + * @return remainder of the pbuf chain, or NULL if it was de-allocated. + * @note May not be called on a packet queue. + */ +struct pbuf * +pbuf_dechain(struct pbuf *p) +{ +  struct pbuf *q; +  u8_t tail_gone = 1; +  /* tail */ +  q = p->next; +  /* pbuf has successor in chain? */ +  if (q != NULL) { +    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ +    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); +    /* enforce invariant if assertion is disabled */ +    q->tot_len = p->tot_len - p->len; +    /* decouple pbuf from remainder */ +    p->next = NULL; +    /* total length of pbuf p is its own length only */ +    p->tot_len = p->len; +    /* q is no longer referenced by p, free it */ +    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); +    tail_gone = pbuf_free(q); +    if (tail_gone > 0) { +      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, +                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); +    } +    /* return remaining tail or NULL if deallocated */ +  } +  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ +  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); +  return ((tail_gone > 0) ? NULL : q); +} + +/** + * + * Create PBUF_RAM copies of pbufs. + * + * Used to queue packets on behalf of the lwIP stack, such as + * ARP based queueing. + * + * @note You MUST explicitly use p = pbuf_take(p); + * + * @note Only one packet is copied, no packet queue! + * + * @param p_to pbuf destination of the copy + * @param p_from pbuf source of the copy + * + * @return ERR_OK if pbuf was copied + *         ERR_ARG if one of the pbufs is NULL or p_to is not big + *                 enough to hold p_from + */ +err_t +pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) +{ +  u16_t offset_to=0, offset_from=0, len; + +  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n", +    (void*)p_to, (void*)p_from)); + +  /* is the target big enough to hold the source? */ +  LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && +             (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); + +  /* iterate through pbuf chain */ +  do +  { +    LWIP_ASSERT("p_to != NULL", p_to != NULL); +    /* copy one part of the original chain */ +    if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { +      /* complete current p_from fits into current p_to */ +      len = p_from->len - offset_from; +    } else { +      /* current p_from does not fit into current p_to */ +      len = p_to->len - offset_to; +    } +    MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); +    offset_to += len; +    offset_from += len; +    LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); +    if (offset_to == p_to->len) { +      /* on to next p_to (if any) */ +      offset_to = 0; +      p_to = p_to->next; +    } +    LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); +    if (offset_from >= p_from->len) { +      /* on to next p_from (if any) */ +      offset_from = 0; +      p_from = p_from->next; +    } + +    if((p_from != NULL) && (p_from->len == p_from->tot_len)) { +      /* don't copy more than one packet! */ +      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", +                 (p_from->next == NULL), return ERR_VAL;); +    } +    if((p_to != NULL) && (p_to->len == p_to->tot_len)) { +      /* don't copy more than one packet! */ +      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", +                  (p_to->next == NULL), return ERR_VAL;); +    } +  } while (p_from); +  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n")); +  return ERR_OK; +} + +/** + * Copy (part of) the contents of a packet buffer + * to an application supplied buffer. + * + * @param buf the pbuf from which to copy data + * @param dataptr the application supplied buffer + * @param len length of data to copy (dataptr must be big enough). No more  + * than buf->tot_len will be copied, irrespective of len + * @param offset offset into the packet buffer from where to begin copying len bytes + * @return the number of bytes copied, or 0 on failure + */ +u16_t +pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) +{ +  struct pbuf *p; +  u16_t left; +  u16_t buf_copy_len; +  u16_t copied_total = 0; + +  LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); +  LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); + +  left = 0; + +  if((buf == NULL) || (dataptr == NULL)) { +    return 0; +  } + +  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ +  for(p = buf; len != 0 && p != NULL; p = p->next) { +    if ((offset != 0) && (offset >= p->len)) { +      /* don't copy from this buffer -> on to the next */ +      offset -= p->len; +    } else { +      /* copy from this buffer. maybe only partially. */ +      buf_copy_len = p->len - offset; +      if (buf_copy_len > len) +          buf_copy_len = len; +      /* copy the necessary parts of the buffer */ +      MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); +      copied_total += buf_copy_len; +      left += buf_copy_len; +      len -= buf_copy_len; +      offset = 0; +    } +  } +  return copied_total; +} + +/** + * Copy application supplied data into a pbuf. + * This function can only be used to copy the equivalent of buf->tot_len data. + * + * @param buf pbuf to fill with data + * @param dataptr application supplied data buffer + * @param len length of the application supplied data buffer + * + * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough + */ +err_t +pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) +{ +  struct pbuf *p; +  u16_t buf_copy_len; +  u16_t total_copy_len = len; +  u16_t copied_total = 0; + +  LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); +  LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); + +  if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { +    return ERR_ARG; +  } + +  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ +  for(p = buf; total_copy_len != 0; p = p->next) { +    LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); +    buf_copy_len = total_copy_len; +    if (buf_copy_len > p->len) { +      /* this pbuf cannot hold all remaining data */ +      buf_copy_len = p->len; +    } +    /* copy the necessary parts of the buffer */ +    MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); +    total_copy_len -= buf_copy_len; +    copied_total += buf_copy_len; +  } +  LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); +  return ERR_OK; +} + +/** + * Creates a single pbuf out of a queue of pbufs. + * + * @remark: The source pbuf 'p' is not freed by this function because that can + *          be illegal in some places! + * + * @param p the source pbuf + * @param layer pbuf_layer of the new pbuf + * + * @return a new, single pbuf (p->next is NULL) + *         or the old pbuf if allocation fails + */ +struct pbuf* +pbuf_coalesce(struct pbuf *p, pbuf_layer layer) +{ +  struct pbuf *q; +  err_t err; +  if (p->next == NULL) { +    return p; +  } +  q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); +  if (q == NULL) { +    /* @todo: what do we do now? */ +    return p; +  } +  err = pbuf_copy(q, p); +  LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); +  pbuf_free(p); +  return q; +} diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/raw.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/raw.c new file mode 100644 index 000000000..589950e75 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/raw.c @@ -0,0 +1,353 @@ +/** + * @file + * Implementation of raw protocol PCBs for low-level handling of + * different types of protocols besides (or overriding) those + * already available in lwIP. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/raw.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "arch/perf.h" + +#include <string.h> + +/** The list of RAW PCBs */ +static struct raw_pcb *raw_pcbs; + +/** + * Determine if in incoming IP packet is covered by a RAW PCB + * and if so, pass it to a user-provided receive callback function. + * + * Given an incoming IP datagram (as a chain of pbufs) this function + * finds a corresponding RAW PCB and calls the corresponding receive + * callback function. + * + * @param p pbuf to be demultiplexed to a RAW PCB. + * @param inp network interface on which the datagram was received. + * @return - 1 if the packet has been eaten by a RAW PCB receive + *           callback function. The caller MAY NOT not reference the + *           packet any longer, and MAY NOT call pbuf_free(). + * @return - 0 if packet is not eaten (pbuf is still referenced by the + *           caller). + * + */ +u8_t +raw_input(struct pbuf *p, struct netif *inp) +{ +  struct raw_pcb *pcb, *prev; +  struct ip_hdr *iphdr; +  s16_t proto; +  u8_t eaten = 0; + +  LWIP_UNUSED_ARG(inp); + +  iphdr = p->payload; +  proto = IPH_PROTO(iphdr); + +  prev = NULL; +  pcb = raw_pcbs; +  /* loop through all raw pcbs until the packet is eaten by one */ +  /* this allows multiple pcbs to match against the packet by design */ +  while ((eaten == 0) && (pcb != NULL)) { +    if (pcb->protocol == proto) { +#if IP_SOF_BROADCAST_RECV +      /* broadcast filter? */ +      if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp)) +#endif /* IP_SOF_BROADCAST_RECV */ +      { +        /* receive callback function available? */ +        if (pcb->recv != NULL) { +          /* the receive callback function did not eat the packet? */ +          if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) { +            /* receive function ate the packet */ +            p = NULL; +            eaten = 1; +            if (prev != NULL) { +            /* move the pcb to the front of raw_pcbs so that is +               found faster next time */ +              prev->next = pcb->next; +              pcb->next = raw_pcbs; +              raw_pcbs = pcb; +            } +          } +        } +        /* no receive callback function was set for this raw PCB */ +      } +      /* drop the packet */ +    } +    prev = pcb; +    pcb = pcb->next; +  } +  return eaten; +} + +/** + * Bind a RAW PCB. + * + * @param pcb RAW PCB to be bound with a local address ipaddr. + * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to + * bind to all local interfaces. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_USE. The specified IP address is already bound to by + * another RAW PCB. + * + * @see raw_disconnect() + */ +err_t +raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr) +{ +  ip_addr_set(&pcb->local_ip, ipaddr); +  return ERR_OK; +} + +/** + * Connect an RAW PCB. This function is required by upper layers + * of lwip. Using the raw api you could use raw_sendto() instead + * + * This will associate the RAW PCB with the remote address. + * + * @param pcb RAW PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * + * @return lwIP error code + * + * @see raw_disconnect() and raw_sendto() + */ +err_t +raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr) +{ +  ip_addr_set(&pcb->remote_ip, ipaddr); +  return ERR_OK; +} + + +/** + * Set the callback function for received packets that match the + * raw PCB's protocol and binding.  + *  + * The callback function MUST either + * - eat the packet by calling pbuf_free() and returning non-zero. The + *   packet will not be passed to other raw PCBs or other protocol layers. + * - not free the packet, and return zero. The packet will be matched + *   against further PCBs and/or forwarded to another protocol layers. + *  + * @return non-zero if the packet was free()d, zero if the packet remains + * available for others. + */ +void +raw_recv(struct raw_pcb *pcb, +         u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p, +                      struct ip_addr *addr), +         void *recv_arg) +{ +  /* remember recv() callback and user data */ +  pcb->recv = recv; +  pcb->recv_arg = recv_arg; +} + +/** + * Send the raw IP packet to the given address. Note that actually you cannot + * modify the IP headers (this is inconsistent with the receive callback where + * you actually get the IP headers), you can only specify the IP payload here. + * It requires some more changes in lwIP. (there will be a raw_send() function + * then.) + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * @param ipaddr the destination address of the IP packet + * + */ +err_t +raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) +{ +  err_t err; +  struct netif *netif; +  struct ip_addr *src_ip; +  struct pbuf *q; /* q will be sent down the stack */ +   +  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n")); +   +  /* not enough space to add an IP header to first pbuf in given p chain? */ +  if (pbuf_header(p, IP_HLEN)) { +    /* allocate header in new pbuf */ +    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); +    /* new header pbuf could not be allocated? */ +    if (q == NULL) { +      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n")); +      return ERR_MEM; +    } +    /* chain header q in front of given pbuf p */ +    pbuf_chain(q, p); +    /* { first pbuf q points to header pbuf } */ +    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); +  }  else { +    /* first pbuf q equals given pbuf */ +    q = p; +    if(pbuf_header(q, -IP_HLEN)) { +      LWIP_ASSERT("Can't restore header we just removed!", 0); +      return ERR_MEM; +    } +  } + +  if ((netif = ip_route(ipaddr)) == NULL) { +    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr)); +    /* free any temporary header pbuf allocated by pbuf_header() */ +    if (q != p) { +      pbuf_free(q); +    } +    return ERR_RTE; +  } + +#if IP_SOF_BROADCAST +  /* broadcast filter? */ +  if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) { +    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); +    /* free any temporary header pbuf allocated by pbuf_header() */ +    if (q != p) { +      pbuf_free(q); +    } +    return ERR_VAL; +  } +#endif /* IP_SOF_BROADCAST */ + +  if (ip_addr_isany(&pcb->local_ip)) { +    /* use outgoing network interface IP address as source address */ +    src_ip = &(netif->ip_addr); +  } else { +    /* use RAW PCB local IP address as source address */ +    src_ip = &(pcb->local_ip); +  } + +#if LWIP_NETIF_HWADDRHINT +  netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ +  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); +#if LWIP_NETIF_HWADDRHINT +  netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ + +  /* did we chain a header earlier? */ +  if (q != p) { +    /* free the header */ +    pbuf_free(q); +  } +  return err; +} + +/** + * Send the raw IP packet to the address given by raw_connect() + * + * @param pcb the raw pcb which to send + * @param p the IP payload to send + * + */ +err_t +raw_send(struct raw_pcb *pcb, struct pbuf *p) +{ +  return raw_sendto(pcb, p, &pcb->remote_ip); +} + +/** + * Remove an RAW PCB. + * + * @param pcb RAW PCB to be removed. The PCB is removed from the list of + * RAW PCB's and the data structure is freed from memory. + * + * @see raw_new() + */ +void +raw_remove(struct raw_pcb *pcb) +{ +  struct raw_pcb *pcb2; +  /* pcb to be removed is first in list? */ +  if (raw_pcbs == pcb) { +    /* make list start at 2nd pcb */ +    raw_pcbs = raw_pcbs->next; +    /* pcb not 1st in list */ +  } else { +    for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { +      /* find pcb in raw_pcbs list */ +      if (pcb2->next != NULL && pcb2->next == pcb) { +        /* remove pcb from list */ +        pcb2->next = pcb->next; +      } +    } +  } +  memp_free(MEMP_RAW_PCB, pcb); +} + +/** + * Create a RAW PCB. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) + * + * @see raw_remove() + */ +struct raw_pcb * +raw_new(u8_t proto) { +  struct raw_pcb *pcb; + +  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_new\n")); + +  pcb = memp_malloc(MEMP_RAW_PCB); +  /* could allocate RAW PCB? */ +  if (pcb != NULL) { +    /* initialize PCB to all zeroes */ +    memset(pcb, 0, sizeof(struct raw_pcb)); +    pcb->protocol = proto; +    pcb->ttl = RAW_TTL; +    pcb->next = raw_pcbs; +    raw_pcbs = pcb; +  } +  return pcb; +} + +#endif /* LWIP_RAW */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/asn1_dec.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/asn1_dec.c new file mode 100644 index 000000000..650fb4037 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/asn1_dec.c @@ -0,0 +1,657 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) decoding + * + * @todo not optimised (yet), favor correctness over speed, favor speed over size + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp_asn1.h" + +/** + * Retrieves type field from incoming pbuf chain. + * + * @param p points to a pbuf holding an ASN1 coded type field + * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field + * @param type return ASN1 type + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; +      *type = *msg_ptr; +      return ERR_OK; +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Decodes length field from incoming pbuf chain into host length. + * + * @param p points to a pbuf holding an ASN1 coded length + * @param ofs points to the offset within the pbuf chain of the ASN1 coded length + * @param octets_used returns number of octets used by the length code + * @param length return host order length, upto 64k + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; + +      if (*msg_ptr < 0x80) +      { +        /* primitive definite length format */ +        *octets_used = 1; +        *length = *msg_ptr; +        return ERR_OK; +      } +      else if (*msg_ptr == 0x80) +      { +        /* constructed indefinite length format, termination with two zero octets */ +        u8_t zeros; +        u8_t i; + +        *length = 0; +        zeros = 0; +        while (zeros != 2) +        { +          i = 2; +          while (i > 0) +          { +            i--; +            (*length) += 1; +            ofs += 1; +            if (ofs >= plen) +            { +              /* next octet in next pbuf */ +              p = p->next; +              if (p == NULL) { return ERR_ARG; } +              msg_ptr = p->payload; +              plen += p->len; +            } +            else +            { +              /* next octet in same pbuf */ +              msg_ptr++; +            } +            if (*msg_ptr == 0) +            { +              zeros++; +              if (zeros == 2) +              { +                /* stop while (i > 0) */ +                i = 0; +              } +            } +            else +            { +              zeros = 0; +            } +          } +        } +        *octets_used = 1; +        return ERR_OK; +      } +      else if (*msg_ptr == 0x81) +      { +        /* constructed definite length format, one octet */ +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +        *length = *msg_ptr; +        *octets_used = 2; +        return ERR_OK; +      } +      else if (*msg_ptr == 0x82) +      { +        u8_t i; + +        /* constructed definite length format, two octets */ +        i = 2; +        while (i > 0) +        { +          i--; +          ofs += 1; +          if (ofs >= plen) +          { +            /* next octet in next pbuf */ +            p = p->next; +            if (p == NULL) { return ERR_ARG; } +            msg_ptr = p->payload; +            plen += p->len; +          } +          else +          { +            /* next octet in same pbuf */ +            msg_ptr++; +          } +          if (i == 0) +          { +            /* least significant length octet */ +            *length |= *msg_ptr; +          } +          else +          { +            /* most significant length octet */ +            *length = (*msg_ptr) << 8; +          } +        } +        *octets_used = 3; +        return ERR_OK; +      } +      else +      { +        /* constructed definite length format 3..127 octets, this is too big (>64k) */ +        /**  @todo: do we need to accept inefficient codings with many leading zero's? */ +        *octets_used = 1 + ((*msg_ptr) & 0x7f); +        return ERR_ARG; +      } +    } +    p = p->next; +  } + +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Decodes positive integer (counter, gauge, timeticks) into u32_t. + * + * @param p points to a pbuf holding an ASN1 coded integer + * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer + * @param len length of the coded integer field + * @param value return host order integer + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + * + * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded + * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value + * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! + */ +err_t +snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; +      if ((len > 0) && (len < 6)) +      { +        /* start from zero */ +        *value = 0; +        if (*msg_ptr & 0x80) +        { +          /* negative, expecting zero sign bit! */ +          return ERR_ARG; +        } +        else +        { +          /* positive */ +          if ((len > 1) && (*msg_ptr == 0)) +          { +            /* skip leading "sign byte" octet 0x00 */ +            len--; +            ofs += 1; +            if (ofs >= plen) +            { +              /* next octet in next pbuf */ +              p = p->next; +              if (p == NULL) { return ERR_ARG; } +              msg_ptr = p->payload; +              plen += p->len; +            } +            else +            { +              /* next octet in same pbuf */ +              msg_ptr++; +            } +          } +        } +        /* OR octets with value */ +        while (len > 1) +        { +          len--; +          *value |= *msg_ptr; +          *value <<= 8; +          ofs += 1; +          if (ofs >= plen) +          { +            /* next octet in next pbuf */ +            p = p->next; +            if (p == NULL) { return ERR_ARG; } +            msg_ptr = p->payload; +            plen += p->len; +          } +          else +          { +            /* next octet in same pbuf */ +            msg_ptr++; +          } +        } +        *value |= *msg_ptr; +        return ERR_OK; +      } +      else +      { +        return ERR_ARG; +      } +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Decodes integer into s32_t. + * + * @param p points to a pbuf holding an ASN1 coded integer + * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer + * @param len length of the coded integer field + * @param value return host order integer + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + * + * @note ASN coded integers are _always_ signed! + */ +err_t +snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value) +{ +  u16_t plen, base; +  u8_t *msg_ptr; +#if BYTE_ORDER == LITTLE_ENDIAN +  u8_t *lsb_ptr = (u8_t*)value; +#endif +#if BYTE_ORDER == BIG_ENDIAN +  u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1; +#endif +  u8_t sign; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; +      if ((len > 0) && (len < 5)) +      { +        if (*msg_ptr & 0x80) +        { +          /* negative, start from -1 */ +          *value = -1; +          sign = 1; +        } +        else +        { +          /* positive, start from 0 */ +          *value = 0; +          sign = 0; +        } +        /* OR/AND octets with value */ +        while (len > 1) +        { +          len--; +          if (sign) +          { +            *lsb_ptr &= *msg_ptr; +            *value <<= 8; +            *lsb_ptr |= 255; +          } +          else +          { +            *lsb_ptr |= *msg_ptr; +            *value <<= 8; +          } +          ofs += 1; +          if (ofs >= plen) +          { +            /* next octet in next pbuf */ +            p = p->next; +            if (p == NULL) { return ERR_ARG; } +            msg_ptr = p->payload; +            plen += p->len; +          } +          else +          { +            /* next octet in same pbuf */ +            msg_ptr++; +          } +        } +        if (sign) +        { +          *lsb_ptr &= *msg_ptr; +        } +        else +        { +          *lsb_ptr |= *msg_ptr; +        } +        return ERR_OK; +      } +      else +      { +        return ERR_ARG; +      } +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Decodes object identifier from incoming message into array of s32_t. + * + * @param p points to a pbuf holding an ASN1 coded object identifier + * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier + * @param len length of the coded object identifier + * @param oid return object identifier struct + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) +{ +  u16_t plen, base; +  u8_t *msg_ptr; +  s32_t *oid_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; + +      oid->len = 0; +      oid_ptr = &oid->id[0]; +      if (len > 0) +      { +        /* first compressed octet */ +        if (*msg_ptr == 0x2B) +        { +          /* (most) common case 1.3 (iso.org) */ +          *oid_ptr = 1; +          oid_ptr++; +          *oid_ptr = 3; +          oid_ptr++; +        } +        else if (*msg_ptr < 40) +        { +          *oid_ptr = 0; +          oid_ptr++; +          *oid_ptr = *msg_ptr; +          oid_ptr++; +        } +        else if (*msg_ptr < 80) +        { +          *oid_ptr = 1; +          oid_ptr++; +          *oid_ptr = (*msg_ptr) - 40; +          oid_ptr++; +        } +        else +        { +          *oid_ptr = 2; +          oid_ptr++; +          *oid_ptr = (*msg_ptr) - 80; +          oid_ptr++; +        } +        oid->len = 2; +      } +      else +      { +        /* accepting zero length identifiers e.g. for +           getnext operation. uncommon but valid */ +        return ERR_OK; +      } +      len--; +      if (len > 0) +      { +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN)) +      { +        /* sub-identifier uses multiple octets */ +        if (*msg_ptr & 0x80) +        { +          s32_t sub_id = 0; + +          while ((*msg_ptr & 0x80) && (len > 1)) +          { +            len--; +            sub_id = (sub_id << 7) + (*msg_ptr & ~0x80); +            ofs += 1; +            if (ofs >= plen) +            { +              /* next octet in next pbuf */ +              p = p->next; +              if (p == NULL) { return ERR_ARG; } +              msg_ptr = p->payload; +              plen += p->len; +            } +            else +            { +              /* next octet in same pbuf */ +              msg_ptr++; +            } +          } +          if (!(*msg_ptr & 0x80) && (len > 0)) +          { +            /* last octet sub-identifier */ +            len--; +            sub_id = (sub_id << 7) + *msg_ptr; +            *oid_ptr = sub_id; +          } +        } +        else +        { +          /* !(*msg_ptr & 0x80) sub-identifier uses single octet */ +          len--; +          *oid_ptr = *msg_ptr; +        } +        if (len > 0) +        { +          /* remaining oid bytes available ... */ +          ofs += 1; +          if (ofs >= plen) +          { +            /* next octet in next pbuf */ +            p = p->next; +            if (p == NULL) { return ERR_ARG; } +            msg_ptr = p->payload; +            plen += p->len; +          } +          else +          { +            /* next octet in same pbuf */ +            msg_ptr++; +          } +        } +        oid_ptr++; +        oid->len++; +      } +      if (len == 0) +      { +        /* len == 0, end of oid */ +        return ERR_OK; +      } +      else +      { +        /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */ +        return ERR_ARG; +      } + +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) + * from incoming message into array. + * + * @param p points to a pbuf holding an ASN1 coded raw data + * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data + * @param len length of the coded raw data (zero is valid, e.g. empty string!) + * @param raw_len length of the raw return value + * @param raw return raw bytes + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode + */ +err_t +snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  if (len > 0) +  { +    plen = 0; +    while (p != NULL) +    { +      base = plen; +      plen += p->len; +      if (ofs < plen) +      { +        msg_ptr = p->payload; +        msg_ptr += ofs - base; +        if (raw_len >= len) +        { +          while (len > 1) +          { +            /* copy len - 1 octets */ +            len--; +            *raw = *msg_ptr; +            raw++; +            ofs += 1; +            if (ofs >= plen) +            { +              /* next octet in next pbuf */ +              p = p->next; +              if (p == NULL) { return ERR_ARG; } +              msg_ptr = p->payload; +              plen += p->len; +            } +            else +            { +              /* next octet in same pbuf */ +              msg_ptr++; +            } +          } +          /* copy last octet */ +          *raw = *msg_ptr; +          return ERR_OK; +        } +        else +        { +          /* raw_len < len, not enough dst space */ +          return ERR_ARG; +        } +      } +      p = p->next; +    } +    /* p == NULL, ofs >= plen */ +    return ERR_ARG; +  } +  else +  { +    /* len == 0, empty string */ +    return ERR_OK; +  } +} + +#endif /* LWIP_SNMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/asn1_enc.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/asn1_enc.c new file mode 100644 index 000000000..77af6b4ba --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/asn1_enc.c @@ -0,0 +1,611 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) encoding + * + * @todo not optimised (yet), favor correctness over speed, favor speed over size + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp_asn1.h" + +/** + * Returns octet count for length. + * + * @param length + * @param octets_needed points to the return value + */ +void +snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) +{ +  if (length < 0x80U) +  { +    *octets_needed = 1; +  } +  else if (length < 0x100U) +  { +    *octets_needed = 2; +  } +  else +  { +    *octets_needed = 3; +  } +} + +/** + * Returns octet count for an u32_t. + * + * @param value + * @param octets_needed points to the return value + * + * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded + * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value + * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! + */ +void +snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) +{ +  if (value < 0x80UL) +  { +    *octets_needed = 1; +  } +  else if (value < 0x8000UL) +  { +    *octets_needed = 2; +  } +  else if (value < 0x800000UL) +  { +    *octets_needed = 3; +  } +  else if (value < 0x80000000UL) +  { +    *octets_needed = 4; +  } +  else +  { +    *octets_needed = 5; +  } +} + +/** + * Returns octet count for an s32_t. + * + * @param value + * @param octets_needed points to the return value + * + * @note ASN coded integers are _always_ signed. + */ +void +snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) +{ +  if (value < 0) +  { +    value = ~value; +  } +  if (value < 0x80L) +  { +    *octets_needed = 1; +  } +  else if (value < 0x8000L) +  { +    *octets_needed = 2; +  } +  else if (value < 0x800000L) +  { +    *octets_needed = 3; +  } +  else +  { +    *octets_needed = 4; +  } +} + +/** + * Returns octet count for an object identifier. + * + * @param ident_len object identifier array length + * @param ident points to object identifier array + * @param octets_needed points to the return value + */ +void +snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed) +{ +  s32_t sub_id; +  u8_t cnt; + +  cnt = 0; +  if (ident_len > 1) +  { +    /* compressed prefix in one octet */ +    cnt++; +    ident_len -= 2; +    ident += 2; +  } +  while(ident_len > 0) +  { +    ident_len--; +    sub_id = *ident; + +    sub_id >>= 7; +    cnt++; +    while(sub_id > 0) +    { +      sub_id >>= 7; +      cnt++; +    } +    ident++; +  } +  *octets_needed = cnt; +} + +/** + * Encodes ASN type field into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode value into + * @param ofs points to the offset within the pbuf chain + * @param type input ASN1 type + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; +      *msg_ptr = type; +      return ERR_OK; +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Encodes host order length field into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode length into + * @param ofs points to the offset within the pbuf chain + * @param length is the host order length to be encoded + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; + +      if (length < 0x80) +      { +        *msg_ptr = length; +        return ERR_OK; +      } +      else if (length < 0x100) +      { +        *msg_ptr = 0x81; +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +        *msg_ptr = length; +        return ERR_OK; +      } +      else +      { +        u8_t i; + +        /* length >= 0x100 && length <= 0xFFFF */ +        *msg_ptr = 0x82; +        i = 2; +        while (i > 0) +        { +          i--; +          ofs += 1; +          if (ofs >= plen) +          { +            /* next octet in next pbuf */ +            p = p->next; +            if (p == NULL) { return ERR_ARG; } +            msg_ptr = p->payload; +            plen += p->len; +          } +          else +          { +            /* next octet in same pbuf */ +            msg_ptr++; +          } +          if (i == 0) +          { +            /* least significant length octet */ +            *msg_ptr = length; +          } +          else +          { +            /* most significant length octet */ +            *msg_ptr = length >> 8; +          } +        } +        return ERR_OK; +      } +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode value into + * @param ofs points to the offset within the pbuf chain + * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) + * @param value is the host order u32_t value to be encoded + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + * + * @see snmp_asn1_enc_u32t_cnt() + */ +err_t +snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; + +      if (octets_needed == 5) +      { +        /* not enough bits in 'value' add leading 0x00 */ +        octets_needed--; +        *msg_ptr = 0x00; +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      while (octets_needed > 1) +      { +        octets_needed--; +        *msg_ptr = value >> (octets_needed << 3); +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      /* (only) one least significant octet */ +      *msg_ptr = value; +      return ERR_OK; +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Encodes s32_t integer into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode value into + * @param ofs points to the offset within the pbuf chain + * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt()) + * @param value is the host order s32_t value to be encoded + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + * + * @see snmp_asn1_enc_s32t_cnt() + */ +err_t +snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; + +      while (octets_needed > 1) +      { +        octets_needed--; +        *msg_ptr = value >> (octets_needed << 3); +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      /* (only) one least significant octet */ +      *msg_ptr = value; +      return ERR_OK; +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Encodes object identifier into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode oid into + * @param ofs points to the offset within the pbuf chain + * @param ident_len object identifier array length + * @param ident points to object identifier array + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; + +      if (ident_len > 1) +      { +        if ((ident[0] == 1) && (ident[1] == 3)) +        { +          /* compressed (most common) prefix .iso.org */ +          *msg_ptr = 0x2b; +        } +        else +        { +          /* calculate prefix */ +          *msg_ptr = (ident[0] * 40) + ident[1]; +        } +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +        ident_len -= 2; +        ident += 2; +      } +      else +      { +/* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */ +        /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */ +        return ERR_ARG; +      } +      while (ident_len > 0) +      { +        s32_t sub_id; +        u8_t shift, tail; + +        ident_len--; +        sub_id = *ident; +        tail = 0; +        shift = 28; +        while(shift > 0) +        { +          u8_t code; + +          code = sub_id >> shift; +          if ((code != 0) || (tail != 0)) +          { +            tail = 1; +            *msg_ptr = code | 0x80; +            ofs += 1; +            if (ofs >= plen) +            { +              /* next octet in next pbuf */ +              p = p->next; +              if (p == NULL) { return ERR_ARG; } +              msg_ptr = p->payload; +              plen += p->len; +            } +            else +            { +              /* next octet in same pbuf */ +              msg_ptr++; +            } +          } +          shift -= 7; +        } +        *msg_ptr = (u8_t)sub_id & 0x7F; +        if (ident_len > 0) +        { +          ofs += 1; +          if (ofs >= plen) +          { +            /* next octet in next pbuf */ +            p = p->next; +            if (p == NULL) { return ERR_ARG; } +            msg_ptr = p->payload; +            plen += p->len; +          } +          else +          { +            /* next octet in same pbuf */ +            msg_ptr++; +          } +        } +        /* proceed to next sub-identifier */ +        ident++; +      } +      return ERR_OK; +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +/** + * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. + * + * @param p points to output pbuf to encode raw data into + * @param ofs points to the offset within the pbuf chain + * @param raw_len raw data length + * @param raw points raw data + * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode + */ +err_t +snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw) +{ +  u16_t plen, base; +  u8_t *msg_ptr; + +  plen = 0; +  while (p != NULL) +  { +    base = plen; +    plen += p->len; +    if (ofs < plen) +    { +      msg_ptr = p->payload; +      msg_ptr += ofs - base; + +      while (raw_len > 1) +      { +        /* copy raw_len - 1 octets */ +        raw_len--; +        *msg_ptr = *raw; +        raw++; +        ofs += 1; +        if (ofs >= plen) +        { +          /* next octet in next pbuf */ +          p = p->next; +          if (p == NULL) { return ERR_ARG; } +          msg_ptr = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      if (raw_len > 0) +      { +        /* copy last or single octet */ +        *msg_ptr = *raw; +      } +      return ERR_OK; +    } +    p = p->next; +  } +  /* p == NULL, ofs >= plen */ +  return ERR_ARG; +} + +#endif /* LWIP_SNMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/mib2.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/mib2.c new file mode 100644 index 000000000..33eeee66c --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/mib2.c @@ -0,0 +1,4126 @@ +/** + * @file + * Management Information Base II (RFC1213) objects and functions. + * + * @note the object identifiers for this MIB-2 and private MIB tree + * must be kept in sorted ascending order. This to ensure correct getnext operation. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/ip_frag.h" +#include "lwip/tcp.h" +#include "lwip/udp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_structs.h" +#include "netif/etharp.h" + +/** + * IANA assigned enterprise ID for lwIP is 26381 + * @see http://www.iana.org/assignments/enterprise-numbers + * + * @note this enterprise ID is assigned to the lwIP project, + * all object identifiers living under this ID are assigned + * by the lwIP maintainers (contact Christiaan Simons)! + * @note don't change this define, use snmp_set_sysobjid() + * + * If you need to create your own private MIB you'll need + * to apply for your own enterprise ID with IANA: + * http://www.iana.org/numbers.html + */ +#define SNMP_ENTERPRISE_ID 26381 +#define SNMP_SYSOBJID_LEN 7 +#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID} + +#ifndef SNMP_SYSSERVICES +#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) +#endif + +#ifndef SNMP_GET_SYSUPTIME +#define SNMP_GET_SYSUPTIME(sysuptime) +#endif + +static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void system_get_value(struct obj_def *od, u16_t len, void *value); +static u8_t system_set_test(struct obj_def *od, u16_t len, void *value); +static void system_set_value(struct obj_def *od, u16_t len, void *value); +static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void interfaces_get_value(struct obj_def *od, u16_t len, void *value); +static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ifentry_get_value(struct obj_def *od, u16_t len, void *value); +#if !SNMP_SAFE_REQUESTS +static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value); +static void ifentry_set_value (struct obj_def *od, u16_t len, void *value); +#endif /* SNMP_SAFE_REQUESTS */ +static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void atentry_get_value(struct obj_def *od, u16_t len, void *value); +static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_get_value(struct obj_def *od, u16_t len, void *value); +static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value); +static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value); +static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value); +static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value); +static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void icmp_get_value(struct obj_def *od, u16_t len, void *value); +#if LWIP_TCP +static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void tcp_get_value(struct obj_def *od, u16_t len, void *value); +#ifdef THIS_SEEMS_UNUSED +static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value); +#endif +#endif +static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void udp_get_value(struct obj_def *od, u16_t len, void *value); +static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void udpentry_get_value(struct obj_def *od, u16_t len, void *value); +static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +static void snmp_get_value(struct obj_def *od, u16_t len, void *value); +static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value); +static void snmp_set_value(struct obj_def *od, u16_t len, void *value); + + +/* snmp .1.3.6.1.2.1.11 */ +const mib_scalar_node snmp_scalar = { +  &snmp_get_object_def, +  &snmp_get_value, +  &snmp_set_test, +  &snmp_set_value, +  MIB_NODE_SC, +  0 +}; +const s32_t snmp_ids[28] = { +  1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, +  17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30 +}; +struct mib_node* const snmp_nodes[28] = { +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar +}; +const struct mib_array_node snmp = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  28, +  snmp_ids, +  snmp_nodes +}; + +/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */ +/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */ +/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */ + +/* udp .1.3.6.1.2.1.7 */ +/** index root node for udpTable */ +struct mib_list_rootnode udp_root = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_LR, +  0, +  NULL, +  NULL, +  0 +}; +const s32_t udpentry_ids[2] = { 1, 2 }; +struct mib_node* const udpentry_nodes[2] = { +  (struct mib_node* const)&udp_root, (struct mib_node* const)&udp_root, +}; +const struct mib_array_node udpentry = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  2, +  udpentry_ids, +  udpentry_nodes +}; + +s32_t udptable_id = 1; +struct mib_node* udptable_node = (struct mib_node* const)&udpentry; +struct mib_ram_array_node udptable = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_RA, +  0, +  &udptable_id, +  &udptable_node +}; + +const mib_scalar_node udp_scalar = { +  &udp_get_object_def, +  &udp_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_SC, +  0 +}; +const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 }; +struct mib_node* const udp_nodes[5] = { +  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar, +  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar, +  (struct mib_node* const)&udptable +}; +const struct mib_array_node udp = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  5, +  udp_ids, +  udp_nodes +}; + +/* tcp .1.3.6.1.2.1.6 */ +#if LWIP_TCP +/* only if the TCP protocol is available may implement this group */ +/** index root node for tcpConnTable */ +struct mib_list_rootnode tcpconntree_root = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_LR, +  0, +  NULL, +  NULL, +  0 +}; +const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 }; +struct mib_node* const tcpconnentry_nodes[5] = { +  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root, +  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root, +  (struct mib_node* const)&tcpconntree_root +}; +const struct mib_array_node tcpconnentry = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  5, +  tcpconnentry_ids, +  tcpconnentry_nodes +}; + +s32_t tcpconntable_id = 1; +struct mib_node* tcpconntable_node = (struct mib_node* const)&tcpconnentry; +struct mib_ram_array_node tcpconntable = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_RA, +/** @todo update maxlength when inserting / deleting from table +   0 when table is empty, 1 when more than one entry */ +  0, +  &tcpconntable_id, +  &tcpconntable_node +}; + +const mib_scalar_node tcp_scalar = { +  &tcp_get_object_def, +  &tcp_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_SC, +  0 +}; +const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +struct mib_node* const tcp_nodes[15] = { +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar +}; +const struct mib_array_node tcp = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  15, +  tcp_ids, +  tcp_nodes +}; +#endif + +/* icmp .1.3.6.1.2.1.5 */ +const mib_scalar_node icmp_scalar = { +  &icmp_get_object_def, +  &icmp_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_SC, +  0 +}; +const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; +struct mib_node* const icmp_nodes[26] = { +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar +}; +const struct mib_array_node icmp = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  26, +  icmp_ids, +  icmp_nodes +}; + +/** index root node for ipNetToMediaTable */ +struct mib_list_rootnode ipntomtree_root = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_LR, +  0, +  NULL, +  NULL, +  0 +}; +const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 }; +struct mib_node* const ipntomentry_nodes[4] = { +  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root, +  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root +}; +const struct mib_array_node ipntomentry = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  4, +  ipntomentry_ids, +  ipntomentry_nodes +}; + +s32_t ipntomtable_id = 1; +struct mib_node* ipntomtable_node = (struct mib_node* const)&ipntomentry; +struct mib_ram_array_node ipntomtable = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_RA, +  0, +  &ipntomtable_id, +  &ipntomtable_node +}; + +/** index root node for ipRouteTable */ +struct mib_list_rootnode iprtetree_root = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_LR, +  0, +  NULL, +  NULL, +  0 +}; +const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; +struct mib_node* const iprteentry_nodes[13] = { +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root +}; +const struct mib_array_node iprteentry = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  13, +  iprteentry_ids, +  iprteentry_nodes +}; + +s32_t iprtetable_id = 1; +struct mib_node* iprtetable_node = (struct mib_node* const)&iprteentry; +struct mib_ram_array_node iprtetable = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_RA, +  0, +  &iprtetable_id, +  &iprtetable_node +}; + +/** index root node for ipAddrTable */ +struct mib_list_rootnode ipaddrtree_root = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_LR, +  0, +  NULL, +  NULL, +  0 +}; +const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 }; +struct mib_node* const ipaddrentry_nodes[5] = { +  (struct mib_node* const)&ipaddrtree_root, +  (struct mib_node* const)&ipaddrtree_root, +  (struct mib_node* const)&ipaddrtree_root, +  (struct mib_node* const)&ipaddrtree_root, +  (struct mib_node* const)&ipaddrtree_root +}; +const struct mib_array_node ipaddrentry = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  5, +  ipaddrentry_ids, +  ipaddrentry_nodes +}; + +s32_t ipaddrtable_id = 1; +struct mib_node* ipaddrtable_node = (struct mib_node* const)&ipaddrentry; +struct mib_ram_array_node ipaddrtable = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_RA, +  0, +  &ipaddrtable_id, +  &ipaddrtable_node +}; + +/* ip .1.3.6.1.2.1.4 */ +const mib_scalar_node ip_scalar = { +  &ip_get_object_def, +  &ip_get_value, +  &ip_set_test, +  &noleafs_set_value, +  MIB_NODE_SC, +  0 +}; +const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; +struct mib_node* const ip_nodes[23] = { +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable, +  (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable, +  (struct mib_node* const)&ip_scalar +}; +const struct mib_array_node mib2_ip = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  23, +  ip_ids, +  ip_nodes +}; + +/** index root node for atTable */ +struct mib_list_rootnode arptree_root = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_LR, +  0, +  NULL, +  NULL, +  0 +}; +const s32_t atentry_ids[3] = { 1, 2, 3 }; +struct mib_node* const atentry_nodes[3] = { +  (struct mib_node* const)&arptree_root, +  (struct mib_node* const)&arptree_root, +  (struct mib_node* const)&arptree_root +}; +const struct mib_array_node atentry = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  3, +  atentry_ids, +  atentry_nodes +}; + +const s32_t attable_id = 1; +struct mib_node* const attable_node = (struct mib_node* const)&atentry; +const struct mib_array_node attable = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  1, +  &attable_id, +  &attable_node +}; + +/* at .1.3.6.1.2.1.3 */ +s32_t at_id = 1; +struct mib_node* mib2_at_node = (struct mib_node* const)&attable; +struct mib_ram_array_node at = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_RA, +  0, +  &at_id, +  &mib2_at_node +}; + +/** index root node for ifTable */ +struct mib_list_rootnode iflist_root = { +  &ifentry_get_object_def, +  &ifentry_get_value, +#if SNMP_SAFE_REQUESTS +  &noleafs_set_test, +  &noleafs_set_value, +#else /* SNMP_SAFE_REQUESTS */ +  &ifentry_set_test, +  &ifentry_set_value, +#endif /* SNMP_SAFE_REQUESTS */ +  MIB_NODE_LR, +  0, +  NULL, +  NULL, +  0 +}; +const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; +struct mib_node* const ifentry_nodes[22] = { +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root +}; +const struct mib_array_node ifentry = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  22, +  ifentry_ids, +  ifentry_nodes +}; + +s32_t iftable_id = 1; +struct mib_node* iftable_node = (struct mib_node* const)&ifentry; +struct mib_ram_array_node iftable = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_RA, +  0, +  &iftable_id, +  &iftable_node +}; + +/* interfaces .1.3.6.1.2.1.2 */ +const mib_scalar_node interfaces_scalar = { +  &interfaces_get_object_def, +  &interfaces_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_SC, +  0 +}; +const s32_t interfaces_ids[2] = { 1, 2 }; +struct mib_node* const interfaces_nodes[2] = { +  (struct mib_node* const)&interfaces_scalar, (struct mib_node* const)&iftable +}; +const struct mib_array_node interfaces = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  2, +  interfaces_ids, +  interfaces_nodes +}; + + +/*             0 1 2 3 4 5 6 */ +/* system .1.3.6.1.2.1.1 */ +const mib_scalar_node sys_tem_scalar = { +  &system_get_object_def, +  &system_get_value, +  &system_set_test, +  &system_set_value, +  MIB_NODE_SC, +  0 +}; +const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 }; +struct mib_node* const sys_tem_nodes[7] = { +  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, +  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, +  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, +  (struct mib_node* const)&sys_tem_scalar +}; +/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */ +const struct mib_array_node sys_tem = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  7, +  sys_tem_ids, +  sys_tem_nodes +}; + +/* mib-2 .1.3.6.1.2.1 */ +#if LWIP_TCP +#define MIB2_GROUPS 8 +#else +#define MIB2_GROUPS 7 +#endif +const s32_t mib2_ids[MIB2_GROUPS] = +{ +  1, +  2, +  3, +  4, +  5, +#if LWIP_TCP +  6, +#endif +  7, +  11 +}; +struct mib_node* const mib2_nodes[MIB2_GROUPS] = { +  (struct mib_node* const)&sys_tem, +  (struct mib_node* const)&interfaces, +  (struct mib_node* const)&at, +  (struct mib_node* const)&mib2_ip, +  (struct mib_node* const)&icmp, +#if LWIP_TCP +  (struct mib_node* const)&tcp, +#endif +  (struct mib_node* const)&udp, +  (struct mib_node* const)&snmp +}; + +const struct mib_array_node mib2 = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  MIB2_GROUPS, +  mib2_ids, +  mib2_nodes +}; + +/* mgmt .1.3.6.1.2 */ +const s32_t mgmt_ids[1] = { 1 }; +struct mib_node* const mgmt_nodes[1] = { (struct mib_node* const)&mib2 }; +const struct mib_array_node mgmt = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  1, +  mgmt_ids, +  mgmt_nodes +}; + +/* internet .1.3.6.1 */ +#if SNMP_PRIVATE_MIB +s32_t internet_ids[2] = { 2, 4 }; +struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&private }; +const struct mib_array_node internet = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  2, +  internet_ids, +  internet_nodes +}; +#else +const s32_t internet_ids[1] = { 2 }; +struct mib_node* const internet_nodes[1] = { (struct mib_node* const)&mgmt }; +const struct mib_array_node internet = { +  &noleafs_get_object_def, +  &noleafs_get_value, +  &noleafs_set_test, +  &noleafs_set_value, +  MIB_NODE_AR, +  1, +  internet_ids, +  internet_nodes +}; +#endif + +/** mib-2.system.sysObjectID  */ +static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID}; +/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */ +static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}}; +/** mib-2.system.sysServices */ +static const s32_t sysservices = SNMP_SYSSERVICES; + +/** mib-2.system.sysDescr */ +static const u8_t sysdescr_len_default = 4; +static const u8_t sysdescr_default[] = "lwIP"; +static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default; +static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0]; +/** mib-2.system.sysContact */ +static const u8_t syscontact_len_default = 0; +static const u8_t syscontact_default[] = ""; +static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default; +static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0]; +/** mib-2.system.sysName */ +static const u8_t sysname_len_default = 8; +static const u8_t sysname_default[] = "FQDN-unk"; +static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default; +static u8_t* sysname_ptr = (u8_t*)&sysname_default[0]; +/** mib-2.system.sysLocation */ +static const u8_t syslocation_len_default = 0; +static const u8_t syslocation_default[] = ""; +static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default; +static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0]; +/** mib-2.snmp.snmpEnableAuthenTraps */ +static const u8_t snmpenableauthentraps_default = 2; /* disabled */ +static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default; + +/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */ +static const struct snmp_obj_id ifspecific = {2, {0, 0}}; +/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */ +static const struct snmp_obj_id iprouteinfo = {2, {0, 0}}; + + + +/* mib-2.system counter(s) */ +static u32_t sysuptime = 0; + +/* mib-2.ip counter(s) */ +static u32_t ipinreceives = 0, +             ipinhdrerrors = 0, +             ipinaddrerrors = 0, +             ipforwdatagrams = 0, +             ipinunknownprotos = 0, +             ipindiscards = 0, +             ipindelivers = 0, +             ipoutrequests = 0, +             ipoutdiscards = 0, +             ipoutnoroutes = 0, +             ipreasmreqds = 0, +             ipreasmoks = 0, +             ipreasmfails = 0, +             ipfragoks = 0, +             ipfragfails = 0, +             ipfragcreates = 0, +             iproutingdiscards = 0; +/* mib-2.icmp counter(s) */ +static u32_t icmpinmsgs = 0, +             icmpinerrors = 0, +             icmpindestunreachs = 0, +             icmpintimeexcds = 0, +             icmpinparmprobs = 0, +             icmpinsrcquenchs = 0, +             icmpinredirects = 0, +             icmpinechos = 0, +             icmpinechoreps = 0, +             icmpintimestamps = 0, +             icmpintimestampreps = 0, +             icmpinaddrmasks = 0, +             icmpinaddrmaskreps = 0, +             icmpoutmsgs = 0, +             icmpouterrors = 0, +             icmpoutdestunreachs = 0, +             icmpouttimeexcds = 0, +             icmpoutparmprobs = 0, +             icmpoutsrcquenchs = 0, +             icmpoutredirects = 0, +             icmpoutechos = 0, +             icmpoutechoreps = 0, +             icmpouttimestamps = 0, +             icmpouttimestampreps = 0, +             icmpoutaddrmasks = 0, +             icmpoutaddrmaskreps = 0; +/* mib-2.tcp counter(s) */ +static u32_t tcpactiveopens = 0, +             tcppassiveopens = 0, +             tcpattemptfails = 0, +             tcpestabresets = 0, +             tcpinsegs = 0, +             tcpoutsegs = 0, +             tcpretranssegs = 0, +             tcpinerrs = 0, +             tcpoutrsts = 0; +/* mib-2.udp counter(s) */ +static u32_t udpindatagrams = 0, +             udpnoports = 0, +             udpinerrors = 0, +             udpoutdatagrams = 0; +/* mib-2.snmp counter(s) */ +static u32_t snmpinpkts = 0, +             snmpoutpkts = 0, +             snmpinbadversions = 0, +             snmpinbadcommunitynames = 0, +             snmpinbadcommunityuses = 0, +             snmpinasnparseerrs = 0, +             snmpintoobigs = 0, +             snmpinnosuchnames = 0, +             snmpinbadvalues = 0, +             snmpinreadonlys = 0, +             snmpingenerrs = 0, +             snmpintotalreqvars = 0, +             snmpintotalsetvars = 0, +             snmpingetrequests = 0, +             snmpingetnexts = 0, +             snmpinsetrequests = 0, +             snmpingetresponses = 0, +             snmpintraps = 0, +             snmpouttoobigs = 0, +             snmpoutnosuchnames = 0, +             snmpoutbadvalues = 0, +             snmpoutgenerrs = 0, +             snmpoutgetrequests = 0, +             snmpoutgetnexts = 0, +             snmpoutsetrequests = 0, +             snmpoutgetresponses = 0, +             snmpouttraps = 0; + + + +/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */ +/** + * Copy octet string. + * + * @param dst points to destination + * @param src points to source + * @param n number of octets to copy. + */ +void ocstrncpy(u8_t *dst, u8_t *src, u8_t n) +{ +  while (n > 0) +  { +    n--; +    *dst++ = *src++; +  } +} + +/** + * Copy object identifier (s32_t) array. + * + * @param dst points to destination + * @param src points to source + * @param n number of sub identifiers to copy. + */ +void objectidncpy(s32_t *dst, s32_t *src, u8_t n) +{ +  while(n > 0) +  { +    n--; +    *dst++ = *src++; +  } +} + +/** + * Initializes sysDescr pointers. + * + * @param str if non-NULL then copy str pointer + * @param len points to string length, excluding zero terminator + */ +void snmp_set_sysdesr(u8_t *str, u8_t *len) +{ +  if (str != NULL) +  { +    sysdescr_ptr = str; +    sysdescr_len_ptr = len; +  } +} + +void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid) +{ +  *oid = &sysobjid; +} + +/** + * Initializes sysObjectID value. + * + * @param oid points to stuct snmp_obj_id to copy + */ +void snmp_set_sysobjid(struct snmp_obj_id *oid) +{ +  sysobjid = *oid; +} + +/** + * Must be called at regular 10 msec interval from a timer interrupt + * or signal handler depending on your runtime environment. + */ +void snmp_inc_sysuptime(void) +{ +  sysuptime++; +} + +void snmp_add_sysuptime(u32_t value) +{ +  sysuptime+=value; +} + +void snmp_get_sysuptime(u32_t *value) +{ +  SNMP_GET_SYSUPTIME(sysuptime); +  *value = sysuptime; +} + +/** + * Initializes sysContact pointers, + * e.g. ptrs to non-volatile memory external to lwIP. + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator + */ +void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen) +{ +  if (ocstr != NULL) +  { +    syscontact_ptr = ocstr; +    syscontact_len_ptr = ocstrlen; +  } +} + +/** + * Initializes sysName pointers, + * e.g. ptrs to non-volatile memory external to lwIP. + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator + */ +void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen) +{ +  if (ocstr != NULL) +  { +    sysname_ptr = ocstr; +    sysname_len_ptr = ocstrlen; +  } +} + +/** + * Initializes sysLocation pointers, + * e.g. ptrs to non-volatile memory external to lwIP. + * + * @param ocstr if non-NULL then copy str pointer + * @param ocstrlen points to string length, excluding zero terminator + */ +void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen) +{ +  if (ocstr != NULL) +  { +    syslocation_ptr = ocstr; +    syslocation_len_ptr = ocstrlen; +  } +} + + +void snmp_add_ifinoctets(struct netif *ni, u32_t value) +{ +  ni->ifinoctets += value; +} + +void snmp_inc_ifinucastpkts(struct netif *ni) +{ +  (ni->ifinucastpkts)++; +} + +void snmp_inc_ifinnucastpkts(struct netif *ni) +{ +  (ni->ifinnucastpkts)++; +} + +void snmp_inc_ifindiscards(struct netif *ni) +{ +  (ni->ifindiscards)++; +} + +void snmp_add_ifoutoctets(struct netif *ni, u32_t value) +{ +  ni->ifoutoctets += value; +} + +void snmp_inc_ifoutucastpkts(struct netif *ni) +{ +  (ni->ifoutucastpkts)++; +} + +void snmp_inc_ifoutnucastpkts(struct netif *ni) +{ +  (ni->ifoutnucastpkts)++; +} + +void snmp_inc_ifoutdiscards(struct netif *ni) +{ +  (ni->ifoutdiscards)++; +} + +void snmp_inc_iflist(void) +{ +  struct mib_list_node *if_node = NULL; + +  snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node); +  /* enable getnext traversal on filled table */ +  iftable.maxlength = 1; +} + +void snmp_dec_iflist(void) +{ +  snmp_mib_node_delete(&iflist_root, iflist_root.tail); +  /* disable getnext traversal on empty table */ +  if(iflist_root.count == 0) iftable.maxlength = 0; +} + +/** + * Inserts ARP table indexes (.xIfIndex.xNetAddress) + * into arp table index trees (both atTable and ipNetToMediaTable). + */ +void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip) +{ +  struct mib_list_rootnode *at_rn; +  struct mib_list_node *at_node; +  struct ip_addr hip; +  s32_t arpidx[5]; +  u8_t level, tree; + +  LWIP_ASSERT("ni != NULL", ni != NULL); +  snmp_netiftoifindex(ni, &arpidx[0]); +  hip.addr = ntohl(ip->addr); +  snmp_iptooid(&hip, &arpidx[1]); + +  for (tree = 0; tree < 2; tree++) +  { +    if (tree == 0) +    { +      at_rn = &arptree_root; +    } +    else +    { +      at_rn = &ipntomtree_root; +    } +    for (level = 0; level < 5; level++) +    { +      at_node = NULL; +      snmp_mib_node_insert(at_rn, arpidx[level], &at_node); +      if ((level != 4) && (at_node != NULL)) +      { +        if (at_node->nptr == NULL) +        { +          at_rn = snmp_mib_lrn_alloc(); +          at_node->nptr = (struct mib_node*)at_rn; +          if (at_rn != NULL) +          { +            if (level == 3) +            { +              if (tree == 0) +              { +                at_rn->get_object_def = atentry_get_object_def; +                at_rn->get_value = atentry_get_value; +              } +              else +              { +                at_rn->get_object_def = ip_ntomentry_get_object_def; +                at_rn->get_value = ip_ntomentry_get_value; +              } +              at_rn->set_test = noleafs_set_test; +              at_rn->set_value = noleafs_set_value; +            } +          } +          else +          { +            /* at_rn == NULL, malloc failure */ +            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full")); +            break; +          } +        } +        else +        { +          at_rn = (struct mib_list_rootnode*)at_node->nptr; +        } +      } +    } +  } +  /* enable getnext traversal on filled tables */ +  at.maxlength = 1; +  ipntomtable.maxlength = 1; +} + +/** + * Removes ARP table indexes (.xIfIndex.xNetAddress) + * from arp table index trees. + */ +void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip) +{ +  struct mib_list_rootnode *at_rn, *next, *del_rn[5]; +  struct mib_list_node *at_n, *del_n[5]; +  struct ip_addr hip; +  s32_t arpidx[5]; +  u8_t fc, tree, level, del_cnt; + +  snmp_netiftoifindex(ni, &arpidx[0]); +  hip.addr = ntohl(ip->addr); +  snmp_iptooid(&hip, &arpidx[1]); + +  for (tree = 0; tree < 2; tree++) +  { +    /* mark nodes for deletion */ +    if (tree == 0) +    { +      at_rn = &arptree_root; +    } +    else +    { +      at_rn = &ipntomtree_root; +    } +    level = 0; +    del_cnt = 0; +    while ((level < 5) && (at_rn != NULL)) +    { +      fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n); +      if (fc == 0) +      { +        /* arpidx[level] does not exist */ +        del_cnt = 0; +        at_rn = NULL; +      } +      else if (fc == 1) +      { +        del_rn[del_cnt] = at_rn; +        del_n[del_cnt] = at_n; +        del_cnt++; +        at_rn = (struct mib_list_rootnode*)(at_n->nptr); +      } +      else if (fc == 2) +      { +        /* reset delete (2 or more childs) */ +        del_cnt = 0; +        at_rn = (struct mib_list_rootnode*)(at_n->nptr); +      } +      level++; +    } +    /* delete marked index nodes */ +    while (del_cnt > 0) +    { +      del_cnt--; + +      at_rn = del_rn[del_cnt]; +      at_n = del_n[del_cnt]; + +      next = snmp_mib_node_delete(at_rn, at_n); +      if (next != NULL) +      { +        LWIP_ASSERT("next_count == 0",next->count == 0); +        snmp_mib_lrn_free(next); +      } +    } +  } +  /* disable getnext traversal on empty tables */ +  if(arptree_root.count == 0) at.maxlength = 0; +  if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0; +} + +void snmp_inc_ipinreceives(void) +{ +  ipinreceives++; +} + +void snmp_inc_ipinhdrerrors(void) +{ +  ipinhdrerrors++; +} + +void snmp_inc_ipinaddrerrors(void) +{ +  ipinaddrerrors++; +} + +void snmp_inc_ipforwdatagrams(void) +{ +  ipforwdatagrams++; +} + +void snmp_inc_ipinunknownprotos(void) +{ +  ipinunknownprotos++; +} + +void snmp_inc_ipindiscards(void) +{ +  ipindiscards++; +} + +void snmp_inc_ipindelivers(void) +{ +  ipindelivers++; +} + +void snmp_inc_ipoutrequests(void) +{ +  ipoutrequests++; +} + +void snmp_inc_ipoutdiscards(void) +{ +  ipoutdiscards++; +} + +void snmp_inc_ipoutnoroutes(void) +{ +  ipoutnoroutes++; +} + +void snmp_inc_ipreasmreqds(void) +{ +  ipreasmreqds++; +} + +void snmp_inc_ipreasmoks(void) +{ +  ipreasmoks++; +} + +void snmp_inc_ipreasmfails(void) +{ +  ipreasmfails++; +} + +void snmp_inc_ipfragoks(void) +{ +  ipfragoks++; +} + +void snmp_inc_ipfragfails(void) +{ +  ipfragfails++; +} + +void snmp_inc_ipfragcreates(void) +{ +  ipfragcreates++; +} + +void snmp_inc_iproutingdiscards(void) +{ +  iproutingdiscards++; +} + +/** + * Inserts ipAddrTable indexes (.ipAdEntAddr) + * into index tree. + */ +void snmp_insert_ipaddridx_tree(struct netif *ni) +{ +  struct mib_list_rootnode *ipa_rn; +  struct mib_list_node *ipa_node; +  struct ip_addr ip; +  s32_t ipaddridx[4]; +  u8_t level; + +  LWIP_ASSERT("ni != NULL", ni != NULL); +  ip.addr = ntohl(ni->ip_addr.addr); +  snmp_iptooid(&ip, &ipaddridx[0]); + +  level = 0; +  ipa_rn = &ipaddrtree_root; +  while (level < 4) +  { +    ipa_node = NULL; +    snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node); +    if ((level != 3) && (ipa_node != NULL)) +    { +      if (ipa_node->nptr == NULL) +      { +        ipa_rn = snmp_mib_lrn_alloc(); +        ipa_node->nptr = (struct mib_node*)ipa_rn; +        if (ipa_rn != NULL) +        { +          if (level == 2) +          { +            ipa_rn->get_object_def = ip_addrentry_get_object_def; +            ipa_rn->get_value = ip_addrentry_get_value; +            ipa_rn->set_test = noleafs_set_test; +            ipa_rn->set_value = noleafs_set_value; +          } +        } +        else +        { +          /* ipa_rn == NULL, malloc failure */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full")); +          break; +        } +      } +      else +      { +        ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr; +      } +    } +    level++; +  } +  /* enable getnext traversal on filled table */ +  ipaddrtable.maxlength = 1; +} + +/** + * Removes ipAddrTable indexes (.ipAdEntAddr) + * from index tree. + */ +void snmp_delete_ipaddridx_tree(struct netif *ni) +{ +  struct mib_list_rootnode *ipa_rn, *next, *del_rn[4]; +  struct mib_list_node *ipa_n, *del_n[4]; +  struct ip_addr ip; +  s32_t ipaddridx[4]; +  u8_t fc, level, del_cnt; + +  LWIP_ASSERT("ni != NULL", ni != NULL); +  ip.addr = ntohl(ni->ip_addr.addr); +  snmp_iptooid(&ip, &ipaddridx[0]); + +  /* mark nodes for deletion */ +  level = 0; +  del_cnt = 0; +  ipa_rn = &ipaddrtree_root; +  while ((level < 4) && (ipa_rn != NULL)) +  { +    fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n); +    if (fc == 0) +    { +      /* ipaddridx[level] does not exist */ +      del_cnt = 0; +      ipa_rn = NULL; +    } +    else if (fc == 1) +    { +      del_rn[del_cnt] = ipa_rn; +      del_n[del_cnt] = ipa_n; +      del_cnt++; +      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); +    } +    else if (fc == 2) +    { +      /* reset delete (2 or more childs) */ +      del_cnt = 0; +      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); +    } +    level++; +  } +  /* delete marked index nodes */ +  while (del_cnt > 0) +  { +    del_cnt--; + +    ipa_rn = del_rn[del_cnt]; +    ipa_n = del_n[del_cnt]; + +    next = snmp_mib_node_delete(ipa_rn, ipa_n); +    if (next != NULL) +    { +      LWIP_ASSERT("next_count == 0",next->count == 0); +      snmp_mib_lrn_free(next); +    } +  } +  /* disable getnext traversal on empty table */ +  if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0; +} + +/** + * Inserts ipRouteTable indexes (.ipRouteDest) + * into index tree. + * + * @param dflt non-zero for the default rte, zero for network rte + * @param ni points to network interface for this rte + * + * @todo record sysuptime for _this_ route when it is installed + *   (needed for ipRouteAge) in the netif. + */ +void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni) +{ +  u8_t insert = 0; +  struct ip_addr dst; + +  if (dflt != 0) +  { +    /* the default route 0.0.0.0 */ +    dst.addr = 0; +    insert = 1; +  } +  else +  { +    /* route to the network address */ +    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr); +    /* exclude 0.0.0.0 network (reserved for default rte) */ +    if (dst.addr != 0) insert = 1; +  } +  if (insert) +  { +    struct mib_list_rootnode *iprte_rn; +    struct mib_list_node *iprte_node; +    s32_t iprteidx[4]; +    u8_t level; + +    snmp_iptooid(&dst, &iprteidx[0]); +    level = 0; +    iprte_rn = &iprtetree_root; +    while (level < 4) +    { +      iprte_node = NULL; +      snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node); +      if ((level != 3) && (iprte_node != NULL)) +      { +        if (iprte_node->nptr == NULL) +        { +          iprte_rn = snmp_mib_lrn_alloc(); +          iprte_node->nptr = (struct mib_node*)iprte_rn; +          if (iprte_rn != NULL) +          { +            if (level == 2) +            { +              iprte_rn->get_object_def = ip_rteentry_get_object_def; +              iprte_rn->get_value = ip_rteentry_get_value; +              iprte_rn->set_test = noleafs_set_test; +              iprte_rn->set_value = noleafs_set_value; +            } +          } +          else +          { +            /* iprte_rn == NULL, malloc failure */ +            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full")); +            break; +          } +        } +        else +        { +          iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr; +        } +      } +      level++; +    } +  } +  /* enable getnext traversal on filled table */ +  iprtetable.maxlength = 1; +} + +/** + * Removes ipRouteTable indexes (.ipRouteDest) + * from index tree. + * + * @param dflt non-zero for the default rte, zero for network rte + * @param ni points to network interface for this rte or NULL + *   for default route to be removed. + */ +void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni) +{ +  u8_t delete = 0; +  struct ip_addr dst; + +  if (dflt != 0) +  { +    /* the default route 0.0.0.0 */ +    dst.addr = 0; +    delete = 1; +  } +  else +  { +    /* route to the network address */ +    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr); +    /* exclude 0.0.0.0 network (reserved for default rte) */ +    if (dst.addr != 0) delete = 1; +  } +  if (delete) +  { +    struct mib_list_rootnode *iprte_rn, *next, *del_rn[4]; +    struct mib_list_node *iprte_n, *del_n[4]; +    s32_t iprteidx[4]; +    u8_t fc, level, del_cnt; + +    snmp_iptooid(&dst, &iprteidx[0]); +    /* mark nodes for deletion */ +    level = 0; +    del_cnt = 0; +    iprte_rn = &iprtetree_root; +    while ((level < 4) && (iprte_rn != NULL)) +    { +      fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n); +      if (fc == 0) +      { +        /* iprteidx[level] does not exist */ +        del_cnt = 0; +        iprte_rn = NULL; +      } +      else if (fc == 1) +      { +        del_rn[del_cnt] = iprte_rn; +        del_n[del_cnt] = iprte_n; +        del_cnt++; +        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); +      } +      else if (fc == 2) +      { +        /* reset delete (2 or more childs) */ +        del_cnt = 0; +        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); +      } +      level++; +    } +    /* delete marked index nodes */ +    while (del_cnt > 0) +    { +      del_cnt--; + +      iprte_rn = del_rn[del_cnt]; +      iprte_n = del_n[del_cnt]; + +      next = snmp_mib_node_delete(iprte_rn, iprte_n); +      if (next != NULL) +      { +        LWIP_ASSERT("next_count == 0",next->count == 0); +        snmp_mib_lrn_free(next); +      } +    } +  } +  /* disable getnext traversal on empty table */ +  if (iprtetree_root.count == 0) iprtetable.maxlength = 0; +} + + +void snmp_inc_icmpinmsgs(void) +{ +  icmpinmsgs++; +} + +void snmp_inc_icmpinerrors(void) +{ +  icmpinerrors++; +} + +void snmp_inc_icmpindestunreachs(void) +{ +  icmpindestunreachs++; +} + +void snmp_inc_icmpintimeexcds(void) +{ +  icmpintimeexcds++; +} + +void snmp_inc_icmpinparmprobs(void) +{ +  icmpinparmprobs++; +} + +void snmp_inc_icmpinsrcquenchs(void) +{ +  icmpinsrcquenchs++; +} + +void snmp_inc_icmpinredirects(void) +{ +  icmpinredirects++; +} + +void snmp_inc_icmpinechos(void) +{ +  icmpinechos++; +} + +void snmp_inc_icmpinechoreps(void) +{ +  icmpinechoreps++; +} + +void snmp_inc_icmpintimestamps(void) +{ +  icmpintimestamps++; +} + +void snmp_inc_icmpintimestampreps(void) +{ +  icmpintimestampreps++; +} + +void snmp_inc_icmpinaddrmasks(void) +{ +  icmpinaddrmasks++; +} + +void snmp_inc_icmpinaddrmaskreps(void) +{ +  icmpinaddrmaskreps++; +} + +void snmp_inc_icmpoutmsgs(void) +{ +  icmpoutmsgs++; +} + +void snmp_inc_icmpouterrors(void) +{ +  icmpouterrors++; +} + +void snmp_inc_icmpoutdestunreachs(void) +{ +  icmpoutdestunreachs++; +} + +void snmp_inc_icmpouttimeexcds(void) +{ +  icmpouttimeexcds++; +} + +void snmp_inc_icmpoutparmprobs(void) +{ +  icmpoutparmprobs++; +} + +void snmp_inc_icmpoutsrcquenchs(void) +{ +  icmpoutsrcquenchs++; +} + +void snmp_inc_icmpoutredirects(void) +{ +  icmpoutredirects++; +} + +void snmp_inc_icmpoutechos(void) +{ +  icmpoutechos++; +} + +void snmp_inc_icmpoutechoreps(void) +{ +  icmpoutechoreps++; +} + +void snmp_inc_icmpouttimestamps(void) +{ +  icmpouttimestamps++; +} + +void snmp_inc_icmpouttimestampreps(void) +{ +  icmpouttimestampreps++; +} + +void snmp_inc_icmpoutaddrmasks(void) +{ +  icmpoutaddrmasks++; +} + +void snmp_inc_icmpoutaddrmaskreps(void) +{ +  icmpoutaddrmaskreps++; +} + +void snmp_inc_tcpactiveopens(void) +{ +  tcpactiveopens++; +} + +void snmp_inc_tcppassiveopens(void) +{ +  tcppassiveopens++; +} + +void snmp_inc_tcpattemptfails(void) +{ +  tcpattemptfails++; +} + +void snmp_inc_tcpestabresets(void) +{ +  tcpestabresets++; +} + +void snmp_inc_tcpinsegs(void) +{ +  tcpinsegs++; +} + +void snmp_inc_tcpoutsegs(void) +{ +  tcpoutsegs++; +} + +void snmp_inc_tcpretranssegs(void) +{ +  tcpretranssegs++; +} + +void snmp_inc_tcpinerrs(void) +{ +  tcpinerrs++; +} + +void snmp_inc_tcpoutrsts(void) +{ +  tcpoutrsts++; +} + +void snmp_inc_udpindatagrams(void) +{ +  udpindatagrams++; +} + +void snmp_inc_udpnoports(void) +{ +  udpnoports++; +} + +void snmp_inc_udpinerrors(void) +{ +  udpinerrors++; +} + +void snmp_inc_udpoutdatagrams(void) +{ +  udpoutdatagrams++; +} + +/** + * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort) + * into index tree. + */ +void snmp_insert_udpidx_tree(struct udp_pcb *pcb) +{ +  struct mib_list_rootnode *udp_rn; +  struct mib_list_node *udp_node; +  struct ip_addr ip; +  s32_t udpidx[5]; +  u8_t level; + +  LWIP_ASSERT("pcb != NULL", pcb != NULL); +  ip.addr = ntohl(pcb->local_ip.addr); +  snmp_iptooid(&ip, &udpidx[0]); +  udpidx[4] = pcb->local_port; + +  udp_rn = &udp_root; +  for (level = 0; level < 5; level++) +  { +    udp_node = NULL; +    snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node); +    if ((level != 4) && (udp_node != NULL)) +    { +      if (udp_node->nptr == NULL) +      { +        udp_rn = snmp_mib_lrn_alloc(); +        udp_node->nptr = (struct mib_node*)udp_rn; +        if (udp_rn != NULL) +        { +          if (level == 3) +          { +            udp_rn->get_object_def = udpentry_get_object_def; +            udp_rn->get_value = udpentry_get_value; +            udp_rn->set_test = noleafs_set_test; +            udp_rn->set_value = noleafs_set_value; +          } +        } +        else +        { +          /* udp_rn == NULL, malloc failure */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full")); +          break; +        } +      } +      else +      { +        udp_rn = (struct mib_list_rootnode*)udp_node->nptr; +      } +    } +  } +  udptable.maxlength = 1; +} + +/** + * Removes udpTable indexes (.udpLocalAddress.udpLocalPort) + * from index tree. + */ +void snmp_delete_udpidx_tree(struct udp_pcb *pcb) +{ +  struct mib_list_rootnode *udp_rn, *next, *del_rn[5]; +  struct mib_list_node *udp_n, *del_n[5]; +  struct ip_addr ip; +  s32_t udpidx[5]; +  u8_t bindings, fc, level, del_cnt; + +  LWIP_ASSERT("pcb != NULL", pcb != NULL); +  ip.addr = ntohl(pcb->local_ip.addr); +  snmp_iptooid(&ip, &udpidx[0]); +  udpidx[4] = pcb->local_port; + +  /* count PCBs for a given binding +     (e.g. when reusing ports or for temp output PCBs) */ +  bindings = 0; +  pcb = udp_pcbs; +  while ((pcb != NULL)) +  { +    if ((pcb->local_ip.addr == ip.addr) && +        (pcb->local_port == udpidx[4])) +    { +      bindings++; +    } +    pcb = pcb->next; +  } +  if (bindings == 1) +  { +    /* selectively remove */ +    /* mark nodes for deletion */ +    level = 0; +    del_cnt = 0; +    udp_rn = &udp_root; +    while ((level < 5) && (udp_rn != NULL)) +    { +      fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n); +      if (fc == 0) +      { +        /* udpidx[level] does not exist */ +        del_cnt = 0; +        udp_rn = NULL; +      } +      else if (fc == 1) +      { +        del_rn[del_cnt] = udp_rn; +        del_n[del_cnt] = udp_n; +        del_cnt++; +        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); +      } +      else if (fc == 2) +      { +        /* reset delete (2 or more childs) */ +        del_cnt = 0; +        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); +      } +      level++; +    } +    /* delete marked index nodes */ +    while (del_cnt > 0) +    { +      del_cnt--; + +      udp_rn = del_rn[del_cnt]; +      udp_n = del_n[del_cnt]; + +      next = snmp_mib_node_delete(udp_rn, udp_n); +      if (next != NULL) +      { +        LWIP_ASSERT("next_count == 0",next->count == 0); +        snmp_mib_lrn_free(next); +      } +    } +  } +  /* disable getnext traversal on empty table */ +  if (udp_root.count == 0) udptable.maxlength = 0; +} + + +void snmp_inc_snmpinpkts(void) +{ +  snmpinpkts++; +} + +void snmp_inc_snmpoutpkts(void) +{ +  snmpoutpkts++; +} + +void snmp_inc_snmpinbadversions(void) +{ +  snmpinbadversions++; +} + +void snmp_inc_snmpinbadcommunitynames(void) +{ +  snmpinbadcommunitynames++; +} + +void snmp_inc_snmpinbadcommunityuses(void) +{ +  snmpinbadcommunityuses++; +} + +void snmp_inc_snmpinasnparseerrs(void) +{ +  snmpinasnparseerrs++; +} + +void snmp_inc_snmpintoobigs(void) +{ +  snmpintoobigs++; +} + +void snmp_inc_snmpinnosuchnames(void) +{ +  snmpinnosuchnames++; +} + +void snmp_inc_snmpinbadvalues(void) +{ +  snmpinbadvalues++; +} + +void snmp_inc_snmpinreadonlys(void) +{ +  snmpinreadonlys++; +} + +void snmp_inc_snmpingenerrs(void) +{ +  snmpingenerrs++; +} + +void snmp_add_snmpintotalreqvars(u8_t value) +{ +  snmpintotalreqvars += value; +} + +void snmp_add_snmpintotalsetvars(u8_t value) +{ +  snmpintotalsetvars += value; +} + +void snmp_inc_snmpingetrequests(void) +{ +  snmpingetrequests++; +} + +void snmp_inc_snmpingetnexts(void) +{ +  snmpingetnexts++; +} + +void snmp_inc_snmpinsetrequests(void) +{ +  snmpinsetrequests++; +} + +void snmp_inc_snmpingetresponses(void) +{ +  snmpingetresponses++; +} + +void snmp_inc_snmpintraps(void) +{ +  snmpintraps++; +} + +void snmp_inc_snmpouttoobigs(void) +{ +  snmpouttoobigs++; +} + +void snmp_inc_snmpoutnosuchnames(void) +{ +  snmpoutnosuchnames++; +} + +void snmp_inc_snmpoutbadvalues(void) +{ +  snmpoutbadvalues++; +} + +void snmp_inc_snmpoutgenerrs(void) +{ +  snmpoutgenerrs++; +} + +void snmp_inc_snmpoutgetrequests(void) +{ +  snmpoutgetrequests++; +} + +void snmp_inc_snmpoutgetnexts(void) +{ +  snmpoutgetnexts++; +} + +void snmp_inc_snmpoutsetrequests(void) +{ +  snmpoutsetrequests++; +} + +void snmp_inc_snmpoutgetresponses(void) +{ +  snmpoutgetresponses++; +} + +void snmp_inc_snmpouttraps(void) +{ +  snmpouttraps++; +} + +void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid) +{ +  *oid = &snmpgrp_id; +} + +void snmp_set_snmpenableauthentraps(u8_t *value) +{ +  if (value != NULL) +  { +    snmpenableauthentraps_ptr = value; +  } +} + +void snmp_get_snmpenableauthentraps(u8_t *value) +{ +  *value = *snmpenableauthentraps_ptr; +} + +void +noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  if (ident_len){} +  if (ident){} +  od->instance = MIB_OBJECT_NONE; +} + +void +noleafs_get_value(struct obj_def *od, u16_t len, void *value) +{ +  if (od){} +  if (len){} +  if (value){} +} + +u8_t +noleafs_set_test(struct obj_def *od, u16_t len, void *value) +{ +  if (od){} +  if (len){} +  if (value){} +  /* can't set */ +  return 0; +} + +void +noleafs_set_value(struct obj_def *od, u16_t len, void *value) +{ +  if (od){} +  if (len){} +  if (value){} +} + + +/** + * Returns systems object definitions. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param od points to object definition. + */ +static void +system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  u8_t id; + +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if (ident_len == 2) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id)); +    switch (id) +    { +      case 1: /* sysDescr */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +        od->v_len = *sysdescr_len_ptr; +        break; +      case 2: /* sysObjectID */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); +        od->v_len = sysobjid.len * sizeof(s32_t); +        break; +      case 3: /* sysUpTime */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); +        od->v_len = sizeof(u32_t); +        break; +      case 4: /* sysContact */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +        od->v_len = *syscontact_len_ptr; +        break; +      case 5: /* sysName */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +        od->v_len = *sysname_len_ptr; +        break; +      case 6: /* sysLocation */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +        od->v_len = *syslocation_len_ptr; +        break; +      case 7: /* sysServices */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    }; +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +/** + * Returns system object value. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value into. + */ +static void +system_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id; + +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* sysDescr */ +      ocstrncpy(value,sysdescr_ptr, len); +      break; +    case 2: /* sysObjectID */ +      objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t))); +      break; +    case 3: /* sysUpTime */ +      { +        snmp_get_sysuptime(value); +      } +      break; +    case 4: /* sysContact */ +      ocstrncpy(value,syscontact_ptr,len); +      break; +    case 5: /* sysName */ +      ocstrncpy(value,sysname_ptr,len); +      break; +    case 6: /* sysLocation */ +      ocstrncpy(value,syslocation_ptr,len); +      break; +    case 7: /* sysServices */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = sysservices; +      } +      break; +  }; +} + +static u8_t +system_set_test(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id, set_ok; + +  if (value) {} +  set_ok = 0; +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 4: /* sysContact */ +      if ((syscontact_ptr != syscontact_default) && +          (len <= 255)) +      { +        set_ok = 1; +      } +      break; +    case 5: /* sysName */ +      if ((sysname_ptr != sysname_default) && +          (len <= 255)) +      { +        set_ok = 1; +      } +      break; +    case 6: /* sysLocation */ +      if ((syslocation_ptr != syslocation_default) && +          (len <= 255)) +      { +        set_ok = 1; +      } +      break; +  }; +  return set_ok; +} + +static void +system_set_value(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id; + +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 4: /* sysContact */ +      ocstrncpy(syscontact_ptr,value,len); +      *syscontact_len_ptr = len; +      break; +    case 5: /* sysName */ +      ocstrncpy(sysname_ptr,value,len); +      *sysname_len_ptr = len; +      break; +    case 6: /* sysLocation */ +      ocstrncpy(syslocation_ptr,value,len); +      *syslocation_len_ptr = len; +      break; +  }; +} + +/** + * Returns interfaces.ifnumber object definition. + * + * @param ident_len the address length (2) + * @param ident points to objectname.index + * @param od points to object definition. + */ +static void +interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if (ident_len == 2) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    od->instance = MIB_OBJECT_SCALAR; +    od->access = MIB_OBJECT_READ_ONLY; +    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +    od->v_len = sizeof(s32_t); +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +/** + * Returns interfaces.ifnumber object value. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value into. + */ +static void +interfaces_get_value(struct obj_def *od, u16_t len, void *value) +{ +  if (len){} +  if (od->id_inst_ptr[0] == 1) +  { +    s32_t *sint_ptr = value; +    *sint_ptr = iflist_root.count; +  } +} + +/** + * Returns ifentry object definitions. + * + * @param ident_len the address length (2) + * @param ident points to objectname.index + * @param od points to object definition. + */ +static void +ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  u8_t id; + +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if (ident_len == 2) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id)); +    switch (id) +    { +      case 1: /* ifIndex */ +      case 3: /* ifType */ +      case 4: /* ifMtu */ +      case 8: /* ifOperStatus */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 2: /* ifDescr */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +        /** @todo this should be some sort of sizeof(struct netif.name) */ +        od->v_len = 2; +        break; +      case 5: /* ifSpeed */ +      case 21: /* ifOutQLen */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); +        od->v_len = sizeof(u32_t); +        break; +      case 6: /* ifPhysAddress */ +        { +          struct netif *netif; + +          snmp_ifindextonetif(ident[1], &netif); +          od->instance = MIB_OBJECT_TAB; +          od->access = MIB_OBJECT_READ_ONLY; +          od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +          od->v_len = netif->hwaddr_len; +        } +        break; +      case 7: /* ifAdminStatus */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 9: /* ifLastChange */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); +        od->v_len = sizeof(u32_t); +        break; +      case 10: /* ifInOctets */ +      case 11: /* ifInUcastPkts */ +      case 12: /* ifInNUcastPkts */ +      case 13: /* ifInDiscarts */ +      case 14: /* ifInErrors */ +      case 15: /* ifInUnkownProtos */ +      case 16: /* ifOutOctets */ +      case 17: /* ifOutUcastPkts */ +      case 18: /* ifOutNUcastPkts */ +      case 19: /* ifOutDiscarts */ +      case 20: /* ifOutErrors */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); +        od->v_len = sizeof(u32_t); +        break; +      case 22: /* ifSpecific */ +        /** @note returning zeroDotZero (0.0) no media specific MIB support */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); +        od->v_len = ifspecific.len * sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    }; +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +/** + * Returns ifentry object value. + * + * @param ident_len the address length (2) + * @param ident points to objectname.0 (object id trailer) + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value into. + */ +static void +ifentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +  struct netif *netif; +  u8_t id; + +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* ifIndex */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = od->id_inst_ptr[1]; +      } +      break; +    case 2: /* ifDescr */ +      ocstrncpy(value,(u8_t*)netif->name,len); +      break; +    case 3: /* ifType */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = netif->link_type; +      } +      break; +    case 4: /* ifMtu */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = netif->mtu; +      } +      break; +    case 5: /* ifSpeed */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->link_speed; +      } +      break; +    case 6: /* ifPhysAddress */ +      ocstrncpy(value,netif->hwaddr,len); +      break; +    case 7: /* ifAdminStatus */ +#if LWIP_NETIF_LINK_CALLBACK +      { +        s32_t *sint_ptr = value; +        if (netif_is_up(netif)) +        { +          if (netif_is_link_up(netif)) +          { +            *sint_ptr = 1; /* up */ +          } +          else +          { +            *sint_ptr = 7; /* lowerLayerDown */ +          } +        } +        else +        { +          *sint_ptr = 2; /* down */ +        } +      } +      break; +#endif +    case 8: /* ifOperStatus */ +      { +        s32_t *sint_ptr = value; +        if (netif_is_up(netif)) +        { +          *sint_ptr = 1; +        } +        else +        { +          *sint_ptr = 2; +        } +      } +      break; +    case 9: /* ifLastChange */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ts; +      } +      break; +    case 10: /* ifInOctets */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifinoctets; +      } +      break; +    case 11: /* ifInUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifinucastpkts; +      } +      break; +    case 12: /* ifInNUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifinnucastpkts; +      } +      break; +    case 13: /* ifInDiscarts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifindiscards; +      } +      break; +    case 14: /* ifInErrors */ +    case 15: /* ifInUnkownProtos */ +      /** @todo add these counters! */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = 0; +      } +      break; +    case 16: /* ifOutOctets */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutoctets; +      } +      break; +    case 17: /* ifOutUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutucastpkts; +      } +      break; +    case 18: /* ifOutNUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutnucastpkts; +      } +      break; +    case 19: /* ifOutDiscarts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutdiscards; +      } +      break; +    case 20: /* ifOutErrors */ +       /** @todo add this counter! */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = 0; +      } +      break; +    case 21: /* ifOutQLen */ +      /** @todo figure out if this must be 0 (no queue) or 1? */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = 0; +      } +      break; +    case 22: /* ifSpecific */ +      objectidncpy((s32_t*)value, (s32_t*)ifspecific.id, (u8_t)(len / sizeof(s32_t))); +      break; +  }; +} + +#if !SNMP_SAFE_REQUESTS +static u8_t +ifentry_set_test (struct obj_def *od, u16_t len, void *value) +{ +  struct netif *netif; +  u8_t id, set_ok; + +  set_ok = 0; +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 7: /* ifAdminStatus */ +      { +        s32_t *sint_ptr = value; +        if (*sint_ptr == 1 || *sint_ptr == 2) +          set_ok = 1; +      } +      break; +  } +  return set_ok; +} + +static void +ifentry_set_value (struct obj_def *od, u16_t len, void *value) +{ +  struct netif *netif; +  u8_t id; + +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 7: /* ifAdminStatus */ +      { +        s32_t *sint_ptr = value; +        if (*sint_ptr == 1) +        { +          netif_set_up(netif); +        } +        else if (*sint_ptr == 2) +        { +          netif_set_down(netif); +         } +      } +      break; +  } +} +#endif /* SNMP_SAFE_REQUESTS */ + +/** + * Returns atentry object definitions. + * + * @param ident_len the address length (6) + * @param ident points to objectname.atifindex.atnetaddress + * @param od points to object definition. + */ +static void +atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (5) */ +  ident_len += 5; +  ident -= 5; + +  if (ident_len == 6) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    switch (ident[0]) +    { +      case 1: /* atIfIndex */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 2: /* atPhysAddress */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +        od->v_len = 6; /** @todo try to use netif::hwaddr_len */ +        break; +      case 3: /* atNetAddress */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); +        od->v_len = 4; +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    } +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +atentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +#if LWIP_ARP +  u8_t id; +  struct eth_addr* ethaddr_ret; +  struct ip_addr* ipaddr_ret; +#endif /* LWIP_ARP */ +  struct ip_addr ip; +  struct netif *netif; + +  if (len) {} + +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  snmp_oidtoip(&od->id_inst_ptr[2], &ip); +  ip.addr = htonl(ip.addr); + +#if LWIP_ARP /** @todo implement a netif_find_addr */ +  if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* atIfIndex */ +        { +          s32_t *sint_ptr = value; +          *sint_ptr = od->id_inst_ptr[1]; +        } +        break; +      case 2: /* atPhysAddress */ +        { +          struct eth_addr *dst = value; + +          *dst = *ethaddr_ret; +        } +        break; +      case 3: /* atNetAddress */ +        { +          struct ip_addr *dst = value; + +          *dst = *ipaddr_ret; +        } +        break; +    } +  } +#endif /* LWIP_ARP */ +} + +static void +ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  u8_t id; + +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if (ident_len == 2) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id)); +    switch (id) +    { +      case 1: /* ipForwarding */ +      case 2: /* ipDefaultTTL */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 3: /* ipInReceives */ +      case 4: /* ipInHdrErrors */ +      case 5: /* ipInAddrErrors */ +      case 6: /* ipForwDatagrams */ +      case 7: /* ipInUnknownProtos */ +      case 8: /* ipInDiscards */ +      case 9: /* ipInDelivers */ +      case 10: /* ipOutRequests */ +      case 11: /* ipOutDiscards */ +      case 12: /* ipOutNoRoutes */ +      case 14: /* ipReasmReqds */ +      case 15: /* ipReasmOKs */ +      case 16: /* ipReasmFails */ +      case 17: /* ipFragOKs */ +      case 18: /* ipFragFails */ +      case 19: /* ipFragCreates */ +      case 23: /* ipRoutingDiscards */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); +        od->v_len = sizeof(u32_t); +        break; +      case 13: /* ipReasmTimeout */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    }; +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +ip_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id; + +  if (len) {} +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* ipForwarding */ +      { +        s32_t *sint_ptr = value; +#if IP_FORWARD +        /* forwarding */ +        *sint_ptr = 1; +#else +        /* not-forwarding */ +        *sint_ptr = 2; +#endif +      } +      break; +    case 2: /* ipDefaultTTL */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = IP_DEFAULT_TTL; +      } +      break; +    case 3: /* ipInReceives */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinreceives; +      } +      break; +    case 4: /* ipInHdrErrors */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinhdrerrors; +      } +      break; +    case 5: /* ipInAddrErrors */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinaddrerrors; +      } +      break; +    case 6: /* ipForwDatagrams */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipforwdatagrams; +      } +      break; +    case 7: /* ipInUnknownProtos */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinunknownprotos; +      } +      break; +    case 8: /* ipInDiscards */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipindiscards; +      } +      break; +    case 9: /* ipInDelivers */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipindelivers; +      } +      break; +    case 10: /* ipOutRequests */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipoutrequests; +      } +      break; +    case 11: /* ipOutDiscards */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipoutdiscards; +      } +      break; +    case 12: /* ipOutNoRoutes */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipoutnoroutes; +      } +      break; +    case 13: /* ipReasmTimeout */ +      { +        s32_t *sint_ptr = value; +#if IP_REASSEMBLY +        *sint_ptr = IP_REASS_MAXAGE; +#else +        *sint_ptr = 0; +#endif +      } +      break; +    case 14: /* ipReasmReqds */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipreasmreqds; +      } +      break; +    case 15: /* ipReasmOKs */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipreasmoks; +      } +      break; +    case 16: /* ipReasmFails */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipreasmfails; +      } +      break; +    case 17: /* ipFragOKs */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipfragoks; +      } +      break; +    case 18: /* ipFragFails */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipfragfails; +      } +      break; +    case 19: /* ipFragCreates */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipfragcreates; +      } +      break; +    case 23: /* ipRoutingDiscards */ +      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = iproutingdiscards; +      } +      break; +  }; +} + +/** + * Test ip object value before setting. + * + * @param od is the object definition + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value from. + * + * @note we allow set if the value matches the hardwired value, + *   otherwise return badvalue. + */ +static u8_t +ip_set_test(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id, set_ok; +  s32_t *sint_ptr = value; + +  if (len) {} +  set_ok = 0; +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* ipForwarding */ +#if IP_FORWARD +      /* forwarding */ +      if (*sint_ptr == 1) +#else +      /* not-forwarding */ +      if (*sint_ptr == 2) +#endif +      { +        set_ok = 1; +      } +      break; +    case 2: /* ipDefaultTTL */ +      if (*sint_ptr == IP_DEFAULT_TTL) +      { +        set_ok = 1; +      } +      break; +  }; +  return set_ok; +} + +static void +ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (4) */ +  ident_len += 4; +  ident -= 4; + +  if (ident_len == 5) +  { +    u8_t id; + +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    switch (id) +    { +      case 1: /* ipAdEntAddr */ +      case 3: /* ipAdEntNetMask */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); +        od->v_len = 4; +        break; +      case 2: /* ipAdEntIfIndex */ +      case 4: /* ipAdEntBcastAddr */ +      case 5: /* ipAdEntReasmMaxSize */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    } +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id; +  u16_t ifidx; +  struct ip_addr ip; +  struct netif *netif = netif_list; + +  if (len) {} +  snmp_oidtoip(&od->id_inst_ptr[1], &ip); +  ip.addr = htonl(ip.addr); +  ifidx = 0; +  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr)) +  { +    netif = netif->next; +    ifidx++; +  } + +  if (netif != NULL) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* ipAdEntAddr */ +        { +          struct ip_addr *dst = value; +          *dst = netif->ip_addr; +        } +        break; +      case 2: /* ipAdEntIfIndex */ +        { +          s32_t *sint_ptr = value; +          *sint_ptr = ifidx + 1; +        } +        break; +      case 3: /* ipAdEntNetMask */ +        { +          struct ip_addr *dst = value; +          *dst = netif->netmask; +        } +        break; +      case 4: /* ipAdEntBcastAddr */ +        { +          s32_t *sint_ptr = value; + +          /* lwIP oddity, there's no broadcast +            address in the netif we can rely on */ +          *sint_ptr = ip_addr_broadcast.addr & 1; +        } +        break; +      case 5: /* ipAdEntReasmMaxSize */ +        { +          s32_t *sint_ptr = value; +#if IP_REASSEMBLY +          /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs, +           * but only if receiving one fragmented packet at a time. +           * The current solution is to calculate for 2 simultaneous packets... +           */ +          *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) * +            (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IP_HLEN))); +#else +          /** @todo returning MTU would be a bad thing and +             returning a wild guess like '576' isn't good either */ +          *sint_ptr = 0; +#endif +        } +        break; +    } +  } +} + +/** + * @note + * lwIP IP routing is currently using the network addresses in netif_list. + * if no suitable network IP is found in netif_list, the default_netif is used. + */ +static void +ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  u8_t id; + +  /* return to object name, adding index depth (4) */ +  ident_len += 4; +  ident -= 4; + +  if (ident_len == 5) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    switch (id) +    { +      case 1: /* ipRouteDest */ +      case 7: /* ipRouteNextHop */ +      case 11: /* ipRouteMask */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); +        od->v_len = 4; +        break; +      case 2: /* ipRouteIfIndex */ +      case 3: /* ipRouteMetric1 */ +      case 4: /* ipRouteMetric2 */ +      case 5: /* ipRouteMetric3 */ +      case 6: /* ipRouteMetric4 */ +      case 8: /* ipRouteType */ +      case 10: /* ipRouteAge */ +      case 12: /* ipRouteMetric5 */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 9: /* ipRouteProto */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 13: /* ipRouteInfo */ +        /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); +        od->v_len = iprouteinfo.len * sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    } +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +  struct netif *netif; +  struct ip_addr dest; +  s32_t *ident; +  u8_t id; + +  ident = od->id_inst_ptr; +  snmp_oidtoip(&ident[1], &dest); +  dest.addr = htonl(dest.addr); + +  if (dest.addr == 0) +  { +    /* ip_route() uses default netif for default route */ +    netif = netif_default; +  } +  else +  { +    /* not using ip_route(), need exact match! */ +    netif = netif_list; +    while ((netif != NULL) && +            !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) ) +    { +      netif = netif->next; +    } +  } +  if (netif != NULL) +  { +    id = ident[0]; +    switch (id) +    { +      case 1: /* ipRouteDest */ +        { +          struct ip_addr *dst = value; + +          if (dest.addr == 0) +          { +            /* default rte has 0.0.0.0 dest */ +            dst->addr = 0; +          } +          else +          { +            /* netifs have netaddress dest */ +            dst->addr = netif->ip_addr.addr & netif->netmask.addr; +          } +        } +        break; +      case 2: /* ipRouteIfIndex */ +        { +          s32_t *sint_ptr = value; + +          snmp_netiftoifindex(netif, sint_ptr); +        } +        break; +      case 3: /* ipRouteMetric1 */ +        { +          s32_t *sint_ptr = value; + +          if (dest.addr == 0) +          { +            /* default rte has metric 1 */ +            *sint_ptr = 1; +          } +          else +          { +            /* other rtes have metric 0 */ +            *sint_ptr = 0; +          } +        } +        break; +      case 4: /* ipRouteMetric2 */ +      case 5: /* ipRouteMetric3 */ +      case 6: /* ipRouteMetric4 */ +      case 12: /* ipRouteMetric5 */ +        { +          s32_t *sint_ptr = value; +          /* not used */ +          *sint_ptr = -1; +        } +        break; +      case 7: /* ipRouteNextHop */ +        { +          struct ip_addr *dst = value; + +          if (dest.addr == 0) +          { +            /* default rte: gateway */ +            *dst = netif->gw; +          } +          else +          { +            /* other rtes: netif ip_addr  */ +            *dst = netif->ip_addr; +          } +        } +        break; +      case 8: /* ipRouteType */ +        { +          s32_t *sint_ptr = value; + +          if (dest.addr == 0) +          { +            /* default rte is indirect */ +            *sint_ptr = 4; +          } +          else +          { +            /* other rtes are direct */ +            *sint_ptr = 3; +          } +        } +        break; +      case 9: /* ipRouteProto */ +        { +          s32_t *sint_ptr = value; +          /* locally defined routes */ +          *sint_ptr = 2; +        } +        break; +      case 10: /* ipRouteAge */ +        { +          s32_t *sint_ptr = value; +          /** @todo (sysuptime - timestamp last change) / 100 +              @see snmp_insert_iprteidx_tree() */ +          *sint_ptr = 0; +        } +        break; +      case 11: /* ipRouteMask */ +        { +          struct ip_addr *dst = value; + +          if (dest.addr == 0) +          { +            /* default rte use 0.0.0.0 mask */ +            dst->addr = 0; +          } +          else +          { +            /* other rtes use netmask */ +            *dst = netif->netmask; +          } +        } +        break; +      case 13: /* ipRouteInfo */ +        objectidncpy((s32_t*)value, (s32_t*)iprouteinfo.id, (u8_t)(len / sizeof(s32_t))); +        break; +    } +  } +} + +static void +ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (5) */ +  ident_len += 5; +  ident -= 5; + +  if (ident_len == 6) +  { +    u8_t id; + +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    switch (id) +    { +      case 1: /* ipNetToMediaIfIndex */ +      case 4: /* ipNetToMediaType */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 2: /* ipNetToMediaPhysAddress */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); +        od->v_len = 6; /** @todo try to use netif::hwaddr_len */ +        break; +      case 3: /* ipNetToMediaNetAddress */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); +        od->v_len = 4; +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    } +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +#if LWIP_ARP +  u8_t id; +  struct eth_addr* ethaddr_ret; +  struct ip_addr* ipaddr_ret; +#endif /* LWIP_ARP */ +  struct ip_addr ip; +  struct netif *netif; + +  if (len) {} + +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  snmp_oidtoip(&od->id_inst_ptr[2], &ip); +  ip.addr = htonl(ip.addr); + +#if LWIP_ARP /** @todo implement a netif_find_addr */ +  if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* ipNetToMediaIfIndex */ +        { +          s32_t *sint_ptr = value; +          *sint_ptr = od->id_inst_ptr[1]; +        } +        break; +      case 2: /* ipNetToMediaPhysAddress */ +        { +          struct eth_addr *dst = value; + +          *dst = *ethaddr_ret; +        } +        break; +      case 3: /* ipNetToMediaNetAddress */ +        { +          struct ip_addr *dst = value; + +          *dst = *ipaddr_ret; +        } +        break; +      case 4: /* ipNetToMediaType */ +        { +          s32_t *sint_ptr = value; +          /* dynamic (?) */ +          *sint_ptr = 3; +        } +        break; +    } +  } +#endif /* LWIP_ARP */ +} + +static void +icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if ((ident_len == 2) && +      (ident[0] > 0) && (ident[0] < 27)) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    od->instance = MIB_OBJECT_SCALAR; +    od->access = MIB_OBJECT_READ_ONLY; +    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); +    od->v_len = sizeof(u32_t); +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +icmp_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u32_t *uint_ptr = value; +  u8_t id; + +  if (len){} +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* icmpInMsgs */ +      *uint_ptr = icmpinmsgs; +      break; +    case 2: /* icmpInErrors */ +      *uint_ptr = icmpinerrors; +      break; +    case 3: /* icmpInDestUnreachs */ +      *uint_ptr = icmpindestunreachs; +      break; +    case 4: /* icmpInTimeExcds */ +      *uint_ptr = icmpintimeexcds; +      break; +    case 5: /* icmpInParmProbs */ +      *uint_ptr = icmpinparmprobs; +      break; +    case 6: /* icmpInSrcQuenchs */ +      *uint_ptr = icmpinsrcquenchs; +      break; +    case 7: /* icmpInRedirects */ +      *uint_ptr = icmpinredirects; +      break; +    case 8: /* icmpInEchos */ +      *uint_ptr = icmpinechos; +      break; +    case 9: /* icmpInEchoReps */ +      *uint_ptr = icmpinechoreps; +      break; +    case 10: /* icmpInTimestamps */ +      *uint_ptr = icmpintimestamps; +      break; +    case 11: /* icmpInTimestampReps */ +      *uint_ptr = icmpintimestampreps; +      break; +    case 12: /* icmpInAddrMasks */ +      *uint_ptr = icmpinaddrmasks; +      break; +    case 13: /* icmpInAddrMaskReps */ +      *uint_ptr = icmpinaddrmaskreps; +      break; +    case 14: /* icmpOutMsgs */ +      *uint_ptr = icmpoutmsgs; +      break; +    case 15: /* icmpOutErrors */ +      *uint_ptr = icmpouterrors; +      break; +    case 16: /* icmpOutDestUnreachs */ +      *uint_ptr = icmpoutdestunreachs; +      break; +    case 17: /* icmpOutTimeExcds */ +      *uint_ptr = icmpouttimeexcds; +      break; +    case 18: /* icmpOutParmProbs */ +      *uint_ptr = icmpoutparmprobs; +      break; +    case 19: /* icmpOutSrcQuenchs */ +      *uint_ptr = icmpoutsrcquenchs; +      break; +    case 20: /* icmpOutRedirects */ +      *uint_ptr = icmpoutredirects; +      break; +    case 21: /* icmpOutEchos */ +      *uint_ptr = icmpoutechos; +      break; +    case 22: /* icmpOutEchoReps */ +      *uint_ptr = icmpoutechoreps; +      break; +    case 23: /* icmpOutTimestamps */ +      *uint_ptr = icmpouttimestamps; +      break; +    case 24: /* icmpOutTimestampReps */ +      *uint_ptr = icmpouttimestampreps; +      break; +    case 25: /* icmpOutAddrMasks */ +      *uint_ptr = icmpoutaddrmasks; +      break; +    case 26: /* icmpOutAddrMaskReps */ +      *uint_ptr = icmpoutaddrmaskreps; +      break; +  } +} + +#if LWIP_TCP +/** @todo tcp grp */ +static void +tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  u8_t id; + +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if (ident_len == 2) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); + +    switch (id) +    { +      case 1: /* tcpRtoAlgorithm */ +      case 2: /* tcpRtoMin */ +      case 3: /* tcpRtoMax */ +      case 4: /* tcpMaxConn */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 5: /* tcpActiveOpens */ +      case 6: /* tcpPassiveOpens */ +      case 7: /* tcpAttemptFails */ +      case 8: /* tcpEstabResets */ +      case 10: /* tcpInSegs */ +      case 11: /* tcpOutSegs */ +      case 12: /* tcpRetransSegs */ +      case 14: /* tcpInErrs */ +      case 15: /* tcpOutRsts */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); +        od->v_len = sizeof(u32_t); +        break; +      case 9: /* tcpCurrEstab */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); +        od->v_len = sizeof(u32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    }; +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +tcp_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u32_t *uint_ptr = value; +  s32_t *sint_ptr = value; +  u8_t id; + +  if (len){} +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* tcpRtoAlgorithm, vanj(4) */ +      *sint_ptr = 4; +      break; +    case 2: /* tcpRtoMin */ +      /* @todo not the actual value, a guess, +          needs to be calculated */ +      *sint_ptr = 1000; +      break; +    case 3: /* tcpRtoMax */ +      /* @todo not the actual value, a guess, +         needs to be calculated */ +      *sint_ptr = 60000; +      break; +    case 4: /* tcpMaxConn */ +      *sint_ptr = MEMP_NUM_TCP_PCB; +      break; +    case 5: /* tcpActiveOpens */ +      *uint_ptr = tcpactiveopens; +      break; +    case 6: /* tcpPassiveOpens */ +      *uint_ptr = tcppassiveopens; +      break; +    case 7: /* tcpAttemptFails */ +      *uint_ptr = tcpattemptfails; +      break; +    case 8: /* tcpEstabResets */ +      *uint_ptr = tcpestabresets; +      break; +    case 9: /* tcpCurrEstab */ +      { +        u16_t tcpcurrestab = 0; +        struct tcp_pcb *pcb = tcp_active_pcbs; +        while (pcb != NULL) +        { +          if ((pcb->state == ESTABLISHED) || +              (pcb->state == CLOSE_WAIT)) +          { +            tcpcurrestab++; +          } +          pcb = pcb->next; +        } +        *uint_ptr = tcpcurrestab; +      } +      break; +    case 10: /* tcpInSegs */ +      *uint_ptr = tcpinsegs; +      break; +    case 11: /* tcpOutSegs */ +      *uint_ptr = tcpoutsegs; +      break; +    case 12: /* tcpRetransSegs */ +      *uint_ptr = tcpretranssegs; +      break; +    case 14: /* tcpInErrs */ +      *uint_ptr = tcpinerrs; +      break; +    case 15: /* tcpOutRsts */ +      *uint_ptr = tcpoutrsts; +      break; +  } +} +#ifdef THIS_SEEMS_UNUSED +static void +tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (10) */ +  ident_len += 10; +  ident -= 10; + +  if (ident_len == 11) +  { +    u8_t id; + +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); + +    switch (id) +    { +      case 1: /* tcpConnState */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      case 2: /* tcpConnLocalAddress */ +      case 4: /* tcpConnRemAddress */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); +        od->v_len = 4; +        break; +      case 3: /* tcpConnLocalPort */ +      case 5: /* tcpConnRemPort */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    }; +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +  struct ip_addr lip, rip; +  u16_t lport, rport; +  s32_t *ident; + +  ident = od->id_inst_ptr; +  snmp_oidtoip(&ident[1], &lip); +  lip.addr = htonl(lip.addr); +  lport = ident[5]; +  snmp_oidtoip(&ident[6], &rip); +  rip.addr = htonl(rip.addr); +  rport = ident[10]; + +  /** @todo find matching PCB */ +} +#endif /* if 0 */ +#endif + +static void +udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if ((ident_len == 2) && +      (ident[0] > 0) && (ident[0] < 6)) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    od->instance = MIB_OBJECT_SCALAR; +    od->access = MIB_OBJECT_READ_ONLY; +    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); +    od->v_len = sizeof(u32_t); +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +udp_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u32_t *uint_ptr = value; +  u8_t id; + +  if (len){} +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* udpInDatagrams */ +      *uint_ptr = udpindatagrams; +      break; +    case 2: /* udpNoPorts */ +      *uint_ptr = udpnoports; +      break; +    case 3: /* udpInErrors */ +      *uint_ptr = udpinerrors; +      break; +    case 4: /* udpOutDatagrams */ +      *uint_ptr = udpoutdatagrams; +      break; +  } +} + +static void +udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (5) */ +  ident_len += 5; +  ident -= 5; + +  if (ident_len == 6) +  { +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    switch (ident[0]) +    { +      case 1: /* udpLocalAddress */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); +        od->v_len = 4; +        break; +      case 2: /* udpLocalPort */ +        od->instance = MIB_OBJECT_TAB; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    } +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +udpentry_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id; +  struct udp_pcb *pcb; +  struct ip_addr ip; +  u16_t port; + +  if (len){} +  snmp_oidtoip(&od->id_inst_ptr[1], &ip); +  ip.addr = htonl(ip.addr); +  port = od->id_inst_ptr[5]; + +  pcb = udp_pcbs; +  while ((pcb != NULL) && +         !((pcb->local_ip.addr == ip.addr) && +           (pcb->local_port == port))) +  { +    pcb = pcb->next; +  } + +  if (pcb != NULL) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* udpLocalAddress */ +        { +          struct ip_addr *dst = value; +          *dst = pcb->local_ip; +        } +        break; +      case 2: /* udpLocalPort */ +        { +          s32_t *sint_ptr = value; +          *sint_ptr = pcb->local_port; +        } +        break; +    } +  } +} + +static void +snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) +{ +  /* return to object name, adding index depth (1) */ +  ident_len += 1; +  ident -= 1; +  if (ident_len == 2) +  { +    u8_t id; + +    od->id_inst_len = ident_len; +    od->id_inst_ptr = ident; + +    id = ident[0]; +    switch (id) +    { +      case 1: /* snmpInPkts */ +      case 2: /* snmpOutPkts */ +      case 3: /* snmpInBadVersions */ +      case 4: /* snmpInBadCommunityNames */ +      case 5: /* snmpInBadCommunityUses */ +      case 6: /* snmpInASNParseErrs */ +      case 8: /* snmpInTooBigs */ +      case 9: /* snmpInNoSuchNames */ +      case 10: /* snmpInBadValues */ +      case 11: /* snmpInReadOnlys */ +      case 12: /* snmpInGenErrs */ +      case 13: /* snmpInTotalReqVars */ +      case 14: /* snmpInTotalSetVars */ +      case 15: /* snmpInGetRequests */ +      case 16: /* snmpInGetNexts */ +      case 17: /* snmpInSetRequests */ +      case 18: /* snmpInGetResponses */ +      case 19: /* snmpInTraps */ +      case 20: /* snmpOutTooBigs */ +      case 21: /* snmpOutNoSuchNames */ +      case 22: /* snmpOutBadValues */ +      case 24: /* snmpOutGenErrs */ +      case 25: /* snmpOutGetRequests */ +      case 26: /* snmpOutGetNexts */ +      case 27: /* snmpOutSetRequests */ +      case 28: /* snmpOutGetResponses */ +      case 29: /* snmpOutTraps */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_ONLY; +        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); +        od->v_len = sizeof(u32_t); +        break; +      case 30: /* snmpEnableAuthenTraps */ +        od->instance = MIB_OBJECT_SCALAR; +        od->access = MIB_OBJECT_READ_WRITE; +        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); +        od->v_len = sizeof(s32_t); +        break; +      default: +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n")); +        od->instance = MIB_OBJECT_NONE; +        break; +    }; +  } +  else +  { +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n")); +    od->instance = MIB_OBJECT_NONE; +  } +} + +static void +snmp_get_value(struct obj_def *od, u16_t len, void *value) +{ +  u32_t *uint_ptr = value; +  u8_t id; + +  if (len){} +  id = od->id_inst_ptr[0]; +  switch (id) +  { +      case 1: /* snmpInPkts */ +        *uint_ptr = snmpinpkts; +        break; +      case 2: /* snmpOutPkts */ +        *uint_ptr = snmpoutpkts; +        break; +      case 3: /* snmpInBadVersions */ +        *uint_ptr = snmpinbadversions; +        break; +      case 4: /* snmpInBadCommunityNames */ +        *uint_ptr = snmpinbadcommunitynames; +        break; +      case 5: /* snmpInBadCommunityUses */ +        *uint_ptr = snmpinbadcommunityuses; +        break; +      case 6: /* snmpInASNParseErrs */ +        *uint_ptr = snmpinasnparseerrs; +        break; +      case 8: /* snmpInTooBigs */ +        *uint_ptr = snmpintoobigs; +        break; +      case 9: /* snmpInNoSuchNames */ +        *uint_ptr = snmpinnosuchnames; +        break; +      case 10: /* snmpInBadValues */ +        *uint_ptr = snmpinbadvalues; +        break; +      case 11: /* snmpInReadOnlys */ +        *uint_ptr = snmpinreadonlys; +        break; +      case 12: /* snmpInGenErrs */ +        *uint_ptr = snmpingenerrs; +        break; +      case 13: /* snmpInTotalReqVars */ +        *uint_ptr = snmpintotalreqvars; +        break; +      case 14: /* snmpInTotalSetVars */ +        *uint_ptr = snmpintotalsetvars; +        break; +      case 15: /* snmpInGetRequests */ +        *uint_ptr = snmpingetrequests; +        break; +      case 16: /* snmpInGetNexts */ +        *uint_ptr = snmpingetnexts; +        break; +      case 17: /* snmpInSetRequests */ +        *uint_ptr = snmpinsetrequests; +        break; +      case 18: /* snmpInGetResponses */ +        *uint_ptr = snmpingetresponses; +        break; +      case 19: /* snmpInTraps */ +        *uint_ptr = snmpintraps; +        break; +      case 20: /* snmpOutTooBigs */ +        *uint_ptr = snmpouttoobigs; +        break; +      case 21: /* snmpOutNoSuchNames */ +        *uint_ptr = snmpoutnosuchnames; +        break; +      case 22: /* snmpOutBadValues */ +        *uint_ptr = snmpoutbadvalues; +        break; +      case 24: /* snmpOutGenErrs */ +        *uint_ptr = snmpoutgenerrs; +        break; +      case 25: /* snmpOutGetRequests */ +        *uint_ptr = snmpoutgetrequests; +        break; +      case 26: /* snmpOutGetNexts */ +        *uint_ptr = snmpoutgetnexts; +        break; +      case 27: /* snmpOutSetRequests */ +        *uint_ptr = snmpoutsetrequests; +        break; +      case 28: /* snmpOutGetResponses */ +        *uint_ptr = snmpoutgetresponses; +        break; +      case 29: /* snmpOutTraps */ +        *uint_ptr = snmpouttraps; +        break; +      case 30: /* snmpEnableAuthenTraps */ +        *uint_ptr = *snmpenableauthentraps_ptr; +        break; +  }; +} + +/** + * Test snmp object value before setting. + * + * @param od is the object definition + * @param len return value space (in bytes) + * @param value points to (varbind) space to copy value from. + */ +static u8_t +snmp_set_test(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id, set_ok; + +  if (len) {} +  set_ok = 0; +  id = od->id_inst_ptr[0]; +  if (id == 30) +  { +    /* snmpEnableAuthenTraps */ +    s32_t *sint_ptr = value; + +    if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default) +    { +      /* we should have writable non-volatile mem here */ +      if ((*sint_ptr == 1) || (*sint_ptr == 2)) +      { +        set_ok = 1; +      } +    } +    else +    { +      /* const or hardwired value */ +      if (*sint_ptr == snmpenableauthentraps_default) +      { +        set_ok = 1; +      } +    } +  } +  return set_ok; +} + +static void +snmp_set_value(struct obj_def *od, u16_t len, void *value) +{ +  u8_t id; + +  if (len) {} +  id = od->id_inst_ptr[0]; +  if (id == 30) +  { +    /* snmpEnableAuthenTraps */ +    s32_t *sint_ptr = value; +    *snmpenableauthentraps_ptr = *sint_ptr; +  } +} + +#endif /* LWIP_SNMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/mib_structs.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/mib_structs.c new file mode 100644 index 000000000..af8994ed2 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/mib_structs.c @@ -0,0 +1,1183 @@ +/** + * @file + * MIB tree access/construction functions. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp_structs.h" +#include "lwip/mem.h" + +/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */ +const s32_t prefix[4] = {1, 3, 6, 1}; + +#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN) +/** node stack entry (old news?) */ +struct nse +{ +  /** right child */ +  struct mib_node* r_ptr; +  /** right child identifier */ +  s32_t r_id; +  /** right child next level */ +  u8_t r_nl; +}; +static u8_t node_stack_cnt; +static struct nse node_stack[NODE_STACK_SIZE]; + +/** + * Pushes nse struct onto stack. + */ +static void +push_node(struct nse* node) +{ +  LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE); +  LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id)); +  if (node_stack_cnt < NODE_STACK_SIZE) +  { +    node_stack[node_stack_cnt] = *node; +    node_stack_cnt++; +  } +} + +/** + * Pops nse struct from stack. + */ +static void +pop_node(struct nse* node) +{ +  if (node_stack_cnt > 0) +  { +    node_stack_cnt--; +    *node = node_stack[node_stack_cnt]; +  } +  LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id)); +} + +/** + * Conversion from ifIndex to lwIP netif + * @param ifindex is a s32_t object sub-identifier + * @param netif points to returned netif struct pointer + */ +void +snmp_ifindextonetif(s32_t ifindex, struct netif **netif) +{ +  struct netif *nif = netif_list; +  u16_t i, ifidx; + +  ifidx = ifindex - 1; +  i = 0; +  while ((nif != NULL) && (i < ifidx)) +  { +    nif = nif->next; +    i++; +  } +  *netif = nif; +} + +/** + * Conversion from lwIP netif to ifIndex + * @param netif points to a netif struct + * @param ifidx points to s32_t object sub-identifier + */ +void +snmp_netiftoifindex(struct netif *netif, s32_t *ifidx) +{ +  struct netif *nif = netif_list; +  u16_t i; + +  i = 0; +  while (nif != netif) +  { +    nif = nif->next; +    i++; +  } +  *ifidx = i+1; +} + +/** + * Conversion from oid to lwIP ip_addr + * @param ident points to s32_t ident[4] input + * @param ip points to output struct + */ +void +snmp_oidtoip(s32_t *ident, struct ip_addr *ip) +{ +  u32_t ipa; + +  ipa = ident[0]; +  ipa <<= 8; +  ipa |= ident[1]; +  ipa <<= 8; +  ipa |= ident[2]; +  ipa <<= 8; +  ipa |= ident[3]; +  ip->addr = ipa; +} + +/** + * Conversion from lwIP ip_addr to oid + * @param ip points to input struct + * @param ident points to s32_t ident[4] output + */ +void +snmp_iptooid(struct ip_addr *ip, s32_t *ident) +{ +  u32_t ipa; + +  ipa = ip->addr; +  ident[0] = (ipa >> 24) & 0xff; +  ident[1] = (ipa >> 16) & 0xff; +  ident[2] = (ipa >> 8) & 0xff; +  ident[3] = ipa & 0xff; +} + +struct mib_list_node * +snmp_mib_ln_alloc(s32_t id) +{ +  struct mib_list_node *ln; + +  ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node)); +  if (ln != NULL) +  { +    ln->prev = NULL; +    ln->next = NULL; +    ln->objid = id; +    ln->nptr = NULL; +  } +  return ln; +} + +void +snmp_mib_ln_free(struct mib_list_node *ln) +{ +  mem_free(ln); +} + +struct mib_list_rootnode * +snmp_mib_lrn_alloc(void) +{ +  struct mib_list_rootnode *lrn; + +  lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode)); +  if (lrn != NULL) +  { +    lrn->get_object_def = noleafs_get_object_def; +    lrn->get_value = noleafs_get_value; +    lrn->set_test = noleafs_set_test; +    lrn->set_value = noleafs_set_value; +    lrn->node_type = MIB_NODE_LR; +    lrn->maxlength = 0; +    lrn->head = NULL; +    lrn->tail = NULL; +    lrn->count = 0; +  } +  return lrn; +} + +void +snmp_mib_lrn_free(struct mib_list_rootnode *lrn) +{ +  mem_free(lrn); +} + +/** + * Inserts node in idx list in a sorted + * (ascending order) fashion and + * allocates the node if needed. + * + * @param rn points to the root node + * @param objid is the object sub identifier + * @param insn points to a pointer to the inserted node + *   used for constructing the tree. + * @return -1 if failed, 1 if inserted, 2 if present. + */ +s8_t +snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn) +{ +  struct mib_list_node *nn; +  s8_t insert; + +  LWIP_ASSERT("rn != NULL",rn != NULL); + +  /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */ +  insert = 0; +  if (rn->head == NULL) +  { +    /* empty list, add first node */ +    LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid)); +    nn = snmp_mib_ln_alloc(objid); +    if (nn != NULL) +    { +      rn->head = nn; +      rn->tail = nn; +      *insn = nn; +      insert = 1; +    } +    else +    { +      insert = -1; +    } +  } +  else +  { +    struct mib_list_node *n; +    /* at least one node is present */ +    n = rn->head; +    while ((n != NULL) && (insert == 0)) +    { +      if (n->objid == objid) +      { +        /* node is already there */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid)); +        *insn = n; +        insert = 2; +      } +      else if (n->objid < objid) +      { +        if (n->next == NULL) +        { +          /* alloc and insert at the tail */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid)); +          nn = snmp_mib_ln_alloc(objid); +          if (nn != NULL) +          { +            nn->next = NULL; +            nn->prev = n; +            n->next = nn; +            rn->tail = nn; +            *insn = nn; +            insert = 1; +          } +          else +          { +            /* insertion failure */ +            insert = -1; +          } +        } +        else +        { +          /* there's more to explore: traverse list */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n")); +          n = n->next; +        } +      } +      else +      { +        /* n->objid > objid */ +        /* alloc and insert between n->prev and n */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid)); +        nn = snmp_mib_ln_alloc(objid); +        if (nn != NULL) +        { +          if (n->prev == NULL) +          { +            /* insert at the head */ +            nn->next = n; +            nn->prev = NULL; +            rn->head = nn; +            n->prev = nn; +          } +          else +          { +            /* insert in the middle */ +            nn->next = n; +            nn->prev = n->prev; +            n->prev->next = nn; +            n->prev = nn; +          } +          *insn = nn; +          insert = 1; +        } +        else +        { +          /* insertion failure */ +          insert = -1; +        } +      } +    } +  } +  if (insert == 1) +  { +    rn->count += 1; +  } +  LWIP_ASSERT("insert != 0",insert != 0); +  return insert; +} + +/** + * Finds node in idx list and returns deletion mark. + * + * @param rn points to the root node + * @param objid  is the object sub identifier + * @param fn returns pointer to found node + * @return 0 if not found, 1 if deletable, + *   2 can't delete (2 or more children), 3 not a list_node + */ +s8_t +snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn) +{ +  s8_t fc; +  struct mib_list_node *n; + +  LWIP_ASSERT("rn != NULL",rn != NULL); +  n = rn->head; +  while ((n != NULL) && (n->objid != objid)) +  { +    n = n->next; +  } +  if (n == NULL) +  { +    fc = 0; +  } +  else if (n->nptr == NULL) +  { +    /* leaf, can delete node */ +    fc = 1; +  } +  else +  { +    struct mib_list_rootnode *r; + +    if (n->nptr->node_type == MIB_NODE_LR) +    { +      r = (struct mib_list_rootnode *)n->nptr; +      if (r->count > 1) +      { +        /* can't delete node */ +        fc = 2; +      } +      else +      { +        /* count <= 1, can delete node */ +        fc = 1; +      } +    } +    else +    { +      /* other node type */ +      fc = 3; +    } +  } +  *fn = n; +  return fc; +} + +/** + * Removes node from idx list + * if it has a single child left. + * + * @param rn points to the root node + * @param n points to the node to delete + * @return the nptr to be freed by caller + */ +struct mib_list_rootnode * +snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n) +{ +  struct mib_list_rootnode *next; + +  LWIP_ASSERT("rn != NULL",rn != NULL); +  LWIP_ASSERT("n != NULL",n != NULL); + +  /* caller must remove this sub-tree */ +  next = (struct mib_list_rootnode*)(n->nptr); +  rn->count -= 1; + +  if (n == rn->head) +  { +    rn->head = n->next; +    if (n->next != NULL) +    { +      /* not last node, new list begin */ +      n->next->prev = NULL; +    } +  } +  else if (n == rn->tail) +  { +    rn->tail = n->prev; +    if (n->prev != NULL) +    { +      /* not last node, new list end */ +      n->prev->next = NULL; +    } +  } +  else +  { +    /* node must be in the middle */ +    n->prev->next = n->next; +    n->next->prev = n->prev; +  } +  LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid)); +  snmp_mib_ln_free(n); +  if (rn->count == 0) +  { +    rn->head = NULL; +    rn->tail = NULL; +  } +  return next; +} + + + +/** + * Searches tree for the supplied (scalar?) object identifier. + * + * @param node points to the root of the tree ('.internet') + * @param ident_len the length of the supplied object identifier + * @param ident points to the array of sub identifiers + * @param np points to the found object instance (rerurn) + * @return pointer to the requested parent (!) node if success, NULL otherwise + */ +struct mib_node * +snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np) +{ +  u8_t node_type, ext_level; + +  ext_level = 0; +  LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident)); +  while (node != NULL) +  { +    node_type = node->node_type; +    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) +    { +      struct mib_array_node *an; +      u16_t i; + +      if (ident_len > 0) +      { +        /* array node (internal ROM or RAM, fixed length) */ +        an = (struct mib_array_node *)node; +        i = 0; +        while ((i < an->maxlength) && (an->objid[i] != *ident)) +        { +          i++; +        } +        if (i < an->maxlength) +        { +          /* found it, if available proceed to child, otherwise inspect leaf */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); +          if (an->nptr[i] == NULL) +          { +            /* a scalar leaf OR table, +               inspect remaining instance number / table index */ +            np->ident_len = ident_len; +            np->ident = ident; +            return (struct mib_node*)an; +          } +          else +          { +            /* follow next child pointer */ +            ident++; +            ident_len--; +            node = an->nptr[i]; +          } +        } +        else +        { +          /* search failed, identifier mismatch (nosuchname) */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident)); +          return NULL; +        } +      } +      else +      { +        /* search failed, short object identifier (nosuchname) */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n")); +        return NULL; +      } +    } +    else if(node_type == MIB_NODE_LR) +    { +      struct mib_list_rootnode *lrn; +      struct mib_list_node *ln; + +      if (ident_len > 0) +      { +        /* list root node (internal 'RAM', variable length) */ +        lrn = (struct mib_list_rootnode *)node; +        ln = lrn->head; +        /* iterate over list, head to tail */ +        while ((ln != NULL) && (ln->objid != *ident)) +        { +          ln = ln->next; +        } +        if (ln != NULL) +        { +          /* found it, proceed to child */; +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); +          if (ln->nptr == NULL) +          { +            np->ident_len = ident_len; +            np->ident = ident; +            return (struct mib_node*)lrn; +          } +          else +          { +            /* follow next child pointer */ +            ident_len--; +            ident++; +            node = ln->nptr; +          } +        } +        else +        { +          /* search failed */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident)); +          return NULL; +        } +      } +      else +      { +        /* search failed, short object identifier (nosuchname) */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n")); +        return NULL; +      } +    } +    else if(node_type == MIB_NODE_EX) +    { +      struct mib_external_node *en; +      u16_t i, len; + +      if (ident_len > 0) +      { +        /* external node (addressing and access via functions) */ +        en = (struct mib_external_node *)node; + +        i = 0; +        len = en->level_length(en->addr_inf,ext_level); +        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0)) +        { +          i++; +        } +        if (i < len) +        { +          s32_t debug_id; + +          en->get_objid(en->addr_inf,ext_level,i,&debug_id); +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident)); +          if ((ext_level + 1) == en->tree_levels) +          { +            np->ident_len = ident_len; +            np->ident = ident; +            return (struct mib_node*)en; +          } +          else +          { +            /* found it, proceed to child */ +            ident_len--; +            ident++; +            ext_level++; +          } +        } +        else +        { +          /* search failed */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident)); +          return NULL; +        } +      } +      else +      { +        /* search failed, short object identifier (nosuchname) */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n")); +        return NULL; +      } +    } +    else if (node_type == MIB_NODE_SC) +    { +      mib_scalar_node *sn; + +      sn = (mib_scalar_node *)node; +      if ((ident_len == 1) && (*ident == 0)) +      { +        np->ident_len = ident_len; +        np->ident = ident; +        return (struct mib_node*)sn; +      } +      else +      { +        /* search failed, short object identifier (nosuchname) */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n")); +        return NULL; +      } +    } +    else +    { +      /* unknown node_type */ +      LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type)); +      return NULL; +    } +  } +  /* done, found nothing */ +  LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node)); +  return NULL; +} + +/** + * Test table for presence of at least one table entry. + */ +static u8_t +empty_table(struct mib_node *node) +{ +  u8_t node_type; +  u8_t empty = 0; + +  if (node != NULL) +  { +    node_type = node->node_type; +    if (node_type == MIB_NODE_LR) +    { +      struct mib_list_rootnode *lrn; +      lrn = (struct mib_list_rootnode *)node; +      if ((lrn->count == 0) || (lrn->head == NULL)) +      { +        empty = 1; +      } +    } +    else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) +    { +      struct mib_array_node *an; +      an = (struct mib_array_node *)node; +      if ((an->maxlength == 0) || (an->nptr == NULL)) +      { +        empty = 1; +      } +    } +    else if (node_type == MIB_NODE_EX) +    { +      struct mib_external_node *en; +      en = (struct mib_external_node *)node; +      if (en->tree_levels == 0) +      { +        empty = 1; +      } +    } +  } +  return empty; +} + +/** + * Tree expansion. + */ +struct mib_node * +snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) +{ +  u8_t node_type, ext_level, climb_tree; + +  ext_level = 0; +  /* reset node stack */ +  node_stack_cnt = 0; +  while (node != NULL) +  { +    climb_tree = 0; +    node_type = node->node_type; +    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) +    { +      struct mib_array_node *an; +      u16_t i; + +      /* array node (internal ROM or RAM, fixed length) */ +      an = (struct mib_array_node *)node; +      if (ident_len > 0) +      { +        i = 0; +        while ((i < an->maxlength) && (an->objid[i] < *ident)) +        { +          i++; +        } +        if (i < an->maxlength) +        { +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); +          /* add identifier to oidret */ +          oidret->id[oidret->len] = an->objid[i]; +          (oidret->len)++; + +          if (an->nptr[i] == NULL) +          { +            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); +            /* leaf node (e.g. in a fixed size table) */ +            if (an->objid[i] > *ident) +            { +              return (struct mib_node*)an; +            } +            else if ((i + 1) < an->maxlength) +            { +              /* an->objid[i] == *ident */ +              (oidret->len)--; +              oidret->id[oidret->len] = an->objid[i + 1]; +              (oidret->len)++; +              return (struct mib_node*)an; +            } +            else +            { +              /* (i + 1) == an->maxlength */ +              (oidret->len)--; +              climb_tree = 1; +            } +          } +          else +          { +            u8_t j; +            struct nse cur_node; + +            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); +            /* non-leaf, store right child ptr and id */ +            j = i + 1; +            while ((j < an->maxlength) && (empty_table(an->nptr[j]))) +            { +              j++; +            } +            if (j < an->maxlength) +            { +              cur_node.r_ptr = an->nptr[j]; +              cur_node.r_id = an->objid[j]; +              cur_node.r_nl = 0; +            } +            else +            { +              cur_node.r_ptr = NULL; +            } +            push_node(&cur_node); +            if (an->objid[i] == *ident) +            { +              ident_len--; +              ident++; +            } +            else +            { +              /* an->objid[i] < *ident */ +              ident_len = 0; +            } +            /* follow next child pointer */ +            node = an->nptr[i]; +          } +        } +        else +        { +          /* i == an->maxlength */ +          climb_tree = 1; +        } +      } +      else +      { +        u8_t j; +        /* ident_len == 0, complete with leftmost '.thing' */ +        j = 0; +        while ((j < an->maxlength) && empty_table(an->nptr[j])) +        { +          j++; +        } +        if (j < an->maxlength) +        { +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j])); +          oidret->id[oidret->len] = an->objid[j]; +          (oidret->len)++; +          if (an->nptr[j] == NULL) +          { +            /* leaf node */ +            return (struct mib_node*)an; +          } +          else +          { +            /* no leaf, continue */ +            node = an->nptr[j]; +          } +        } +        else +        { +          /* j == an->maxlength */ +          climb_tree = 1; +        } +      } +    } +    else if(node_type == MIB_NODE_LR) +    { +      struct mib_list_rootnode *lrn; +      struct mib_list_node *ln; + +      /* list root node (internal 'RAM', variable length) */ +      lrn = (struct mib_list_rootnode *)node; +      if (ident_len > 0) +      { +        ln = lrn->head; +        /* iterate over list, head to tail */ +        while ((ln != NULL) && (ln->objid < *ident)) +        { +          ln = ln->next; +        } +        if (ln != NULL) +        { +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); +          oidret->id[oidret->len] = ln->objid; +          (oidret->len)++; +          if (ln->nptr == NULL) +          { +            /* leaf node */ +            if (ln->objid > *ident) +            { +              return (struct mib_node*)lrn; +            } +            else if (ln->next != NULL) +            { +              /* ln->objid == *ident */ +              (oidret->len)--; +              oidret->id[oidret->len] = ln->next->objid; +              (oidret->len)++; +              return (struct mib_node*)lrn; +            } +            else +            { +              /* ln->next == NULL */ +              (oidret->len)--; +              climb_tree = 1; +            } +          } +          else +          { +            struct mib_list_node *jn; +            struct nse cur_node; + +            /* non-leaf, store right child ptr and id */ +            jn = ln->next; +            while ((jn != NULL) && empty_table(jn->nptr)) +            { +              jn = jn->next; +            } +            if (jn != NULL) +            { +              cur_node.r_ptr = jn->nptr; +              cur_node.r_id = jn->objid; +              cur_node.r_nl = 0; +            } +            else +            { +              cur_node.r_ptr = NULL; +            } +            push_node(&cur_node); +            if (ln->objid == *ident) +            { +              ident_len--; +              ident++; +            } +            else +            { +              /* ln->objid < *ident */ +              ident_len = 0; +            } +            /* follow next child pointer */ +            node = ln->nptr; +          } + +        } +        else +        { +          /* ln == NULL */ +          climb_tree = 1; +        } +      } +      else +      { +        struct mib_list_node *jn; +        /* ident_len == 0, complete with leftmost '.thing' */ +        jn = lrn->head; +        while ((jn != NULL) && empty_table(jn->nptr)) +        { +          jn = jn->next; +        } +        if (jn != NULL) +        { +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid)); +          oidret->id[oidret->len] = jn->objid; +          (oidret->len)++; +          if (jn->nptr == NULL) +          { +            /* leaf node */ +            LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n")); +            return (struct mib_node*)lrn; +          } +          else +          { +            /* no leaf, continue */ +            node = jn->nptr; +          } +        } +        else +        { +          /* jn == NULL */ +          climb_tree = 1; +        } +      } +    } +    else if(node_type == MIB_NODE_EX) +    { +      struct mib_external_node *en; +      s32_t ex_id; + +      /* external node (addressing and access via functions) */ +      en = (struct mib_external_node *)node; +      if (ident_len > 0) +      { +        u16_t i, len; + +        i = 0; +        len = en->level_length(en->addr_inf,ext_level); +        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0)) +        { +          i++; +        } +        if (i < len) +        { +          /* add identifier to oidret */ +          en->get_objid(en->addr_inf,ext_level,i,&ex_id); +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident)); +          oidret->id[oidret->len] = ex_id; +          (oidret->len)++; + +          if ((ext_level + 1) == en->tree_levels) +          { +            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); +            /* leaf node */ +            if (ex_id > *ident) +            { +              return (struct mib_node*)en; +            } +            else if ((i + 1) < len) +            { +              /* ex_id == *ident */ +              en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id); +              (oidret->len)--; +              oidret->id[oidret->len] = ex_id; +              (oidret->len)++; +              return (struct mib_node*)en; +            } +            else +            { +              /* (i + 1) == len */ +              (oidret->len)--; +              climb_tree = 1; +            } +          } +          else +          { +            u8_t j; +            struct nse cur_node; + +            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); +            /* non-leaf, store right child ptr and id */ +            j = i + 1; +            if (j < len) +            { +              /* right node is the current external node */ +              cur_node.r_ptr = node; +              en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id); +              cur_node.r_nl = ext_level + 1; +            } +            else +            { +              cur_node.r_ptr = NULL; +            } +            push_node(&cur_node); +            if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0) +            { +              ident_len--; +              ident++; +            } +            else +            { +              /* external id < *ident */ +              ident_len = 0; +            } +            /* proceed to child */ +            ext_level++; +          } +        } +        else +        { +          /* i == len (en->level_len()) */ +          climb_tree = 1; +        } +      } +      else +      { +        /* ident_len == 0, complete with leftmost '.thing' */ +        en->get_objid(en->addr_inf,ext_level,0,&ex_id); +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id)); +        oidret->id[oidret->len] = ex_id; +        (oidret->len)++; +        if ((ext_level + 1) == en->tree_levels) +        { +          /* leaf node */ +          LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n")); +          return (struct mib_node*)en; +        } +        else +        { +          /* no leaf, proceed to child */ +          ext_level++; +        } +      } +    } +    else if(node_type == MIB_NODE_SC) +    { +      mib_scalar_node *sn; + +      /* scalar node  */ +      sn = (mib_scalar_node *)node; +      if (ident_len > 0) +      { +        /* at .0 */ +        climb_tree = 1; +      } +      else +      { +        /* ident_len == 0, complete object identifier */ +        oidret->id[oidret->len] = 0; +        (oidret->len)++; +        /* leaf node */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n")); +        return (struct mib_node*)sn; +      } +    } +    else +    { +      /* unknown/unhandled node_type */ +      LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type)); +      return NULL; +    } + +    if (climb_tree) +    { +      struct nse child; + +      /* find right child ptr */ +      child.r_ptr = NULL; +      child.r_id = 0; +      child.r_nl = 0; +      while ((node_stack_cnt > 0) && (child.r_ptr == NULL)) +      { +        pop_node(&child); +        /* trim returned oid */ +        (oidret->len)--; +      } +      if (child.r_ptr != NULL) +      { +        /* incoming ident is useless beyond this point */ +        ident_len = 0; +        oidret->id[oidret->len] = child.r_id; +        oidret->len++; +        node = child.r_ptr; +        ext_level = child.r_nl; +      } +      else +      { +        /* tree ends here ... */ +        LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n")); +        return NULL; +      } +    } +  } +  /* done, found nothing */ +  LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node)); +  return NULL; +} + +/** + * Test object identifier for the iso.org.dod.internet prefix. + * + * @param ident_len the length of the supplied object identifier + * @param ident points to the array of sub identifiers + * @return 1 if it matches, 0 otherwise + */ +u8_t +snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident) +{ +  if ((ident_len > 3) && +      (ident[0] == 1) && (ident[1] == 3) && +      (ident[2] == 6) && (ident[3] == 1)) +  { +    return 1; +  } +  else +  { +    return 0; +  } +} + +/** + * Expands object identifier to the iso.org.dod.internet + * prefix for use in getnext operation. + * + * @param ident_len the length of the supplied object identifier + * @param ident points to the array of sub identifiers + * @param oidret points to returned expanded object identifier + * @return 1 if it matches, 0 otherwise + * + * @note ident_len 0 is allowed, expanding to the first known object id!! + */ +u8_t +snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) +{ +  const s32_t *prefix_ptr; +  s32_t *ret_ptr; +  u8_t i; + +  i = 0; +  prefix_ptr = &prefix[0]; +  ret_ptr = &oidret->id[0]; +  ident_len = ((ident_len < 4)?ident_len:4); +  while ((i < ident_len) && ((*ident) <= (*prefix_ptr))) +  { +    *ret_ptr++ = *prefix_ptr++; +    ident++; +    i++; +  } +  if (i == ident_len) +  { +    /* match, complete missing bits */ +    while (i < 4) +    { +      *ret_ptr++ = *prefix_ptr++; +      i++; +    } +    oidret->len = i; +    return 1; +  } +  else +  { +    /* i != ident_len */ +    return 0; +  } +} + +#endif /* LWIP_SNMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/msg_in.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/msg_in.c new file mode 100644 index 000000000..d0c3c7534 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/msg_in.c @@ -0,0 +1,1454 @@ +/** + * @file + * SNMP input message processing (RFC1157). + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip_addr.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_msg.h" +#include "lwip/snmp_structs.h" + +#include <string.h> + +/* public (non-static) constants */ +/** SNMP v1 == 0 */ +const s32_t snmp_version = 0; +/** default SNMP community string */ +const char snmp_publiccommunity[7] = "public"; + +/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */ +struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS]; +/* UDP Protocol Control Block */ +struct udp_pcb *snmp1_pcb; + +static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); +static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); +static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); + + +/** + * Starts SNMP Agent. + * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161. + */ +void +snmp_init(void) +{ +  struct snmp_msg_pstat *msg_ps; +  u8_t i; + +  snmp1_pcb = udp_new(); +  if (snmp1_pcb != NULL) +  { +    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT); +    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT); +  } +  msg_ps = &msg_input_list[0]; +  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++) +  { +    msg_ps->state = SNMP_MSG_EMPTY; +    msg_ps->error_index = 0; +    msg_ps->error_status = SNMP_ES_NOERROR; +    msg_ps++; +  } +  trap_msg.pcb = snmp1_pcb; +  /* The coldstart trap will only be output +     if our outgoing interface is up & configured  */ +  snmp_coldstart_trap(); +} + +static void +snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error) +{ +  snmp_varbind_list_free(&msg_ps->outvb); +  msg_ps->outvb = msg_ps->invb; +  msg_ps->invb.head = NULL; +  msg_ps->invb.tail = NULL; +  msg_ps->invb.count = 0; +  msg_ps->error_status = error; +  msg_ps->error_index = 1 + msg_ps->vb_idx; +  snmp_send_response(msg_ps); +  snmp_varbind_list_free(&msg_ps->outvb); +  msg_ps->state = SNMP_MSG_EMPTY; +} + +static void +snmp_ok_response(struct snmp_msg_pstat *msg_ps) +{ +  err_t err_ret; + +  err_ret = snmp_send_response(msg_ps); +  if (err_ret == ERR_MEM) +  { +    /* serious memory problem, can't return tooBig */ +  } +  else +  { +    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status)); +  } +  /* free varbinds (if available) */ +  snmp_varbind_list_free(&msg_ps->invb); +  snmp_varbind_list_free(&msg_ps->outvb); +  msg_ps->state = SNMP_MSG_EMPTY; +} + +/** + * Service an internal or external event for SNMP GET. + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + * @param msg_ps points to the assosicated message process state + */ +static void +snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) +{ +  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); + +  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) +  { +    struct mib_external_node *en; +    struct snmp_name_ptr np; + +    /* get_object_def() answer*/ +    en = msg_ps->ext_mib_node; +    np = msg_ps->ext_name_ptr; + +    /* translate answer into a known lifeform */ +    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); +    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) +    { +      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; +      en->get_value_q(request_id, &msg_ps->ext_object_def); +    } +    else +    { +      en->get_object_def_pc(request_id, np.ident_len, np.ident); +      /* search failed, object id points to unknown object (nosuchname) */ +      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +    } +  } +  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) +  { +    struct mib_external_node *en; +    struct snmp_varbind *vb; + +    /* get_value() answer */ +    en = msg_ps->ext_mib_node; + +    /* allocate output varbind */ +    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); +    LWIP_ASSERT("vb != NULL",vb != NULL); +    if (vb != NULL) +    { +      vb->next = NULL; +      vb->prev = NULL; + +      /* move name from invb to outvb */ +      vb->ident = msg_ps->vb_ptr->ident; +      vb->ident_len = msg_ps->vb_ptr->ident_len; +      /* ensure this memory is refereced once only */ +      msg_ps->vb_ptr->ident = NULL; +      msg_ps->vb_ptr->ident_len = 0; + +      vb->value_type = msg_ps->ext_object_def.asn_type; +      vb->value_len =  msg_ps->ext_object_def.v_len; +      if (vb->value_len > 0) +      { +        vb->value = mem_malloc(vb->value_len); +        LWIP_ASSERT("vb->value != NULL",vb->value != NULL); +        if (vb->value != NULL) +        { +          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); +          snmp_varbind_tail_add(&msg_ps->outvb, vb); +          /* search again (if vb_idx < msg_ps->invb.count) */ +          msg_ps->state = SNMP_MSG_SEARCH_OBJ; +          msg_ps->vb_idx += 1; +        } +        else +        { +          en->get_value_pc(request_id, &msg_ps->ext_object_def); +          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n")); +          msg_ps->vb_ptr->ident = vb->ident; +          msg_ps->vb_ptr->ident_len = vb->ident_len; +          mem_free(vb); +          snmp_error_response(msg_ps,SNMP_ES_TOOBIG); +        } +      } +      else +      { +        /* vb->value_len == 0, empty value (e.g. empty string) */ +        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL); +        vb->value = NULL; +        snmp_varbind_tail_add(&msg_ps->outvb, vb); +        /* search again (if vb_idx < msg_ps->invb.count) */ +        msg_ps->state = SNMP_MSG_SEARCH_OBJ; +        msg_ps->vb_idx += 1; +      } +    } +    else +    { +      en->get_value_pc(request_id, &msg_ps->ext_object_def); +      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n")); +      snmp_error_response(msg_ps,SNMP_ES_TOOBIG); +    } +  } + +  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && +         (msg_ps->vb_idx < msg_ps->invb.count)) +  { +    struct mib_node *mn; +    struct snmp_name_ptr np; + +    if (msg_ps->vb_idx == 0) +    { +      msg_ps->vb_ptr = msg_ps->invb.head; +    } +    else +    { +      msg_ps->vb_ptr = msg_ps->vb_ptr->next; +    } +    /** test object identifier for .iso.org.dod.internet prefix */ +    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident)) +    { +      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, +                             msg_ps->vb_ptr->ident + 4, &np); +      if (mn != NULL) +      { +        if (mn->node_type == MIB_NODE_EX) +        { +          /* external object */ +          struct mib_external_node *en = (struct mib_external_node*)mn; + +          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; +          /* save en && args in msg_ps!! */ +          msg_ps->ext_mib_node = en; +          msg_ps->ext_name_ptr = np; + +          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); +        } +        else +        { +          /* internal object */ +          struct obj_def object_def; + +          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; +          mn->get_object_def(np.ident_len, np.ident, &object_def); +          if (object_def.instance != MIB_OBJECT_NONE) +          { +            mn = mn; +          } +          else +          { +            /* search failed, object id points to unknown object (nosuchname) */ +            mn =  NULL; +          } +          if (mn != NULL) +          { +            struct snmp_varbind *vb; + +            msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; +            /* allocate output varbind */ +            vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); +            LWIP_ASSERT("vb != NULL",vb != NULL); +            if (vb != NULL) +            { +              vb->next = NULL; +              vb->prev = NULL; + +              /* move name from invb to outvb */ +              vb->ident = msg_ps->vb_ptr->ident; +              vb->ident_len = msg_ps->vb_ptr->ident_len; +              /* ensure this memory is refereced once only */ +              msg_ps->vb_ptr->ident = NULL; +              msg_ps->vb_ptr->ident_len = 0; + +              vb->value_type = object_def.asn_type; +              vb->value_len = object_def.v_len; +              if (vb->value_len > 0) +              { +                vb->value = mem_malloc(vb->value_len); +                LWIP_ASSERT("vb->value != NULL",vb->value != NULL); +                if (vb->value != NULL) +                { +                  mn->get_value(&object_def, vb->value_len, vb->value); +                  snmp_varbind_tail_add(&msg_ps->outvb, vb); +                  msg_ps->state = SNMP_MSG_SEARCH_OBJ; +                  msg_ps->vb_idx += 1; +                } +                else +                { +                  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n")); +                  msg_ps->vb_ptr->ident = vb->ident; +                  msg_ps->vb_ptr->ident_len = vb->ident_len; +                  mem_free(vb); +                  snmp_error_response(msg_ps,SNMP_ES_TOOBIG); +                } +              } +              else +              { +                /* vb->value_len == 0, empty value (e.g. empty string) */ +                vb->value = NULL; +                snmp_varbind_tail_add(&msg_ps->outvb, vb); +                msg_ps->state = SNMP_MSG_SEARCH_OBJ; +                msg_ps->vb_idx += 1; +              } +            } +            else +            { +              LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n")); +              snmp_error_response(msg_ps,SNMP_ES_TOOBIG); +            } +          } +        } +      } +    } +    else +    { +      mn = NULL; +    } +    if (mn == NULL) +    { +      /* mn == NULL, noSuchName */ +      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +    } +  } +  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && +      (msg_ps->vb_idx == msg_ps->invb.count)) +  { +    snmp_ok_response(msg_ps); +  } +} + +/** + * Service an internal or external event for SNMP GETNEXT. + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + * @param msg_ps points to the assosicated message process state + */ +static void +snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) +{ +  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); + +  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) +  { +    struct mib_external_node *en; + +    /* get_object_def() answer*/ +    en = msg_ps->ext_mib_node; + +    /* translate answer into a known lifeform */ +    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def); +    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) +    { +      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; +      en->get_value_q(request_id, &msg_ps->ext_object_def); +    } +    else +    { +      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]); +      /* search failed, object id points to unknown object (nosuchname) */ +      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +    } +  } +  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) +  { +    struct mib_external_node *en; +    struct snmp_varbind *vb; + +    /* get_value() answer */ +    en = msg_ps->ext_mib_node; + +    vb = snmp_varbind_alloc(&msg_ps->ext_oid, +                            msg_ps->ext_object_def.asn_type, +                            msg_ps->ext_object_def.v_len); +    if (vb != NULL) +    { +      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); +      snmp_varbind_tail_add(&msg_ps->outvb, vb); +      msg_ps->state = SNMP_MSG_SEARCH_OBJ; +      msg_ps->vb_idx += 1; +    } +    else +    { +      en->get_value_pc(request_id, &msg_ps->ext_object_def); +      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n")); +      snmp_error_response(msg_ps,SNMP_ES_TOOBIG); +    } +  } + +  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && +         (msg_ps->vb_idx < msg_ps->invb.count)) +  { +    struct mib_node *mn; +    struct snmp_obj_id oid; + +    if (msg_ps->vb_idx == 0) +    { +      msg_ps->vb_ptr = msg_ps->invb.head; +    } +    else +    { +      msg_ps->vb_ptr = msg_ps->vb_ptr->next; +    } +    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid)) +    { +      if (msg_ps->vb_ptr->ident_len > 3) +      { +        /* can offset ident_len and ident */ +        mn = snmp_expand_tree((struct mib_node*)&internet, +                              msg_ps->vb_ptr->ident_len - 4, +                              msg_ps->vb_ptr->ident + 4, &oid); +      } +      else +      { +        /* can't offset ident_len -4, ident + 4 */ +        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid); +      } +    } +    else +    { +      mn = NULL; +    } +    if (mn != NULL) +    { +      if (mn->node_type == MIB_NODE_EX) +      { +        /* external object */ +        struct mib_external_node *en = (struct mib_external_node*)mn; + +        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; +        /* save en && args in msg_ps!! */ +        msg_ps->ext_mib_node = en; +        msg_ps->ext_oid = oid; + +        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]); +      } +      else +      { +        /* internal object */ +        struct obj_def object_def; +        struct snmp_varbind *vb; + +        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; +        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def); + +        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len); +        if (vb != NULL) +        { +          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; +          mn->get_value(&object_def, object_def.v_len, vb->value); +          snmp_varbind_tail_add(&msg_ps->outvb, vb); +          msg_ps->state = SNMP_MSG_SEARCH_OBJ; +          msg_ps->vb_idx += 1; +        } +        else +        { +          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n")); +          snmp_error_response(msg_ps,SNMP_ES_TOOBIG); +        } +      } +    } +    if (mn == NULL) +    { +      /* mn == NULL, noSuchName */ +      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +    } +  } +  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && +      (msg_ps->vb_idx == msg_ps->invb.count)) +  { +    snmp_ok_response(msg_ps); +  } +} + +/** + * Service an internal or external event for SNMP SET. + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + * @param msg_ps points to the assosicated message process state + */ +static void +snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) +{ +  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); + +  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) +  { +    struct mib_external_node *en; +    struct snmp_name_ptr np; + +    /* get_object_def() answer*/ +    en = msg_ps->ext_mib_node; +    np = msg_ps->ext_name_ptr; + +    /* translate answer into a known lifeform */ +    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); +    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) +    { +      msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST; +      en->set_test_q(request_id, &msg_ps->ext_object_def); +    } +    else +    { +      en->get_object_def_pc(request_id, np.ident_len, np.ident); +      /* search failed, object id points to unknown object (nosuchname) */ +      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +    } +  } +  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST) +  { +    struct mib_external_node *en; + +    /* set_test() answer*/ +    en = msg_ps->ext_mib_node; + +    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE) +    { +       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) && +           (en->set_test_a(request_id,&msg_ps->ext_object_def, +                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) +      { +        msg_ps->state = SNMP_MSG_SEARCH_OBJ; +        msg_ps->vb_idx += 1; +      } +      else +      { +        en->set_test_pc(request_id,&msg_ps->ext_object_def); +        /* bad value */ +        snmp_error_response(msg_ps,SNMP_ES_BADVALUE); +      } +    } +    else +    { +      en->set_test_pc(request_id,&msg_ps->ext_object_def); +      /* object not available for set */ +      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +    } +  } +  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S) +  { +    struct mib_external_node *en; +    struct snmp_name_ptr np; + +    /* get_object_def() answer*/ +    en = msg_ps->ext_mib_node; +    np = msg_ps->ext_name_ptr; + +    /* translate answer into a known lifeform */ +    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); +    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) +    { +      msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE; +      en->set_value_q(request_id, &msg_ps->ext_object_def, +                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); +    } +    else +    { +      en->get_object_def_pc(request_id, np.ident_len, np.ident); +      /* set_value failed, object has disappeared for some odd reason?? */ +      snmp_error_response(msg_ps,SNMP_ES_GENERROR); +    } +  } +  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE) +  { +    struct mib_external_node *en; + +    /** set_value_a() */ +    en = msg_ps->ext_mib_node; +    en->set_value_a(request_id, &msg_ps->ext_object_def, +      msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value); + +    /** @todo use set_value_pc() if toobig */ +    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; +    msg_ps->vb_idx += 1; +  } + +  /* test all values before setting */ +  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && +         (msg_ps->vb_idx < msg_ps->invb.count)) +  { +    struct mib_node *mn; +    struct snmp_name_ptr np; + +    if (msg_ps->vb_idx == 0) +    { +      msg_ps->vb_ptr = msg_ps->invb.head; +    } +    else +    { +      msg_ps->vb_ptr = msg_ps->vb_ptr->next; +    } +    /** test object identifier for .iso.org.dod.internet prefix */ +    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident)) +    { +      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, +                             msg_ps->vb_ptr->ident + 4, &np); +      if (mn != NULL) +      { +        if (mn->node_type == MIB_NODE_EX) +        { +          /* external object */ +          struct mib_external_node *en = (struct mib_external_node*)mn; + +          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; +          /* save en && args in msg_ps!! */ +          msg_ps->ext_mib_node = en; +          msg_ps->ext_name_ptr = np; + +          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); +        } +        else +        { +          /* internal object */ +          struct obj_def object_def; + +          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; +          mn->get_object_def(np.ident_len, np.ident, &object_def); +          if (object_def.instance != MIB_OBJECT_NONE) +          { +            mn = mn; +          } +          else +          { +            /* search failed, object id points to unknown object (nosuchname) */ +            mn = NULL; +          } +          if (mn != NULL) +          { +            msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST; + +            if (object_def.access == MIB_OBJECT_READ_WRITE) +            { +              if ((object_def.asn_type == msg_ps->vb_ptr->value_type) && +                  (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) +              { +                msg_ps->state = SNMP_MSG_SEARCH_OBJ; +                msg_ps->vb_idx += 1; +              } +              else +              { +                /* bad value */ +                snmp_error_response(msg_ps,SNMP_ES_BADVALUE); +              } +            } +            else +            { +              /* object not available for set */ +              snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +            } +          } +        } +      } +    } +    else +    { +      mn = NULL; +    } +    if (mn == NULL) +    { +      /* mn == NULL, noSuchName */ +      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); +    } +  } + +  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && +      (msg_ps->vb_idx == msg_ps->invb.count)) +  { +    msg_ps->vb_idx = 0; +    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; +  } + +  /* set all values "atomically" (be as "atomic" as possible) */ +  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && +         (msg_ps->vb_idx < msg_ps->invb.count)) +  { +    struct mib_node *mn; +    struct snmp_name_ptr np; + +    if (msg_ps->vb_idx == 0) +    { +      msg_ps->vb_ptr = msg_ps->invb.head; +    } +    else +    { +      msg_ps->vb_ptr = msg_ps->vb_ptr->next; +    } +    /* skip iso prefix test, was done previously while settesting() */ +    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, +                           msg_ps->vb_ptr->ident + 4, &np); +    /* check if object is still available +       (e.g. external hot-plug thingy present?) */ +    if (mn != NULL) +    { +      if (mn->node_type == MIB_NODE_EX) +      { +        /* external object */ +        struct mib_external_node *en = (struct mib_external_node*)mn; + +        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S; +        /* save en && args in msg_ps!! */ +        msg_ps->ext_mib_node = en; +        msg_ps->ext_name_ptr = np; + +        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); +      } +      else +      { +        /* internal object */ +        struct obj_def object_def; + +        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S; +        mn->get_object_def(np.ident_len, np.ident, &object_def); +        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; +        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); +        msg_ps->vb_idx += 1; +      } +    } +  } +  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && +      (msg_ps->vb_idx == msg_ps->invb.count)) +  { +    /* simply echo the input if we can set it +       @todo do we need to return the actual value? +       e.g. if value is silently modified or behaves sticky? */ +    msg_ps->outvb = msg_ps->invb; +    msg_ps->invb.head = NULL; +    msg_ps->invb.tail = NULL; +    msg_ps->invb.count = 0; +    snmp_ok_response(msg_ps); +  } +} + + +/** + * Handle one internal or external event. + * Called for one async event. (recv external/private answer) + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + */ +void +snmp_msg_event(u8_t request_id) +{ +  struct snmp_msg_pstat *msg_ps; + +  if (request_id < SNMP_CONCURRENT_REQUESTS) +  { +    msg_ps = &msg_input_list[request_id]; +    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) +    { +      snmp_msg_getnext_event(request_id, msg_ps); +    } +    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) +    { +      snmp_msg_get_event(request_id, msg_ps); +    } +    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ) +    { +      snmp_msg_set_event(request_id, msg_ps); +    } +  } +} + + +/* lwIP UDP receive callback function */ +static void +snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +{ +  struct udp_hdr *udphdr; + +  /* suppress unused argument warning */ +  LWIP_UNUSED_ARG(arg); +  /* peek in the UDP header (goto IP payload) */ +  if(pbuf_header(p, UDP_HLEN)){ +    LWIP_ASSERT("Can't move to UDP header", 0); +    pbuf_free(p); +    return; +  } +  udphdr = p->payload; + +  /* check if datagram is really directed at us (including broadcast requests) */ +  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT)) +  { +    struct snmp_msg_pstat *msg_ps; +    u8_t req_idx; + +    /* traverse input message process list, look for SNMP_MSG_EMPTY */ +    msg_ps = &msg_input_list[0]; +    req_idx = 0; +    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) +    { +      req_idx++; +      msg_ps++; +    } +    if (req_idx != SNMP_CONCURRENT_REQUESTS) +    { +      err_t err_ret; +      u16_t payload_len; +      u16_t payload_ofs; +      u16_t varbind_ofs = 0; + +      /* accepting request */ +      snmp_inc_snmpinpkts(); +      /* record used 'protocol control block' */ +      msg_ps->pcb = pcb; +      /* source address (network order) */ +      msg_ps->sip = *addr; +      /* source port (host order (lwIP oddity)) */ +      msg_ps->sp = port; +      /* read UDP payload length from UDP header */ +      payload_len = ntohs(udphdr->len) - UDP_HLEN; + +      /* adjust to UDP payload */ +      payload_ofs = UDP_HLEN; + +      /* check total length, version, community, pdu type */ +      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); +      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) || +           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) || +           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) && +          ((msg_ps->error_status == SNMP_ES_NOERROR) && +           (msg_ps->error_index == 0)) ) +      { +        /* Only accept requests and requests without error (be robust) */ +        err_ret = err_ret; +      } +      else +      { +        /* Reject response and trap headers or error requests as input! */ +        err_ret = ERR_ARG; +      } +      if (err_ret == ERR_OK) +      { +        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); + +        /* Builds a list of variable bindings. Copy the varbinds from the pbuf +          chain to glue them when these are divided over two or more pbuf's. */ +        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); +        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0)) +        { +          /* we've decoded the incoming message, release input msg now */ +          pbuf_free(p); + +          msg_ps->error_status = SNMP_ES_NOERROR; +          msg_ps->error_index = 0; +          /* find object for each variable binding */ +          msg_ps->state = SNMP_MSG_SEARCH_OBJ; +          /* first variable binding from list to inspect */ +          msg_ps->vb_idx = 0; + +          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); + +          /* handle input event and as much objects as possible in one go */ +          snmp_msg_event(req_idx); +        } +        else +        { +          /* varbind-list decode failed, or varbind list empty. +             drop request silently, do not return error! +             (errors are only returned for a specific varbind failure) */ +          pbuf_free(p); +          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); +        } +      } +      else +      { +        /* header check failed +           drop request silently, do not return error! */ +        pbuf_free(p); +        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); +      } +    } +    else +    { +      /* exceeding number of concurrent requests */ +      pbuf_free(p); +    } +  } +  else +  { +    /* datagram not for us */ +    pbuf_free(p); +  } +} + +/** + * Checks and decodes incoming SNMP message header, logs header errors. + * + * @param p points to pbuf chain of SNMP message (UDP payload) + * @param ofs points to first octet of SNMP message + * @param pdu_len the length of the UDP payload + * @param ofs_ret returns the ofset of the variable bindings + * @param m_stat points to the current message request state return + * @return + * - ERR_OK SNMP header is sane and accepted + * - ERR_ARG SNMP header is either malformed or rejected + */ +static err_t +snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) +{ +  err_t derr; +  u16_t len, ofs_base; +  u8_t  len_octets; +  u8_t  type; +  s32_t version; + +  ofs_base = ofs; +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +  if ((derr != ERR_OK) || +      (pdu_len != (1 + len_octets + len)) || +      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) +  { +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  ofs += (1 + len_octets); +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) +  { +    /* can't decode or no integer (version) */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version); +  if (derr != ERR_OK) +  { +    /* can't decode */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  if (version != 0) +  { +    /* not version 1 */ +    snmp_inc_snmpinbadversions(); +    return ERR_ARG; +  } +  ofs += (1 + len_octets + len); +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR))) +  { +    /* can't decode or no octet string (community) */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community); +  if (derr != ERR_OK) +  { +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  /* add zero terminator */ +  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN)); +  m_stat->community[len] = 0; +  m_stat->com_strlen = len; +  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0) +  { +    /** @todo: move this if we need to check more names */ +    snmp_inc_snmpinbadcommunitynames(); +    snmp_authfail_trap(); +    return ERR_ARG; +  } +  ofs += (1 + len_octets + len); +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +  if (derr != ERR_OK) +  { +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  switch(type) +  { +    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ): +      /* GetRequest PDU */ +      snmp_inc_snmpingetrequests(); +      derr = ERR_OK; +      break; +    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ): +      /* GetNextRequest PDU */ +      snmp_inc_snmpingetnexts(); +      derr = ERR_OK; +      break; +    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP): +      /* GetResponse PDU */ +      snmp_inc_snmpingetresponses(); +      derr = ERR_ARG; +      break; +    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ): +      /* SetRequest PDU */ +      snmp_inc_snmpinsetrequests(); +      derr = ERR_OK; +      break; +    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP): +      /* Trap PDU */ +      snmp_inc_snmpintraps(); +      derr = ERR_ARG; +      break; +    default: +      snmp_inc_snmpinasnparseerrs(); +      derr = ERR_ARG; +      break; +  } +  if (derr != ERR_OK) +  { +    /* unsupported input PDU for this agent (no parse error) */ +    return ERR_ARG; +  } +  m_stat->rt = type & 0x1F; +  ofs += (1 + len_octets); +  if (len != (pdu_len - (ofs - ofs_base))) +  { +    /* decoded PDU length does not equal actual payload length */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) +  { +    /* can't decode or no integer (request ID) */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid); +  if (derr != ERR_OK) +  { +    /* can't decode */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  ofs += (1 + len_octets + len); +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) +  { +    /* can't decode or no integer (error-status) */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  /* must be noError (0) for incoming requests. +     log errors for mib-2 completeness and for debug purposes */ +  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status); +  if (derr != ERR_OK) +  { +    /* can't decode */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  switch (m_stat->error_status) +  { +    case SNMP_ES_TOOBIG: +      snmp_inc_snmpintoobigs(); +      break; +    case SNMP_ES_NOSUCHNAME: +      snmp_inc_snmpinnosuchnames(); +      break; +    case SNMP_ES_BADVALUE: +      snmp_inc_snmpinbadvalues(); +      break; +    case SNMP_ES_READONLY: +      snmp_inc_snmpinreadonlys(); +      break; +    case SNMP_ES_GENERROR: +      snmp_inc_snmpingenerrs(); +      break; +  } +  ofs += (1 + len_octets + len); +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) +  { +    /* can't decode or no integer (error-index) */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  /* must be 0 for incoming requests. +     decode anyway to catch bad integers (and dirty tricks) */ +  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index); +  if (derr != ERR_OK) +  { +    /* can't decode */ +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  ofs += (1 + len_octets + len); +  *ofs_ret = ofs; +  return ERR_OK; +} + +static err_t +snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) +{ +  err_t derr; +  u16_t len, vb_len; +  u8_t  len_octets; +  u8_t type; + +  /* variable binding list */ +  snmp_asn1_dec_type(p, ofs, &type); +  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len); +  if ((derr != ERR_OK) || +      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) +  { +    snmp_inc_snmpinasnparseerrs(); +    return ERR_ARG; +  } +  ofs += (1 + len_octets); + +  /* start with empty list */ +  m_stat->invb.count = 0; +  m_stat->invb.head = NULL; +  m_stat->invb.tail = NULL; + +  while (vb_len > 0) +  { +    struct snmp_obj_id oid, oid_value; +    struct snmp_varbind *vb; + +    snmp_asn1_dec_type(p, ofs, &type); +    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +    if ((derr != ERR_OK) || +        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) || +        (len == 0) || (len > vb_len)) +    { +      snmp_inc_snmpinasnparseerrs(); +      /* free varbinds (if available) */ +      snmp_varbind_list_free(&m_stat->invb); +      return ERR_ARG; +    } +    ofs += (1 + len_octets); +    vb_len -= (1 + len_octets); + +    snmp_asn1_dec_type(p, ofs, &type); +    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID))) +    { +      /* can't decode object name length */ +      snmp_inc_snmpinasnparseerrs(); +      /* free varbinds (if available) */ +      snmp_varbind_list_free(&m_stat->invb); +      return ERR_ARG; +    } +    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid); +    if (derr != ERR_OK) +    { +      /* can't decode object name */ +      snmp_inc_snmpinasnparseerrs(); +      /* free varbinds (if available) */ +      snmp_varbind_list_free(&m_stat->invb); +      return ERR_ARG; +    } +    ofs += (1 + len_octets + len); +    vb_len -= (1 + len_octets + len); + +    snmp_asn1_dec_type(p, ofs, &type); +    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); +    if (derr != ERR_OK) +    { +      /* can't decode object value length */ +      snmp_inc_snmpinasnparseerrs(); +      /* free varbinds (if available) */ +      snmp_varbind_list_free(&m_stat->invb); +      return ERR_ARG; +    } + +    switch (type) +    { +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): +        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t)); +        if (vb != NULL) +        { +          s32_t *vptr = vb->value; + +          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr); +          snmp_varbind_tail_add(&m_stat->invb, vb); +        } +        else +        { +          derr = ERR_ARG; +        } +        break; +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): +        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t)); +        if (vb != NULL) +        { +          u32_t *vptr = vb->value; + +          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr); +          snmp_varbind_tail_add(&m_stat->invb, vb); +        } +        else +        { +          derr = ERR_ARG; +        } +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): +        vb = snmp_varbind_alloc(&oid, type, len); +        if (vb != NULL) +        { +          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value); +          snmp_varbind_tail_add(&m_stat->invb, vb); +        } +        else +        { +          derr = ERR_ARG; +        } +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): +        vb = snmp_varbind_alloc(&oid, type, 0); +        if (vb != NULL) +        { +          snmp_varbind_tail_add(&m_stat->invb, vb); +          derr = ERR_OK; +        } +        else +        { +          derr = ERR_ARG; +        } +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): +        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value); +        if (derr == ERR_OK) +        { +          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t)); +          if (vb != NULL) +          { +            u8_t i = oid_value.len; +            s32_t *vptr = vb->value; + +            while(i > 0) +            { +              i--; +              vptr[i] = oid_value.id[i]; +            } +            snmp_varbind_tail_add(&m_stat->invb, vb); +            derr = ERR_OK; +          } +          else +          { +            derr = ERR_ARG; +          } +        } +        break; +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): +        if (len == 4) +        { +          /* must be exactly 4 octets! */ +          vb = snmp_varbind_alloc(&oid, type, 4); +          if (vb != NULL) +          { +            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value); +            snmp_varbind_tail_add(&m_stat->invb, vb); +          } +          else +          { +            derr = ERR_ARG; +          } +        } +        else +        { +          derr = ERR_ARG; +        } +        break; +      default: +        derr = ERR_ARG; +        break; +    } +    if (derr != ERR_OK) +    { +      snmp_inc_snmpinasnparseerrs(); +      /* free varbinds (if available) */ +      snmp_varbind_list_free(&m_stat->invb); +      return ERR_ARG; +    } +    ofs += (1 + len_octets + len); +    vb_len -= (1 + len_octets + len); +  } + +  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ) +  { +    snmp_add_snmpintotalsetvars(m_stat->invb.count); +  } +  else +  { +    snmp_add_snmpintotalreqvars(m_stat->invb.count); +  } + +  *ofs_ret = ofs; +  return ERR_OK; +} + +struct snmp_varbind* +snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) +{ +  struct snmp_varbind *vb; + +  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); +  LWIP_ASSERT("vb != NULL",vb != NULL); +  if (vb != NULL) +  { +    u8_t i; + +    vb->next = NULL; +    vb->prev = NULL; +    i = oid->len; +    vb->ident_len = i; +    if (i > 0) +    { +      /* allocate array of s32_t for our object identifier */ +      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i); +      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL); +      if (vb->ident == NULL) +      { +        mem_free(vb); +        return NULL; +      } +      while(i > 0) +      { +        i--; +        vb->ident[i] = oid->id[i]; +      } +    } +    else +    { +      /* i == 0, pass zero length object identifier */ +      vb->ident = NULL; +    } +    vb->value_type = type; +    vb->value_len = len; +    if (len > 0) +    { +      /* allocate raw bytes for our object value */ +      vb->value = mem_malloc(len); +      LWIP_ASSERT("vb->value != NULL",vb->value != NULL); +      if (vb->value == NULL) +      { +        if (vb->ident != NULL) +        { +          mem_free(vb->ident); +        } +        mem_free(vb); +        return NULL; +      } +    } +    else +    { +      /* ASN1_NUL type, or zero length ASN1_OC_STR */ +      vb->value = NULL; +    } +  } +  return vb; +} + +void +snmp_varbind_free(struct snmp_varbind *vb) +{ +  if (vb->value != NULL ) +  { +    mem_free(vb->value); +  } +  if (vb->ident != NULL ) +  { +    mem_free(vb->ident); +  } +  mem_free(vb); +} + +void +snmp_varbind_list_free(struct snmp_varbind_root *root) +{ +  struct snmp_varbind *vb, *prev; + +  vb = root->tail; +  while ( vb != NULL ) +  { +    prev = vb->prev; +    snmp_varbind_free(vb); +    vb = prev; +  } +  root->count = 0; +  root->head = NULL; +  root->tail = NULL; +} + +void +snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb) +{ +  if (root->count == 0) +  { +    /* add first varbind to list */ +    root->head = vb; +    root->tail = vb; +  } +  else +  { +    /* add nth varbind to list tail */ +    root->tail->next = vb; +    vb->prev = root->tail; +    root->tail = vb; +  } +  root->count += 1; +} + +struct snmp_varbind* +snmp_varbind_tail_remove(struct snmp_varbind_root *root) +{ +  struct snmp_varbind* vb; + +  if (root->count > 0) +  { +    /* remove tail varbind */ +    vb = root->tail; +    root->tail = vb->prev; +    vb->prev->next = NULL; +    root->count -= 1; +  } +  else +  { +    /* nothing to remove */ +    vb = NULL; +  } +  return vb; +} + +#endif /* LWIP_SNMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/msg_out.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/msg_out.c new file mode 100644 index 000000000..b705aaca7 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/snmp/msg_out.c @@ -0,0 +1,683 @@ +/** + * @file + * SNMP output message processing (RFC1157). + * + * Output responses and traps are build in two passes: + * + * Pass 0: iterate over the output message backwards to determine encoding lengths + * Pass 1: the actual forward encoding of internal form into ASN1 + * + * The single-pass encoding method described by Comer & Stevens + * requires extra buffer space and copying for reversal of the packet. + * The buffer requirement can be prohibitively large for big payloads + * (>= 484) therefore we use the two encoding passes. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/netif.h" +#include "lwip/snmp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_msg.h" + +struct snmp_trap_dst +{ +  /* destination IP address in network order */ +  struct ip_addr dip; +  /* set to 0 when disabled, >0 when enabled */ +  u8_t enable; +}; +struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; + +/** TRAP message structure */ +struct snmp_msg_trap trap_msg; + +static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len); +static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len); +static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root); + +static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p); +static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p); +static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs); + +/** + * Sets enable switch for this trap destination. + * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 + * @param enable switch if 0 destination is disabled >0 enabled. + */ +void +snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) +{ +  if (dst_idx < SNMP_TRAP_DESTINATIONS) +  { +    trap_dst[dst_idx].enable = enable; +  } +} + +/** + * Sets IPv4 address for this trap destination. + * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 + * @param dst IPv4 address in host order. + */ +void +snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst) +{ +  if (dst_idx < SNMP_TRAP_DESTINATIONS) +  { +    trap_dst[dst_idx].dip.addr = htonl(dst->addr); +  } +} + +/** + * Sends a 'getresponse' message to the request originator. + * + * @param m_stat points to the current message request state source + * @return ERR_OK when success, ERR_MEM if we're out of memory + * + * @note the caller is responsible for filling in outvb in the m_stat + * and provide error-status and index (except for tooBig errors) ... + */ +err_t +snmp_send_response(struct snmp_msg_pstat *m_stat) +{ +  struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0}; +  struct pbuf *p; +  u16_t tot_len; +  err_t err; + +  /* pass 0, calculate length fields */ +  tot_len = snmp_varbind_list_sum(&m_stat->outvb); +  tot_len = snmp_resp_header_sum(m_stat, tot_len); + +  /* try allocating pbuf(s) for complete response */ +  p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); +  if (p == NULL) +  { +    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n")); + +    /* can't construct reply, return error-status tooBig */ +    m_stat->error_status = SNMP_ES_TOOBIG; +    m_stat->error_index = 0; +    /* pass 0, recalculate lengths, for empty varbind-list */ +    tot_len = snmp_varbind_list_sum(&emptyvb); +    tot_len = snmp_resp_header_sum(m_stat, tot_len); +    /* retry allocation once for header and empty varbind-list */ +    p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); +  } +  if (p != NULL) +  { +    /* first pbuf alloc try or retry alloc success */ +    u16_t ofs; + +    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n")); + +    /* pass 1, size error, encode packet ino the pbuf(s) */ +    ofs = snmp_resp_header_enc(m_stat, p); +    if (m_stat->error_status == SNMP_ES_TOOBIG) +    { +      snmp_varbind_list_enc(&emptyvb, p, ofs); +    } +    else +    { +      snmp_varbind_list_enc(&m_stat->outvb, p, ofs); +    } + +    switch (m_stat->error_status) +    { +      case SNMP_ES_TOOBIG: +        snmp_inc_snmpouttoobigs(); +        break; +      case SNMP_ES_NOSUCHNAME: +        snmp_inc_snmpoutnosuchnames(); +        break; +      case SNMP_ES_BADVALUE: +        snmp_inc_snmpoutbadvalues(); +        break; +      case SNMP_ES_GENERROR: +        snmp_inc_snmpoutgenerrs(); +        break; +    } +    snmp_inc_snmpoutgetresponses(); +    snmp_inc_snmpoutpkts(); + +    /** @todo do we need separate rx and tx pcbs for threaded case? */ +    /** connect to the originating source */ +    udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp); +    err = udp_send(m_stat->pcb, p); +    if (err == ERR_MEM) +    { +      /** @todo release some memory, retry and return tooBig? tooMuchHassle? */ +      err = ERR_MEM; +    } +    else +    { +      err = ERR_OK; +    } +    /** disassociate remote address and port with this pcb */ +    udp_disconnect(m_stat->pcb); + +    pbuf_free(p); +    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n")); +    return err; +  } +  else +  { +    /* first pbuf alloc try or retry alloc failed +       very low on memory, couldn't return tooBig */ +    return ERR_MEM; +  } +} + + +/** + * Sends an generic or enterprise specific trap message. + * + * @param generic_trap is the trap code + * @param eoid points to enterprise object identifier + * @param specific_trap used for enterprise traps when generic_trap == 6 + * @return ERR_OK when success, ERR_MEM if we're out of memory + * + * @note the caller is responsible for filling in outvb in the trap_msg + * @note the use of the enterpise identifier field + * is per RFC1215. + * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps + * and .iso.org.dod.internet.private.enterprises.yourenterprise + * (sysObjectID) for specific traps. + */ +err_t +snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap) +{ +  struct snmp_trap_dst *td; +  struct netif *dst_if; +  struct ip_addr dst_ip; +  struct pbuf *p; +  u16_t i,tot_len; + +  for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++) +  { +    if ((td->enable != 0) && (td->dip.addr != 0)) +    { +      /* network order trap destination */ +      trap_msg.dip.addr = td->dip.addr; +      /* lookup current source address for this dst */ +      dst_if = ip_route(&td->dip); +      dst_ip.addr = ntohl(dst_if->ip_addr.addr); +      trap_msg.sip_raw[0] = dst_ip.addr >> 24; +      trap_msg.sip_raw[1] = dst_ip.addr >> 16; +      trap_msg.sip_raw[2] = dst_ip.addr >> 8; +      trap_msg.sip_raw[3] = dst_ip.addr; +      trap_msg.gen_trap = generic_trap; +      trap_msg.spc_trap = specific_trap; +      if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) +      { +        /* enterprise-Specific trap */ +        trap_msg.enterprise = eoid; +      } +      else +      { +        /* generic (MIB-II) trap */ +        snmp_get_snmpgrpid_ptr(&trap_msg.enterprise); +      } +      snmp_get_sysuptime(&trap_msg.ts); + +      /* pass 0, calculate length fields */ +      tot_len = snmp_varbind_list_sum(&trap_msg.outvb); +      tot_len = snmp_trap_header_sum(&trap_msg, tot_len); + +      /* allocate pbuf(s) */ +      p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); +      if (p != NULL) +      { +        u16_t ofs; + +        /* pass 1, encode packet ino the pbuf(s) */ +        ofs = snmp_trap_header_enc(&trap_msg, p); +        snmp_varbind_list_enc(&trap_msg.outvb, p, ofs); + +        snmp_inc_snmpouttraps(); +        snmp_inc_snmpoutpkts(); + +        /** connect to the TRAP destination */ +        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT); +        udp_send(trap_msg.pcb, p); +        /** disassociate remote address and port with this pcb */ +        udp_disconnect(trap_msg.pcb); + +        pbuf_free(p); +      } +      else +      { +        return ERR_MEM; +      } +    } +  } +  return ERR_OK; +} + +void +snmp_coldstart_trap(void) +{ +  trap_msg.outvb.head = NULL; +  trap_msg.outvb.tail = NULL; +  trap_msg.outvb.count = 0; +  snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0); +} + +void +snmp_authfail_trap(void) +{ +  u8_t enable; +  snmp_get_snmpenableauthentraps(&enable); +  if (enable == 1) +  { +    trap_msg.outvb.head = NULL; +    trap_msg.outvb.tail = NULL; +    trap_msg.outvb.count = 0; +    snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0); +  } +} + +/** + * Sums response header field lengths from tail to head and + * returns resp_header_lengths for second encoding pass. + * + * @param vb_len varbind-list length + * @param rhl points to returned header lengths + * @return the required lenght for encoding the response header + */ +static u16_t +snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len) +{ +  u16_t tot_len; +  struct snmp_resp_header_lengths *rhl; + +  rhl = &m_stat->rhl; +  tot_len = vb_len; +  snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen); +  snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen); +  tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen; + +  snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen); +  snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen); +  tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen; + +  snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen); +  snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen); +  tot_len += 1 + rhl->ridlenlen + rhl->ridlen; + +  rhl->pdulen = tot_len; +  snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen); +  tot_len += 1 + rhl->pdulenlen; + +  rhl->comlen = m_stat->com_strlen; +  snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen); +  tot_len += 1 + rhl->comlenlen + rhl->comlen; + +  snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen); +  snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen); +  tot_len += 1 + rhl->verlen + rhl->verlenlen; + +  rhl->seqlen = tot_len; +  snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen); +  tot_len += 1 + rhl->seqlenlen; + +  return tot_len; +} + +/** + * Sums trap header field lengths from tail to head and + * returns trap_header_lengths for second encoding pass. + * + * @param vb_len varbind-list length + * @param thl points to returned header lengths + * @return the required lenght for encoding the trap header + */ +static u16_t +snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len) +{ +  u16_t tot_len; +  struct snmp_trap_header_lengths *thl; + +  thl = &m_trap->thl; +  tot_len = vb_len; + +  snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen); +  snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen); +  tot_len += 1 + thl->tslen + thl->tslenlen; + +  snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen); +  snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen); +  tot_len += 1 + thl->strplen + thl->strplenlen; + +  snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen); +  snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen); +  tot_len += 1 + thl->gtrplen + thl->gtrplenlen; + +  thl->aaddrlen = 4; +  snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen); +  tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen; + +  snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen); +  snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen); +  tot_len += 1 + thl->eidlen + thl->eidlenlen; + +  thl->pdulen = tot_len; +  snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen); +  tot_len += 1 + thl->pdulenlen; + +  thl->comlen = sizeof(snmp_publiccommunity) - 1; +  snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen); +  tot_len += 1 + thl->comlenlen + thl->comlen; + +  snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen); +  snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen); +  tot_len += 1 + thl->verlen + thl->verlenlen; + +  thl->seqlen = tot_len; +  snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen); +  tot_len += 1 + thl->seqlenlen; + +  return tot_len; +} + +/** + * Sums varbind lengths from tail to head and + * annotates lengths in varbind for second encoding pass. + * + * @param root points to the root of the variable binding list + * @return the required lenght for encoding the variable bindings + */ +static u16_t +snmp_varbind_list_sum(struct snmp_varbind_root *root) +{ +  struct snmp_varbind *vb; +  u32_t *uint_ptr; +  s32_t *sint_ptr; +  u16_t tot_len; + +  tot_len = 0; +  vb = root->tail; +  while ( vb != NULL ) +  { +    /* encoded value lenght depends on type */ +    switch (vb->value_type) +    { +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): +        sint_ptr = vb->value; +        snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen); +        break; +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): +        uint_ptr = vb->value; +        snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen); +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): +        vb->vlen = vb->value_len; +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): +        sint_ptr = vb->value; +        snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen); +        break; +      default: +        /* unsupported type */ +        vb->vlen = 0; +        break; +    }; +    /* encoding length of value length field */ +    snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen); +    snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen); +    snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen); + +    vb->seqlen = 1 + vb->vlenlen + vb->vlen; +    vb->seqlen += 1 + vb->olenlen + vb->olen; +    snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen); + +    /* varbind seq */ +    tot_len += 1 + vb->seqlenlen + vb->seqlen; + +    vb = vb->prev; +  } + +  /* varbind-list seq */ +  root->seqlen = tot_len; +  snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen); +  tot_len += 1 + root->seqlenlen; + +  return tot_len; +} + +/** + * Encodes response header from head to tail. + */ +static u16_t +snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p) +{ +  u16_t ofs; + +  ofs = 0; +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen); +  ofs += m_stat->rhl.seqlenlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen); +  ofs += m_stat->rhl.verlenlen; +  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version); +  ofs += m_stat->rhl.verlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen); +  ofs += m_stat->rhl.comlenlen; +  snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community); +  ofs += m_stat->rhl.comlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen); +  ofs += m_stat->rhl.pdulenlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen); +  ofs += m_stat->rhl.ridlenlen; +  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid); +  ofs += m_stat->rhl.ridlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen); +  ofs += m_stat->rhl.errstatlenlen; +  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status); +  ofs += m_stat->rhl.errstatlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen); +  ofs += m_stat->rhl.erridxlenlen; +  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index); +  ofs += m_stat->rhl.erridxlen; + +  return ofs; +} + +/** + * Encodes trap header from head to tail. + */ +static u16_t +snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p) +{ +  u16_t ofs; + +  ofs = 0; +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen); +  ofs += m_trap->thl.seqlenlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen); +  ofs += m_trap->thl.verlenlen; +  snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version); +  ofs += m_trap->thl.verlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen); +  ofs += m_trap->thl.comlenlen; +  snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]); +  ofs += m_trap->thl.comlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen); +  ofs += m_trap->thl.pdulenlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen); +  ofs += m_trap->thl.eidlenlen; +  snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]); +  ofs += m_trap->thl.eidlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen); +  ofs += m_trap->thl.aaddrlenlen; +  snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]); +  ofs += m_trap->thl.aaddrlen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen); +  ofs += m_trap->thl.gtrplenlen; +  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap); +  ofs += m_trap->thl.gtrplen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen); +  ofs += m_trap->thl.strplenlen; +  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap); +  ofs += m_trap->thl.strplen; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen); +  ofs += m_trap->thl.tslenlen; +  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts); +  ofs += m_trap->thl.tslen; + +  return ofs; +} + +/** + * Encodes varbind list from head to tail. + */ +static u16_t +snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs) +{ +  struct snmp_varbind *vb; +  s32_t *sint_ptr; +  u32_t *uint_ptr; +  u8_t *raw_ptr; + +  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); +  ofs += 1; +  snmp_asn1_enc_length(p, ofs, root->seqlen); +  ofs += root->seqlenlen; + +  vb = root->head; +  while ( vb != NULL ) +  { +    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); +    ofs += 1; +    snmp_asn1_enc_length(p, ofs, vb->seqlen); +    ofs += vb->seqlenlen; + +    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); +    ofs += 1; +    snmp_asn1_enc_length(p, ofs, vb->olen); +    ofs += vb->olenlen; +    snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]); +    ofs += vb->olen; + +    snmp_asn1_enc_type(p, ofs, vb->value_type); +    ofs += 1; +    snmp_asn1_enc_length(p, ofs, vb->vlen); +    ofs += vb->vlenlen; + +    switch (vb->value_type) +    { +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): +        sint_ptr = vb->value; +        snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr); +        break; +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): +        uint_ptr = vb->value; +        snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr); +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): +      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): +        raw_ptr = vb->value; +        snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr); +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): +        break; +      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): +        sint_ptr = vb->value; +        snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr); +        break; +      default: +        /* unsupported type */ +        break; +    }; +    ofs += vb->vlen; +    vb = vb->next; +  } +  return ofs; +} + +#endif /* LWIP_SNMP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/stats.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/stats.c new file mode 100644 index 000000000..a036d83bb --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/stats.c @@ -0,0 +1,149 @@ +/** + * @file + * Statistics module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/stats.h" +#include "lwip/mem.h" + +#include <string.h> + +struct stats_ lwip_stats; + +#if LWIP_STATS_DISPLAY +void +stats_display_proto(struct stats_proto *proto, char *name) +{ +  LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); +  LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));  +  LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));  +  LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));  +  LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));  +  LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr));  +  LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr));  +  LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr));  +  LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr));  +  LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr));  +  LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr));  +  LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err));  +  LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));  +} + +#if IGMP_STATS +void +stats_display_igmp(struct stats_igmp *igmp) +{ +  LWIP_PLATFORM_DIAG(("\nIGMP\n\t")); +  LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));  +  LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));  +  LWIP_PLATFORM_DIAG(("v1_rxed: %"STAT_COUNTER_F"\n\t", igmp->v1_rxed));  +  LWIP_PLATFORM_DIAG(("join_sent: %"STAT_COUNTER_F"\n\t", igmp->join_sent));  +  LWIP_PLATFORM_DIAG(("leave_sent: %"STAT_COUNTER_F"\n\t", igmp->leave_sent));  +  LWIP_PLATFORM_DIAG(("unicast_query: %"STAT_COUNTER_F"\n\t", igmp->unicast_query));  +  LWIP_PLATFORM_DIAG(("report_sent: %"STAT_COUNTER_F"\n\t", igmp->report_sent));  +  LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));  +  LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed)); +} +#endif /* IGMP_STATS */ + +#if MEM_STATS || MEMP_STATS +void +stats_display_mem(struct stats_mem *mem, char *name) +{ +  LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); +  LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));  +  LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used));  +  LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max));  +  LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); +} + +#if MEMP_STATS +void +stats_display_memp(struct stats_mem *mem, int index) +{ +  char * memp_names[] = { +#define LWIP_MEMPOOL(name,num,size,desc) desc, +#include "lwip/memp_std.h" +  }; +  if(index < MEMP_MAX) { +    stats_display_mem(mem, memp_names[index]); +  } +} +#endif /* MEMP_STATS */ +#endif /* MEM_STATS || MEMP_STATS */ + +#if SYS_STATS +void +stats_display_sys(struct stats_sys *sys) +{ +  LWIP_PLATFORM_DIAG(("\nSYS\n\t")); +  LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));  +  LWIP_PLATFORM_DIAG(("sem.max:  %"U32_F"\n\t", (u32_t)sys->sem.max));  +  LWIP_PLATFORM_DIAG(("sem.err:  %"U32_F"\n\t", (u32_t)sys->sem.err));  +  LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));  +  LWIP_PLATFORM_DIAG(("mbox.max:  %"U32_F"\n\t", (u32_t)sys->mbox.max));  +  LWIP_PLATFORM_DIAG(("mbox.err:  %"U32_F"\n\t", (u32_t)sys->mbox.err));  +} +#endif /* SYS_STATS */ + +void +stats_display(void) +{ +  s16_t i; + +  LINK_STATS_DISPLAY(); +  ETHARP_STATS_DISPLAY(); +  IPFRAG_STATS_DISPLAY(); +  IP_STATS_DISPLAY(); +  IGMP_STATS_DISPLAY(); +  ICMP_STATS_DISPLAY(); +  UDP_STATS_DISPLAY(); +  TCP_STATS_DISPLAY(); +  MEM_STATS_DISPLAY(); +  for (i = 0; i < MEMP_MAX; i++) { +    MEMP_STATS_DISPLAY(i); +  } +  SYS_STATS_DISPLAY(); +} +#endif /* LWIP_STATS_DISPLAY */ + +#endif /* LWIP_STATS */ + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/sys.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/sys.c new file mode 100644 index 000000000..d1fbda4e6 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/sys.c @@ -0,0 +1,344 @@ +/** + * @file + * lwIP Operating System abstraction + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/tcpip.h" + +/** + * Struct used for sys_sem_wait_timeout() to tell wether the time + * has run out or the semaphore has really become available. + */ +struct sswt_cb +{ +  s16_t timeflag; +  sys_sem_t *psem; +}; + +/** + * Wait (forever) for a message to arrive in an mbox. + * While waiting, timeouts (for this thread) are processed. + * + * @param mbox the mbox to fetch the message from + * @param msg the place to store the message + */ +void +sys_mbox_fetch(sys_mbox_t mbox, void **msg) +{ +  u32_t time_needed; +  struct sys_timeouts *timeouts; +  struct sys_timeo *tmptimeout; +  sys_timeout_handler h; +  void *arg; + + again: +  timeouts = sys_arch_timeouts(); + +  if (!timeouts || !timeouts->next) { +    UNLOCK_TCPIP_CORE(); +    time_needed = sys_arch_mbox_fetch(mbox, msg, 0); +    LOCK_TCPIP_CORE(); +  } else { +    if (timeouts->next->time > 0) { +      UNLOCK_TCPIP_CORE(); +      time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time); +      LOCK_TCPIP_CORE(); +    } else { +      time_needed = SYS_ARCH_TIMEOUT; +    } + +    if (time_needed == SYS_ARCH_TIMEOUT) { +      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message +         could be fetched. We should now call the timeout handler and +         deallocate the memory allocated for the timeout. */ +      tmptimeout = timeouts->next; +      timeouts->next = tmptimeout->next; +      h   = tmptimeout->h; +      arg = tmptimeout->arg; +      memp_free(MEMP_SYS_TIMEOUT, tmptimeout); +      if (h != NULL) { +        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg)); +        h(arg); +      } + +      /* We try again to fetch a message from the mbox. */ +      goto again; +    } else { +      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout +         occured. The time variable is set to the number of +         milliseconds we waited for the message. */ +      if (time_needed < timeouts->next->time) { +        timeouts->next->time -= time_needed; +      } else { +        timeouts->next->time = 0; +      } +    } +  } +} + +/** + * Wait (forever) for a semaphore to become available. + * While waiting, timeouts (for this thread) are processed. + * + * @param sem semaphore to wait for + */ +void +sys_sem_wait(sys_sem_t sem) +{ +  u32_t time_needed; +  struct sys_timeouts *timeouts; +  struct sys_timeo *tmptimeout; +  sys_timeout_handler h; +  void *arg; + + again: + +  timeouts = sys_arch_timeouts(); + +  if (!timeouts || !timeouts->next) { +    sys_arch_sem_wait(sem, 0); +  } else { +    if (timeouts->next->time > 0) { +      time_needed = sys_arch_sem_wait(sem, timeouts->next->time); +    } else { +      time_needed = SYS_ARCH_TIMEOUT; +    } + +    if (time_needed == SYS_ARCH_TIMEOUT) { +      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message +        could be fetched. We should now call the timeout handler and +        deallocate the memory allocated for the timeout. */ +      tmptimeout = timeouts->next; +      timeouts->next = tmptimeout->next; +      h = tmptimeout->h; +      arg = tmptimeout->arg; +      memp_free(MEMP_SYS_TIMEOUT, tmptimeout); +      if (h != NULL) { +        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg)); +        h(arg); +      } + +      /* We try again to fetch a message from the mbox. */ +      goto again; +    } else { +      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout +         occured. The time variable is set to the number of +         milliseconds we waited for the message. */ +      if (time_needed < timeouts->next->time) { +        timeouts->next->time -= time_needed; +      } else { +        timeouts->next->time = 0; +      } +    } +  } +} + +/** + * Create a one-shot timer (aka timeout). Timeouts are processed in the + * following cases: + * - while waiting for a message using sys_mbox_fetch() + * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout() + * - while sleeping using the inbuilt sys_msleep() + * + * @param msecs time in milliseconds after that the timer should expire + * @param h callback function to call when msecs have elapsed + * @param arg argument to pass to the callback function + */ +void +sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ +  struct sys_timeouts *timeouts; +  struct sys_timeo *timeout, *t; + +  timeout = memp_malloc(MEMP_SYS_TIMEOUT); +  if (timeout == NULL) { +    LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL); +    return; +  } +  timeout->next = NULL; +  timeout->h = h; +  timeout->arg = arg; +  timeout->time = msecs; + +  timeouts = sys_arch_timeouts(); + +  LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n", +    (void *)timeout, msecs, (void*)&h, (void *)arg)); + +  if (timeouts == NULL) { +    LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL); +    return; +  } + +  if (timeouts->next == NULL) { +    timeouts->next = timeout; +    return; +  } + +  if (timeouts->next->time > msecs) { +    timeouts->next->time -= msecs; +    timeout->next = timeouts->next; +    timeouts->next = timeout; +  } else { +    for(t = timeouts->next; t != NULL; t = t->next) { +      timeout->time -= t->time; +      if (t->next == NULL || t->next->time > timeout->time) { +        if (t->next != NULL) { +          t->next->time -= timeout->time; +        } +        timeout->next = t->next; +        t->next = timeout; +        break; +      } +    } +  } +} + +/** + * Go through timeout list (for this task only) and remove the first matching + * entry, even though the timeout has not triggered yet. + * + * @note This function only works as expected if there is only one timeout + * calling 'h' in the list of timeouts. + * + * @param h callback function that would be called by the timeout + * @param arg callback argument that would be passed to h +*/ +void +sys_untimeout(sys_timeout_handler h, void *arg) +{ +  struct sys_timeouts *timeouts; +  struct sys_timeo *prev_t, *t; + +  timeouts = sys_arch_timeouts(); + +  if (timeouts == NULL) { +    LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL); +    return; +  } +  if (timeouts->next == NULL) { +    return; +  } + +  for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { +    if ((t->h == h) && (t->arg == arg)) { +      /* We have a match */ +      /* Unlink from previous in list */ +      if (prev_t == NULL) +        timeouts->next = t->next; +      else +        prev_t->next = t->next; +      /* If not the last one, add time of this one back to next */ +      if (t->next != NULL) +        t->next->time += t->time; +      memp_free(MEMP_SYS_TIMEOUT, t); +      return; +    } +  } +  return; +} + +/** + * Timeout handler function for sys_sem_wait_timeout() + * + * @param arg struct sswt_cb* used to signal a semaphore and end waiting. + */ +static void +sswt_handler(void *arg) +{ +  struct sswt_cb *sswt_cb = (struct sswt_cb *) arg; + +  /* Timeout. Set flag to TRUE and signal semaphore */ +  sswt_cb->timeflag = 1; +  sys_sem_signal(*(sswt_cb->psem)); +} + +/** + * Wait for a semaphore with timeout (specified in ms) + * + * @param sem semaphore to wait + * @param timeout timeout in ms (0: wait forever) + * @return 0 on timeout, 1 otherwise + */ +int +sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout) +{ +  struct sswt_cb sswt_cb; + +  sswt_cb.psem = &sem; +  sswt_cb.timeflag = 0; + +  /* If timeout is zero, then just wait forever */ +  if (timeout > 0) { +    /* Create a timer and pass it the address of our flag */ +    sys_timeout(timeout, sswt_handler, &sswt_cb); +  } +  sys_sem_wait(sem); +  /* Was it a timeout? */ +  if (sswt_cb.timeflag) { +    /* timeout */ +    return 0; +  } else { +    /* Not a timeout. Remove timeout entry */ +    sys_untimeout(sswt_handler, &sswt_cb); +    return 1; +  } +} + +/** + * Sleep for some ms. Timeouts are processed while sleeping. + * + * @param ms number of milliseconds to sleep + */ +void +sys_msleep(u32_t ms) +{ +  sys_sem_t delaysem = sys_sem_new(0); + +  sys_sem_wait_timeout(delaysem, ms); + +  sys_sem_free(delaysem); +} + + +#endif /* NO_SYS */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp.c new file mode 100644 index 000000000..0f3fd41c3 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp.c @@ -0,0 +1,1458 @@ +/** + * @file + * Transmission Control Protocol for IP + * + * This file contains common functions for the TCP implementation, such as functinos + * for manipulating the data structures and the TCP timer functions. TCP functions + * related to input and output is found in tcp_in.c and tcp_out.c respectively. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/snmp.h" +#include "lwip/tcp.h" +#include "lwip/debug.h" + +#include <string.h> + +/* Incremented every coarse grained timer shot (typically every 500 ms). */ +u32_t tcp_ticks; +const u8_t tcp_backoff[13] = +    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; + /* Times per slowtmr hits */ +const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; + +/* The TCP PCB lists. */ + +/** List of all TCP PCBs bound but not yet (connected || listening) */ +struct tcp_pcb *tcp_bound_pcbs;   +/** List of all TCP PCBs in LISTEN state */ +union tcp_listen_pcbs_t tcp_listen_pcbs; +/** List of all TCP PCBs that are in a state in which + * they accept or send data. */ +struct tcp_pcb *tcp_active_pcbs;   +/** List of all TCP PCBs in TIME-WAIT state */ +struct tcp_pcb *tcp_tw_pcbs; + +struct tcp_pcb *tcp_tmp_pcb; + +static u8_t tcp_timer; +static u16_t tcp_new_port(void); + +/** + * Called periodically to dispatch TCP timers. + * + */ +void +tcp_tmr(void) +{ +  /* Call tcp_fasttmr() every 250 ms */ +  tcp_fasttmr(); + +  if (++tcp_timer & 1) { +    /* Call tcp_tmr() every 500 ms, i.e., every other timer +       tcp_tmr() is called. */ +    tcp_slowtmr(); +  } +} + +/** + * Closes the connection held by the PCB. + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it. + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + *         another err_t if closing failed and pcb is not freed + */ +err_t +tcp_close(struct tcp_pcb *pcb) +{ +  err_t err; + +#if TCP_DEBUG +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); +  tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ + +  switch (pcb->state) { +  case CLOSED: +    /* Closing a pcb in the CLOSED state might seem erroneous, +     * however, it is in this state once allocated and as yet unused +     * and the user needs some way to free it should the need arise. +     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) +     * or for a pcb that has been used and then entered the CLOSED state  +     * is erroneous, but this should never happen as the pcb has in those cases +     * been freed, and so any remaining handles are bogus. */ +    err = ERR_OK; +    TCP_RMV(&tcp_bound_pcbs, pcb); +    memp_free(MEMP_TCP_PCB, pcb); +    pcb = NULL; +    break; +  case LISTEN: +    err = ERR_OK; +    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb); +    memp_free(MEMP_TCP_PCB_LISTEN, pcb); +    pcb = NULL; +    break; +  case SYN_SENT: +    err = ERR_OK; +    tcp_pcb_remove(&tcp_active_pcbs, pcb); +    memp_free(MEMP_TCP_PCB, pcb); +    pcb = NULL; +    snmp_inc_tcpattemptfails(); +    break; +  case SYN_RCVD: +    err = tcp_send_ctrl(pcb, TCP_FIN); +    if (err == ERR_OK) { +      snmp_inc_tcpattemptfails(); +      pcb->state = FIN_WAIT_1; +    } +    break; +  case ESTABLISHED: +    err = tcp_send_ctrl(pcb, TCP_FIN); +    if (err == ERR_OK) { +      snmp_inc_tcpestabresets(); +      pcb->state = FIN_WAIT_1; +    } +    break; +  case CLOSE_WAIT: +    err = tcp_send_ctrl(pcb, TCP_FIN); +    if (err == ERR_OK) { +      snmp_inc_tcpestabresets(); +      pcb->state = LAST_ACK; +    } +    break; +  default: +    /* Has already been closed, do nothing. */ +    err = ERR_OK; +    pcb = NULL; +    break; +  } + +  if (pcb != NULL && err == ERR_OK) { +    /* To ensure all data has been sent when tcp_close returns, we have +       to make sure tcp_output doesn't fail. +       Since we don't really have to ensure all data has been sent when tcp_close +       returns (unsent data is sent from tcp timer functions, also), we don't care +       for the return value of tcp_output for now. */ +    /* @todo: When implementing SO_LINGER, this must be changed somehow: +       If SOF_LINGER is set, the data should be sent when tcp_close returns. */ +    tcp_output(pcb); +  } +  return err; +} + +/** + * Abandons a connection and optionally sends a RST to the remote + * host.  Deletes the local protocol control block. This is done when + * a connection is killed because of shortage of memory. + * + * @param pcb the tcp_pcb to abort + * @param reset boolean to indicate whether a reset should be sent + */ +void +tcp_abandon(struct tcp_pcb *pcb, int reset) +{ +  u32_t seqno, ackno; +  u16_t remote_port, local_port; +  struct ip_addr remote_ip, local_ip; +#if LWIP_CALLBACK_API   +  void (* errf)(void *arg, err_t err); +#endif /* LWIP_CALLBACK_API */ +  void *errf_arg; + +   +  /* Figure out on which TCP PCB list we are, and remove us. If we +     are in an active state, call the receive function associated with +     the PCB with a NULL argument, and send an RST to the remote end. */ +  if (pcb->state == TIME_WAIT) { +    tcp_pcb_remove(&tcp_tw_pcbs, pcb); +    memp_free(MEMP_TCP_PCB, pcb); +  } else { +    seqno = pcb->snd_nxt; +    ackno = pcb->rcv_nxt; +    ip_addr_set(&local_ip, &(pcb->local_ip)); +    ip_addr_set(&remote_ip, &(pcb->remote_ip)); +    local_port = pcb->local_port; +    remote_port = pcb->remote_port; +#if LWIP_CALLBACK_API +    errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ +    errf_arg = pcb->callback_arg; +    tcp_pcb_remove(&tcp_active_pcbs, pcb); +    if (pcb->unacked != NULL) { +      tcp_segs_free(pcb->unacked); +    } +    if (pcb->unsent != NULL) { +      tcp_segs_free(pcb->unsent); +    } +#if TCP_QUEUE_OOSEQ     +    if (pcb->ooseq != NULL) { +      tcp_segs_free(pcb->ooseq); +    } +#endif /* TCP_QUEUE_OOSEQ */ +    memp_free(MEMP_TCP_PCB, pcb); +    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); +    if (reset) { +      LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); +      tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); +    } +  } +} + +/** + * Binds the connection to a local portnumber and IP address. If the + * IP address is not given (i.e., ipaddr == NULL), the IP address of + * the outgoing network interface is used instead. + * + * @param pcb the tcp_pcb to bind (no check is done whether this pcb is + *        already bound!) + * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind + *        to any local address + * @param port the local port to bind to + * @return ERR_USE if the port is already in use + *         ERR_OK if bound + */ +err_t +tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ +  struct tcp_pcb *cpcb; + +  LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + +  if (port == 0) { +    port = tcp_new_port(); +  } +  /* Check if the address already is in use. */ +  /* Check the listen pcbs. */ +  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; +      cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (ip_addr_isany(&(cpcb->local_ip)) || +          ip_addr_isany(ipaddr) || +          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { +        return ERR_USE; +      } +    } +  } +  /* Check the connected pcbs. */ +  for(cpcb = tcp_active_pcbs; +      cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (ip_addr_isany(&(cpcb->local_ip)) || +          ip_addr_isany(ipaddr) || +          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { +        return ERR_USE; +      } +    } +  } +  /* Check the bound, not yet connected pcbs. */ +  for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (ip_addr_isany(&(cpcb->local_ip)) || +          ip_addr_isany(ipaddr) || +          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { +        return ERR_USE; +      } +    } +  } +  /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah), +   * we have to check the pcbs in TIME-WAIT state, also: */ +  for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { +        return ERR_USE; +      } +    } +  } + +  if (!ip_addr_isany(ipaddr)) { +    pcb->local_ip = *ipaddr; +  } +  pcb->local_port = port; +  TCP_REG(&tcp_bound_pcbs, pcb); +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); +  return ERR_OK; +} +#if LWIP_CALLBACK_API +/** + * Default accept callback if no accept callback is specified by the user. + */ +static err_t +tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) +{ +  LWIP_UNUSED_ARG(arg); +  LWIP_UNUSED_ARG(pcb); +  LWIP_UNUSED_ARG(err); + +  return ERR_ABRT; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * + * @param pcb the original tcp_pcb + * @param backlog the incoming connections queue limit + * @return tcp_pcb used for listening, consumes less memory. + * + * @note The original tcp_pcb is freed. This function therefore has to be + *       called like this: + *             tpcb = tcp_listen(tpcb); + */ +struct tcp_pcb * +tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) +{ +  struct tcp_pcb_listen *lpcb; + +  LWIP_UNUSED_ARG(backlog); +  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); + +  /* already listening? */ +  if (pcb->state == LISTEN) { +    return pcb; +  } +  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN); +  if (lpcb == NULL) { +    return NULL; +  } +  lpcb->callback_arg = pcb->callback_arg; +  lpcb->local_port = pcb->local_port; +  lpcb->state = LISTEN; +  lpcb->so_options = pcb->so_options; +  lpcb->so_options |= SOF_ACCEPTCONN; +  lpcb->ttl = pcb->ttl; +  lpcb->tos = pcb->tos; +  ip_addr_set(&lpcb->local_ip, &pcb->local_ip); +  TCP_RMV(&tcp_bound_pcbs, pcb); +  memp_free(MEMP_TCP_PCB, pcb); +#if LWIP_CALLBACK_API +  lpcb->accept = tcp_accept_null; +#endif /* LWIP_CALLBACK_API */ +#if TCP_LISTEN_BACKLOG +  lpcb->accepts_pending = 0; +  lpcb->backlog = (backlog ? backlog : 1); +#endif /* TCP_LISTEN_BACKLOG */ +  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb); +  return (struct tcp_pcb *)lpcb; +} + +/**  + * Update the state that tracks the available window space to advertise. + * + * Returns how much extra window would be advertised if we sent an + * update now. + */ +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) +{ +  u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; + +  if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + pcb->mss)) { +    /* we can advertise more window */ +    pcb->rcv_ann_wnd = pcb->rcv_wnd; +    return new_right_edge - pcb->rcv_ann_right_edge; +  } else { +    if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { +      /* Can happen due to other end sending out of advertised window, +       * but within actual available (but not yet advertised) window */ +      pcb->rcv_ann_wnd = 0; +    } else { +      /* keep the right edge of window constant */ +      pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; +    } +    return 0; +  } +} + +/** + * This function should be called by the application when it has + * processed the data. The purpose is to advertise a larger window + * when the data has been processed. + * + * @param pcb the tcp_pcb for which data is read + * @param len the amount of bytes that have been read by the application + */ +void +tcp_recved(struct tcp_pcb *pcb, u16_t len) +{ +  int wnd_inflation; + +  LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n", +              len <= 0xffff - pcb->rcv_wnd ); + +  pcb->rcv_wnd += len; +  if (pcb->rcv_wnd > TCP_WND) +    pcb->rcv_wnd = TCP_WND; + +  wnd_inflation = tcp_update_rcv_ann_wnd(pcb); + +  /* If the change in the right edge of window is significant (default +   * watermark is TCP_WND/2), then send an explicit update now. +   * Otherwise wait for a packet to be sent in the normal course of +   * events (or more window to be available later) */ +  if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD)  +    tcp_ack_now(pcb); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", +         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); +} + +/** + * A nastly hack featuring 'goto' statements that allocates a + * new TCP local port. + * + * @return a new (free) local TCP port number + */ +static u16_t +tcp_new_port(void) +{ +  struct tcp_pcb *pcb; +#ifndef TCP_LOCAL_PORT_RANGE_START +#define TCP_LOCAL_PORT_RANGE_START 4096 +#define TCP_LOCAL_PORT_RANGE_END   0x7fff +#endif +  static u16_t port = TCP_LOCAL_PORT_RANGE_START; +   + again: +  if (++port > TCP_LOCAL_PORT_RANGE_END) { +    port = TCP_LOCAL_PORT_RANGE_START; +  } +   +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    if (pcb->local_port == port) { +      goto again; +    } +  } +  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { +    if (pcb->local_port == port) { +      goto again; +    } +  } +  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { +    if (pcb->local_port == port) { +      goto again; +    } +  } +  return port; +} + +/** + * Connects to another host. The function given as the "connected" + * argument will be called when the connection has been established. + * + * @param pcb the tcp_pcb used to establish the connection + * @param ipaddr the remote ip address to connect to + * @param port the remote tcp port to connect to + * @param connected callback function to call when connected (or on error) + * @return ERR_VAL if invalid arguments are given + *         ERR_OK if connect request has been sent + *         other err_t values if connect request couldn't be sent + */ +err_t +tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, +      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) +{ +  err_t ret; +  u32_t iss; + +  LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); +  if (ipaddr != NULL) { +    pcb->remote_ip = *ipaddr; +  } else { +    return ERR_VAL; +  } +  pcb->remote_port = port; +  if (pcb->local_port == 0) { +    pcb->local_port = tcp_new_port(); +  } +  iss = tcp_next_iss(); +  pcb->rcv_nxt = 0; +  pcb->snd_nxt = iss; +  pcb->lastack = iss - 1; +  pcb->snd_lbb = iss - 1; +  pcb->rcv_wnd = TCP_WND; +  pcb->rcv_ann_wnd = TCP_WND; +  pcb->rcv_ann_right_edge = pcb->rcv_nxt; +  pcb->snd_wnd = TCP_WND; +  /* As initial send MSS, we use TCP_MSS but limit it to 536. +     The send MSS is updated when an MSS option is received. */ +  pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; +#if TCP_CALCULATE_EFF_SEND_MSS +  pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ +  pcb->cwnd = 1; +  pcb->ssthresh = pcb->mss * 10; +  pcb->state = SYN_SENT; +#if LWIP_CALLBACK_API   +  pcb->connected = connected; +#endif /* LWIP_CALLBACK_API */ +  TCP_RMV(&tcp_bound_pcbs, pcb); +  TCP_REG(&tcp_active_pcbs, pcb); + +  snmp_inc_tcpactiveopens(); +   +  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS +#if LWIP_TCP_TIMESTAMPS +                    | TF_SEG_OPTS_TS +#endif +                    ); +  if (ret == ERR_OK) {  +    tcp_output(pcb); +  } +  return ret; +}  + +/** + * Called every 500 ms and implements the retransmission timer and the timer that + * removes PCBs that have been in TIME-WAIT for enough time. It also increments + * various timers such as the inactivity timer in each PCB. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_slowtmr(void) +{ +  struct tcp_pcb *pcb, *pcb2, *prev; +  u16_t eff_wnd; +  u8_t pcb_remove;      /* flag if a PCB should be removed */ +  err_t err; + +  err = ERR_OK; + +  ++tcp_ticks; + +  /* Steps through all of the active PCBs. */ +  prev = NULL; +  pcb = tcp_active_pcbs; +  if (pcb == NULL) { +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); +  } +  while (pcb != NULL) { +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); +    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); +    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); +    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); + +    pcb_remove = 0; + +    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { +      ++pcb_remove; +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); +    } +    else if (pcb->nrtx == TCP_MAXRTX) { +      ++pcb_remove; +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); +    } else { +      if (pcb->persist_backoff > 0) { +        /* If snd_wnd is zero, use persist timer to send 1 byte probes +         * instead of using the standard retransmission mechanism. */ +        pcb->persist_cnt++; +        if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) { +          pcb->persist_cnt = 0; +          if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { +            pcb->persist_backoff++; +          } +          tcp_zero_window_probe(pcb); +        } +      } else { +        /* Increase the retransmission timer if it is running */ +        if(pcb->rtime >= 0) +          ++pcb->rtime; + +        if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { +          /* Time for a retransmission. */ +          LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F +                                      " pcb->rto %"S16_F"\n", +                                      pcb->rtime, pcb->rto)); + +          /* Double retransmission time-out unless we are trying to +           * connect to somebody (i.e., we are in SYN_SENT). */ +          if (pcb->state != SYN_SENT) { +            pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; +          } + +          /* Reset the retransmission timer. */ +          pcb->rtime = 0; + +          /* Reduce congestion window and ssthresh. */ +          eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); +          pcb->ssthresh = eff_wnd >> 1; +          if (pcb->ssthresh < pcb->mss) { +            pcb->ssthresh = pcb->mss * 2; +          } +          pcb->cwnd = pcb->mss; +          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F +                                       " ssthresh %"U16_F"\n", +                                       pcb->cwnd, pcb->ssthresh)); +  +          /* The following needs to be called AFTER cwnd is set to one +             mss - STJ */ +          tcp_rexmit_rto(pcb); +        } +      } +    } +    /* Check if this PCB has stayed too long in FIN-WAIT-2 */ +    if (pcb->state == FIN_WAIT_2) { +      if ((u32_t)(tcp_ticks - pcb->tmr) > +          TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { +        ++pcb_remove; +        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); +      } +    } + +    /* Check if KEEPALIVE should be sent */ +    if((pcb->so_options & SOF_KEEPALIVE) &&  +       ((pcb->state == ESTABLISHED) ||  +        (pcb->state == CLOSE_WAIT))) { +#if LWIP_TCP_KEEPALIVE +      if((u32_t)(tcp_ticks - pcb->tmr) >  +         (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl)) +         / TCP_SLOW_INTERVAL) +#else       +      if((u32_t)(tcp_ticks - pcb->tmr) >  +         (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) +#endif /* LWIP_TCP_KEEPALIVE */ +      { +        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", +                                ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +                                ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); +         +        tcp_abort(pcb); +      } +#if LWIP_TCP_KEEPALIVE +      else if((u32_t)(tcp_ticks - pcb->tmr) >  +              (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl) +              / TCP_SLOW_INTERVAL) +#else +      else if((u32_t)(tcp_ticks - pcb->tmr) >  +              (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)  +              / TCP_SLOW_INTERVAL) +#endif /* LWIP_TCP_KEEPALIVE */ +      { +        tcp_keepalive(pcb); +        pcb->keep_cnt_sent++; +      } +    } + +    /* If this PCB has queued out of sequence data, but has been +       inactive for too long, will drop the data (it will eventually +       be retransmitted). */ +#if TCP_QUEUE_OOSEQ     +    if (pcb->ooseq != NULL && +        (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { +      tcp_segs_free(pcb->ooseq); +      pcb->ooseq = NULL; +      LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); +    } +#endif /* TCP_QUEUE_OOSEQ */ + +    /* Check if this PCB has stayed too long in SYN-RCVD */ +    if (pcb->state == SYN_RCVD) { +      if ((u32_t)(tcp_ticks - pcb->tmr) > +          TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { +        ++pcb_remove; +        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); +      } +    } + +    /* Check if this PCB has stayed too long in LAST-ACK */ +    if (pcb->state == LAST_ACK) { +      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { +        ++pcb_remove; +        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); +      } +    } + +    /* If the PCB should be removed, do it. */ +    if (pcb_remove) { +      tcp_pcb_purge(pcb);       +      /* Remove PCB from tcp_active_pcbs list. */ +      if (prev != NULL) { +        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); +        prev->next = pcb->next; +      } else { +        /* This PCB was the first. */ +        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); +        tcp_active_pcbs = pcb->next; +      } + +      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); + +      pcb2 = pcb->next; +      memp_free(MEMP_TCP_PCB, pcb); +      pcb = pcb2; +    } else { + +      /* We check if we should poll the connection. */ +      ++pcb->polltmr; +      if (pcb->polltmr >= pcb->pollinterval) { +        pcb->polltmr = 0; +        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); +        TCP_EVENT_POLL(pcb, err); +        if (err == ERR_OK) { +          tcp_output(pcb); +        } +      } +       +      prev = pcb; +      pcb = pcb->next; +    } +  } + +   +  /* Steps through all of the TIME-WAIT PCBs. */ +  prev = NULL;     +  pcb = tcp_tw_pcbs; +  while (pcb != NULL) { +    LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); +    pcb_remove = 0; + +    /* Check if this PCB has stayed long enough in TIME-WAIT */ +    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { +      ++pcb_remove; +    } +     + + +    /* If the PCB should be removed, do it. */ +    if (pcb_remove) { +      tcp_pcb_purge(pcb);       +      /* Remove PCB from tcp_tw_pcbs list. */ +      if (prev != NULL) { +        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); +        prev->next = pcb->next; +      } else { +        /* This PCB was the first. */ +        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); +        tcp_tw_pcbs = pcb->next; +      } +      pcb2 = pcb->next; +      memp_free(MEMP_TCP_PCB, pcb); +      pcb = pcb2; +    } else { +      prev = pcb; +      pcb = pcb->next; +    } +  } +} + +/** + * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously + * "refused" by upper layer (application) and sends delayed ACKs. + * + * Automatically called from tcp_tmr(). + */ +void +tcp_fasttmr(void) +{ +  struct tcp_pcb *pcb; + +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    /* If there is data which was previously "refused" by upper layer */ +    if (pcb->refused_data != NULL) { +      /* Notify again application with data previously received. */ +      err_t err; +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); +      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); +      if (err == ERR_OK) { +        pcb->refused_data = NULL; +      } +    } + +    /* send delayed ACKs */   +    if (pcb->flags & TF_ACK_DELAY) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); +      tcp_ack_now(pcb); +      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); +    } +  } +} + +/** + * Deallocates a list of TCP segments (tcp_seg structures). + * + * @param seg tcp_seg list of TCP segments to free + * @return the number of pbufs that were deallocated + */ +u8_t +tcp_segs_free(struct tcp_seg *seg) +{ +  u8_t count = 0; +  struct tcp_seg *next; +  while (seg != NULL) { +    next = seg->next; +    count += tcp_seg_free(seg); +    seg = next; +  } +  return count; +} + +/** + * Frees a TCP segment (tcp_seg structure). + * + * @param seg single tcp_seg to free + * @return the number of pbufs that were deallocated + */ +u8_t +tcp_seg_free(struct tcp_seg *seg) +{ +  u8_t count = 0; +   +  if (seg != NULL) { +    if (seg->p != NULL) { +      count = pbuf_free(seg->p); +#if TCP_DEBUG +      seg->p = NULL; +#endif /* TCP_DEBUG */ +    } +    memp_free(MEMP_TCP_SEG, seg); +  } +  return count; +} + +/** + * Sets the priority of a connection. + * + * @param pcb the tcp_pcb to manipulate + * @param prio new priority + */ +void +tcp_setprio(struct tcp_pcb *pcb, u8_t prio) +{ +  pcb->prio = prio; +} +#if TCP_QUEUE_OOSEQ + +/** + * Returns a copy of the given TCP segment. + * The pbuf and data are not copied, only the pointers + * + * @param seg the old tcp_seg + * @return a copy of seg + */  +struct tcp_seg * +tcp_seg_copy(struct tcp_seg *seg) +{ +  struct tcp_seg *cseg; + +  cseg = memp_malloc(MEMP_TCP_SEG); +  if (cseg == NULL) { +    return NULL; +  } +  SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg));  +  pbuf_ref(cseg->p); +  return cseg; +} +#endif + +#if LWIP_CALLBACK_API +/** + * Default receive callback that is called if the user didn't register + * a recv callback for the pcb. + */ +static err_t +tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ +  arg = arg; +  if (p != NULL) { +    pbuf_free(p); +  } else if (err == ERR_OK) { +    return tcp_close(pcb); +  } +  return ERR_OK; +} +#endif /* LWIP_CALLBACK_API */ + +/** + * Kills the oldest active connection that has lower priority than prio. + * + * @param prio minimum priority + */ +static void +tcp_kill_prio(u8_t prio) +{ +  struct tcp_pcb *pcb, *inactive; +  u32_t inactivity; +  u8_t mprio; + + +  mprio = TCP_PRIO_MAX; +   +  /* We kill the oldest active connection that has lower priority than prio. */ +  inactivity = 0; +  inactive = NULL; +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    if (pcb->prio <= prio && +       pcb->prio <= mprio && +       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { +      inactivity = tcp_ticks - pcb->tmr; +      inactive = pcb; +      mprio = pcb->prio; +    } +  } +  if (inactive != NULL) { +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", +           (void *)inactive, inactivity)); +    tcp_abort(inactive); +  }       +} + +/** + * Kills the oldest connection that is in TIME_WAIT state. + * Called from tcp_alloc() if no more connections are available. + */ +static void +tcp_kill_timewait(void) +{ +  struct tcp_pcb *pcb, *inactive; +  u32_t inactivity; + +  inactivity = 0; +  inactive = NULL; +  /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ +  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { +    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { +      inactivity = tcp_ticks - pcb->tmr; +      inactive = pcb; +    } +  } +  if (inactive != NULL) { +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", +           (void *)inactive, inactivity)); +    tcp_abort(inactive); +  }       +} + +/** + * Allocate a new tcp_pcb structure. + * + * @param prio priority for the new pcb + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_alloc(u8_t prio) +{ +  struct tcp_pcb *pcb; +  u32_t iss; +   +  pcb = memp_malloc(MEMP_TCP_PCB); +  if (pcb == NULL) { +    /* Try killing oldest connection in TIME-WAIT. */ +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); +    tcp_kill_timewait(); +    /* Try to allocate a tcp_pcb again. */ +    pcb = memp_malloc(MEMP_TCP_PCB); +    if (pcb == NULL) { +      /* Try killing active connections with lower priority than the new one. */ +      tcp_kill_prio(prio); +      /* Try to allocate a tcp_pcb again. */ +      pcb = memp_malloc(MEMP_TCP_PCB); +    } +  } +  if (pcb != NULL) { +    memset(pcb, 0, sizeof(struct tcp_pcb)); +    pcb->prio = TCP_PRIO_NORMAL; +    pcb->snd_buf = TCP_SND_BUF; +    pcb->snd_queuelen = 0; +    pcb->rcv_wnd = TCP_WND; +    pcb->rcv_ann_wnd = TCP_WND; +    pcb->tos = 0; +    pcb->ttl = TCP_TTL; +    /* As initial send MSS, we use TCP_MSS but limit it to 536. +       The send MSS is updated when an MSS option is received. */ +    pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; +    pcb->rto = 3000 / TCP_SLOW_INTERVAL; +    pcb->sa = 0; +    pcb->sv = 3000 / TCP_SLOW_INTERVAL; +    pcb->rtime = -1; +    pcb->cwnd = 1; +    iss = tcp_next_iss(); +    pcb->snd_wl2 = iss; +    pcb->snd_nxt = iss; +    pcb->lastack = iss; +    pcb->snd_lbb = iss;    +    pcb->tmr = tcp_ticks; + +    pcb->polltmr = 0; + +#if LWIP_CALLBACK_API +    pcb->recv = tcp_recv_null; +#endif /* LWIP_CALLBACK_API */   +     +    /* Init KEEPALIVE timer */ +    pcb->keep_idle  = TCP_KEEPIDLE_DEFAULT; +     +#if LWIP_TCP_KEEPALIVE +    pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; +    pcb->keep_cnt   = TCP_KEEPCNT_DEFAULT; +#endif /* LWIP_TCP_KEEPALIVE */ + +    pcb->keep_cnt_sent = 0; +  } +  return pcb; +} + +/** + * Creates a new TCP protocol control block but doesn't place it on + * any of the TCP PCB lists. + * The pcb is not put on any list until binding using tcp_bind(). + * + * @internal: Maybe there should be a idle TCP PCB list where these + * PCBs are put on. Port reservation using tcp_bind() is implemented but + * allocated pcbs that are not bound can't be killed automatically if wanting + * to allocate a pcb with higher prio (@see tcp_kill_prio()) + * + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new(void) +{ +  return tcp_alloc(TCP_PRIO_NORMAL); +} + +/** + * Used to specify the argument that should be passed callback + * functions. + * + * @param pcb tcp_pcb to set the callback argument + * @param arg void pointer argument to pass to callback functions + */  +void +tcp_arg(struct tcp_pcb *pcb, void *arg) +{   +  pcb->callback_arg = arg; +} +#if LWIP_CALLBACK_API + +/** + * Used to specify the function that should be called when a TCP + * connection receives data. + * + * @param pcb tcp_pcb to set the recv callback + * @param recv callback function to call for this pcb when data is received + */  +void +tcp_recv(struct tcp_pcb *pcb, +   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) +{ +  pcb->recv = recv; +} + +/** + * Used to specify the function that should be called when TCP data + * has been successfully delivered to the remote host. + * + * @param pcb tcp_pcb to set the sent callback + * @param sent callback function to call for this pcb when data is successfully sent + */  +void +tcp_sent(struct tcp_pcb *pcb, +   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) +{ +  pcb->sent = sent; +} + +/** + * Used to specify the function that should be called when a fatal error + * has occured on the connection. + * + * @param pcb tcp_pcb to set the err callback + * @param errf callback function to call for this pcb when a fatal error + *        has occured on the connection + */  +void +tcp_err(struct tcp_pcb *pcb, +   void (* errf)(void *arg, err_t err)) +{ +  pcb->errf = errf; +} + +/** + * Used for specifying the function that should be called when a + * LISTENing connection has been connected to another host. + * + * @param pcb tcp_pcb to set the accept callback + * @param accept callback function to call for this pcb when LISTENing + *        connection has been connected to another host + */  +void +tcp_accept(struct tcp_pcb *pcb, +     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) +{ +  pcb->accept = accept; +} +#endif /* LWIP_CALLBACK_API */ + + +/** + * Used to specify the function that should be called periodically + * from TCP. The interval is specified in terms of the TCP coarse + * timer interval, which is called twice a second. + * + */  +void +tcp_poll(struct tcp_pcb *pcb, +   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) +{ +#if LWIP_CALLBACK_API +  pcb->poll = poll; +#endif /* LWIP_CALLBACK_API */   +  pcb->pollinterval = interval; +} + +/** + * Purges a TCP PCB. Removes any buffered data and frees the buffer memory + * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). + * + * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! + */ +void +tcp_pcb_purge(struct tcp_pcb *pcb) +{ +  if (pcb->state != CLOSED && +     pcb->state != TIME_WAIT && +     pcb->state != LISTEN) { + +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); + +#if TCP_LISTEN_BACKLOG +    if (pcb->state == SYN_RCVD) { +      /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ +      struct tcp_pcb_listen *lpcb; +      LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL", +        tcp_listen_pcbs.listen_pcbs != NULL); +      for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { +        if ((lpcb->local_port == pcb->local_port) && +            (ip_addr_isany(&lpcb->local_ip) || +             ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) { +            /* port and address of the listen pcb match the timed-out pcb */ +            LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", +              lpcb->accepts_pending > 0); +            lpcb->accepts_pending--; +            break; +          } +      } +    } +#endif /* TCP_LISTEN_BACKLOG */ + + +    if (pcb->refused_data != NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); +      pbuf_free(pcb->refused_data); +      pcb->refused_data = NULL; +    } +    if (pcb->unsent != NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); +    } +    if (pcb->unacked != NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); +    } +#if TCP_QUEUE_OOSEQ /* LW */ +    if (pcb->ooseq != NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); +    } + +    /* Stop the retransmission timer as it will expect data on unacked +       queue if it fires */ +    pcb->rtime = -1; + +    tcp_segs_free(pcb->ooseq); +    pcb->ooseq = NULL; +#endif /* TCP_QUEUE_OOSEQ */ +    tcp_segs_free(pcb->unsent); +    tcp_segs_free(pcb->unacked); +    pcb->unacked = pcb->unsent = NULL; +  } +} + +/** + * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. + * + * @param pcblist PCB list to purge. + * @param pcb tcp_pcb to purge. The pcb itself is also deallocated! + */ +void +tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) +{ +  TCP_RMV(pcblist, pcb); + +  tcp_pcb_purge(pcb); +   +  /* if there is an outstanding delayed ACKs, send it */ +  if (pcb->state != TIME_WAIT && +     pcb->state != LISTEN && +     pcb->flags & TF_ACK_DELAY) { +    pcb->flags |= TF_ACK_NOW; +    tcp_output(pcb); +  } + +  if (pcb->state != LISTEN) { +    LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); +    LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); +#if TCP_QUEUE_OOSEQ +    LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); +#endif /* TCP_QUEUE_OOSEQ */ +  } + +  pcb->state = CLOSED; + +  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); +} + +/** + * Calculates a new initial sequence number for new connections. + * + * @return u32_t pseudo random sequence number + */ +u32_t +tcp_next_iss(void) +{ +  static u32_t iss = 6510; +   +  iss += tcp_ticks;       /* XXX */ +  return iss; +} + +#if TCP_CALCULATE_EFF_SEND_MSS +/** + * Calcluates the effective send mss that can be used for a specific IP address + * by using ip_route to determin the netif used to send to the address and + * calculating the minimum of TCP_MSS and that netif's mtu (if set). + */ +u16_t +tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr) +{ +  u16_t mss_s; +  struct netif *outif; + +  outif = ip_route(addr); +  if ((outif != NULL) && (outif->mtu != 0)) { +    mss_s = outif->mtu - IP_HLEN - TCP_HLEN; +    /* RFC 1122, chap 4.2.2.6: +     * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize +     * We correct for TCP options in tcp_enqueue(), and don't support +     * IP options +     */ +    sendmss = LWIP_MIN(sendmss, mss_s); +  } +  return sendmss; +} +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +/** + * Print a tcp header for debugging purposes. + * + * @param tcphdr pointer to a struct tcp_hdr + */ +void +tcp_debug_print(struct tcp_hdr *tcphdr) +{ +  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); +  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n", +         ntohs(tcphdr->src), ntohs(tcphdr->dest))); +  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n", +          ntohl(tcphdr->seqno))); +  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n", +         ntohl(tcphdr->ackno))); +  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (", +       TCPH_HDRLEN(tcphdr), +         TCPH_FLAGS(tcphdr) >> 5 & 1, +         TCPH_FLAGS(tcphdr) >> 4 & 1, +         TCPH_FLAGS(tcphdr) >> 3 & 1, +         TCPH_FLAGS(tcphdr) >> 2 & 1, +         TCPH_FLAGS(tcphdr) >> 1 & 1, +         TCPH_FLAGS(tcphdr) & 1, +         ntohs(tcphdr->wnd))); +  tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); +  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); +  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n", +         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); +  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); +} + +/** + * Print a tcp state for debugging purposes. + * + * @param s enum tcp_state to print + */ +void +tcp_debug_print_state(enum tcp_state s) +{ +  LWIP_DEBUGF(TCP_DEBUG, ("State: ")); +  switch (s) { +  case CLOSED: +    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n")); +    break; + case LISTEN: +   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n")); +   break; +  case SYN_SENT: +    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n")); +    break; +  case SYN_RCVD: +    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n")); +    break; +  case ESTABLISHED: +    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n")); +    break; +  case FIN_WAIT_1: +    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n")); +    break; +  case FIN_WAIT_2: +    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n")); +    break; +  case CLOSE_WAIT: +    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n")); +    break; +  case CLOSING: +    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n")); +    break; +  case LAST_ACK: +    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n")); +    break; +  case TIME_WAIT: +    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n")); +   break; +  } +} + +/** + * Print tcp flags for debugging purposes. + * + * @param flags tcp flags, all active flags are printed + */ +void +tcp_debug_print_flags(u8_t flags) +{ +  if (flags & TCP_FIN) { +    LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); +  } +  if (flags & TCP_SYN) { +    LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); +  } +  if (flags & TCP_RST) { +    LWIP_DEBUGF(TCP_DEBUG, ("RST ")); +  } +  if (flags & TCP_PSH) { +    LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); +  } +  if (flags & TCP_ACK) { +    LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); +  } +  if (flags & TCP_URG) { +    LWIP_DEBUGF(TCP_DEBUG, ("URG ")); +  } +  if (flags & TCP_ECE) { +    LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); +  } +  if (flags & TCP_CWR) { +    LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); +  } +  LWIP_DEBUGF(TCP_DEBUG, ("\n")); +} + +/** + * Print all tcp_pcbs in every list for debugging purposes. + */ +void +tcp_debug_print_pcbs(void) +{ +  struct tcp_pcb *pcb; +  LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", +                       pcb->local_port, pcb->remote_port, +                       pcb->snd_nxt, pcb->rcv_nxt)); +    tcp_debug_print_state(pcb->state); +  }     +  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); +  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { +    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", +                       pcb->local_port, pcb->remote_port, +                       pcb->snd_nxt, pcb->rcv_nxt)); +    tcp_debug_print_state(pcb->state); +  }     +  LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); +  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { +    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", +                       pcb->local_port, pcb->remote_port, +                       pcb->snd_nxt, pcb->rcv_nxt)); +    tcp_debug_print_state(pcb->state); +  }     +} + +/** + * Check state consistency of the tcp_pcb lists. + */ +s16_t +tcp_pcbs_sane(void) +{ +  struct tcp_pcb *pcb; +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); +    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); +    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); +  } +  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { +    LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); +  } +  return 1; +} +#endif /* TCP_DEBUG */ + +#endif /* LWIP_TCP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp_in.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp_in.c new file mode 100644 index 000000000..362a4a62d --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp_in.c @@ -0,0 +1,1419 @@ +/** + * @file + * Transmission Control Protocol, incoming traffic + * + * The input processing functions of the TCP layer. + * + * These functions are generally called in the order (ip_input() ->) + * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). + *  + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "arch/perf.h" + +/* These variables are global to all functions involved in the input +   processing of TCP segments. They are set by the tcp_input() +   function. */ +static struct tcp_seg inseg; +static struct tcp_hdr *tcphdr; +static struct ip_hdr *iphdr; +static u32_t seqno, ackno; +static u8_t flags; +static u16_t tcplen; + +static u8_t recv_flags; +static struct pbuf *recv_data; + +struct tcp_pcb *tcp_input_pcb; + +/* Forward declarations. */ +static err_t tcp_process(struct tcp_pcb *pcb); +static u8_t tcp_receive(struct tcp_pcb *pcb); +static void tcp_parseopt(struct tcp_pcb *pcb); + +static err_t tcp_listen_input(struct tcp_pcb_listen *pcb); +static err_t tcp_timewait_input(struct tcp_pcb *pcb); + +/** + * The initial input processing of TCP. It verifies the TCP header, demultiplexes + * the segment between the PCBs and passes it on to tcp_process(), which implements + * the TCP finite state machine. This function is called by the IP layer (in + * ip_input()). + * + * @param p received TCP segment to process (p->payload pointing to the IP header) + * @param inp network interface on which this segment was received + */ +void +tcp_input(struct pbuf *p, struct netif *inp) +{ +  struct tcp_pcb *pcb, *prev; +  struct tcp_pcb_listen *lpcb; +  u8_t hdrlen; +  err_t err; + +  PERF_START; + +  TCP_STATS_INC(tcp.recv); +  snmp_inc_tcpinsegs(); + +  iphdr = p->payload; +  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); + +#if TCP_INPUT_DEBUG +  tcp_debug_print(tcphdr); +#endif + +  /* remove header from payload */ +  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) { +    /* drop short packets */ +    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); +    TCP_STATS_INC(tcp.lenerr); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } + +  /* Don't even process incoming broadcasts/multicasts. */ +  if (ip_addr_isbroadcast(&(iphdr->dest), inp) || +      ip_addr_ismulticast(&(iphdr->dest))) { +    TCP_STATS_INC(tcp.proterr); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } + +#if CHECKSUM_CHECK_TCP +  /* Verify TCP checksum. */ +  if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), +      (struct ip_addr *)&(iphdr->dest), +      IP_PROTO_TCP, p->tot_len) != 0) { +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", +        inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), +      IP_PROTO_TCP, p->tot_len))); +#if TCP_DEBUG +    tcp_debug_print(tcphdr); +#endif /* TCP_DEBUG */ +    TCP_STATS_INC(tcp.chkerr); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } +#endif + +  /* Move the payload pointer in the pbuf so that it points to the +     TCP data instead of the TCP header. */ +  hdrlen = TCPH_HDRLEN(tcphdr); +  if(pbuf_header(p, -(hdrlen * 4))){ +    /* drop short packets */ +    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); +    TCP_STATS_INC(tcp.lenerr); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } + +  /* Convert fields in TCP header to host byte order. */ +  tcphdr->src = ntohs(tcphdr->src); +  tcphdr->dest = ntohs(tcphdr->dest); +  seqno = tcphdr->seqno = ntohl(tcphdr->seqno); +  ackno = tcphdr->ackno = ntohl(tcphdr->ackno); +  tcphdr->wnd = ntohs(tcphdr->wnd); + +  flags = TCPH_FLAGS(tcphdr); +  tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); + +  /* Demultiplex an incoming segment. First, we check if it is destined +     for an active connection. */ +  prev = NULL; + +   +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); +    LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); +    LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); +    if (pcb->remote_port == tcphdr->src && +       pcb->local_port == tcphdr->dest && +       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && +       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + +      /* Move this PCB to the front of the list so that subsequent +         lookups will be faster (we exploit locality in TCP segment +         arrivals). */ +      LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); +      if (prev != NULL) { +        prev->next = pcb->next; +        pcb->next = tcp_active_pcbs; +        tcp_active_pcbs = pcb; +      } +      LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); +      break; +    } +    prev = pcb; +  } + +  if (pcb == NULL) { +    /* If it did not go to an active connection, we check the connections +       in the TIME-WAIT state. */ +    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { +      LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); +      if (pcb->remote_port == tcphdr->src && +         pcb->local_port == tcphdr->dest && +         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && +         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { +        /* We don't really care enough to move this PCB to the front +           of the list since we are not very likely to receive that +           many segments for connections in TIME-WAIT. */ +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); +        tcp_timewait_input(pcb); +        pbuf_free(p); +        return; +      } +    } + +  /* Finally, if we still did not get a match, we check all PCBs that +     are LISTENing for incoming connections. */ +    prev = NULL; +    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { +      if ((ip_addr_isany(&(lpcb->local_ip)) || +        ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) && +        lpcb->local_port == tcphdr->dest) { +        /* Move this PCB to the front of the list so that subsequent +           lookups will be faster (we exploit locality in TCP segment +           arrivals). */ +        if (prev != NULL) { +          ((struct tcp_pcb_listen *)prev)->next = lpcb->next; +                /* our successor is the remainder of the listening list */ +          lpcb->next = tcp_listen_pcbs.listen_pcbs; +                /* put this listening pcb at the head of the listening list */ +          tcp_listen_pcbs.listen_pcbs = lpcb; +        } +       +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); +        tcp_listen_input(lpcb); +        pbuf_free(p); +        return; +      } +      prev = (struct tcp_pcb *)lpcb; +    } +  } + +#if TCP_INPUT_DEBUG +  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); +  tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); +  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); +#endif /* TCP_INPUT_DEBUG */ + + +  if (pcb != NULL) { +    /* The incoming segment belongs to a connection. */ +#if TCP_INPUT_DEBUG +#if TCP_DEBUG +    tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ + +    /* Set up a tcp_seg structure. */ +    inseg.next = NULL; +    inseg.len = p->tot_len; +    inseg.dataptr = p->payload; +    inseg.p = p; +    inseg.tcphdr = tcphdr; + +    recv_data = NULL; +    recv_flags = 0; + +    /* If there is data which was previously "refused" by upper layer */ +    if (pcb->refused_data != NULL) { +      /* Notify again application with data previously received. */ +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); +      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); +      if (err == ERR_OK) { +        pcb->refused_data = NULL; +      } else { +        /* drop incoming packets, because pcb is "full" */ +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); +        TCP_STATS_INC(tcp.drop); +        snmp_inc_tcpinerrs(); +        pbuf_free(p); +        return; +      } +    } + +    tcp_input_pcb = pcb; +    err = tcp_process(pcb); +    tcp_input_pcb = NULL; +    /* A return value of ERR_ABRT means that tcp_abort() was called +       and that the pcb has been freed. If so, we don't do anything. */ +    if (err != ERR_ABRT) { +      if (recv_flags & TF_RESET) { +        /* TF_RESET means that the connection was reset by the other +           end. We then call the error callback to inform the +           application that the connection is dead before we +           deallocate the PCB. */ +        TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); +        tcp_pcb_remove(&tcp_active_pcbs, pcb); +        memp_free(MEMP_TCP_PCB, pcb); +      } else if (recv_flags & TF_CLOSED) { +        /* The connection has been closed and we will deallocate the +           PCB. */ +        tcp_pcb_remove(&tcp_active_pcbs, pcb); +        memp_free(MEMP_TCP_PCB, pcb); +      } else { +        err = ERR_OK; +        /* If the application has registered a "sent" function to be +           called when new send buffer space is available, we call it +           now. */ +        if (pcb->acked > 0) { +          TCP_EVENT_SENT(pcb, pcb->acked, err); +        } +       +        if (recv_data != NULL) { +          if(flags & TCP_PSH) { +            recv_data->flags |= PBUF_FLAG_PUSH; +          } + +          /* Notify application that data has been received. */ +          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + +          /* If the upper layer can't receive this data, store it */ +          if (err != ERR_OK) { +            pcb->refused_data = recv_data; +            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); +          } +        } + +        /* If a FIN segment was received, we call the callback +           function with a NULL buffer to indicate EOF. */ +        if (recv_flags & TF_GOT_FIN) { +          TCP_EVENT_RECV(pcb, NULL, ERR_OK, err); +        } + +        /* If there were no errors, we try to send something out. */ +        if (err == ERR_OK) { +          tcp_output(pcb); +        } +      } +    } + + +    /* give up our reference to inseg.p */ +    if (inseg.p != NULL) +    { +      pbuf_free(inseg.p); +      inseg.p = NULL; +    } +#if TCP_INPUT_DEBUG +#if TCP_DEBUG +    tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ +       +  } else { + +    /* If no matching PCB was found, send a TCP RST (reset) to the +       sender. */ +    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); +    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { +      TCP_STATS_INC(tcp.proterr); +      TCP_STATS_INC(tcp.drop); +      tcp_rst(ackno, seqno + tcplen, +        &(iphdr->dest), &(iphdr->src), +        tcphdr->dest, tcphdr->src); +    } +    pbuf_free(p); +  } + +  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); +  PERF_STOP("tcp_input"); +} + +/** + * Called by tcp_input() when a segment arrives for a listening + * connection (from tcp_input()). + * + * @param pcb the tcp_pcb_listen for which a segment arrived + * @return ERR_OK if the segment was processed + *         another err_t on error + * + * @note the return value is not (yet?) used in tcp_input() + * @note the segment which arrived is saved in global variables, therefore only the pcb + *       involved is passed as a parameter to this function + */ +static err_t +tcp_listen_input(struct tcp_pcb_listen *pcb) +{ +  struct tcp_pcb *npcb; +  err_t rc; + +  /* In the LISTEN state, we check for incoming SYN segments, +     creates a new PCB, and responds with a SYN|ACK. */ +  if (flags & TCP_ACK) { +    /* For incoming segments with the ACK flag set, respond with a +       RST. */ +    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); +    tcp_rst(ackno + 1, seqno + tcplen, +      &(iphdr->dest), &(iphdr->src), +      tcphdr->dest, tcphdr->src); +  } else if (flags & TCP_SYN) { +    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); +#if TCP_LISTEN_BACKLOG +    if (pcb->accepts_pending >= pcb->backlog) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); +      return ERR_ABRT; +    } +#endif /* TCP_LISTEN_BACKLOG */ +    npcb = tcp_alloc(pcb->prio); +    /* If a new PCB could not be created (probably due to lack of memory), +       we don't do anything, but rely on the sender will retransmit the +       SYN at a time when we have more memory available. */ +    if (npcb == NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); +      TCP_STATS_INC(tcp.memerr); +      return ERR_MEM; +    } +#if TCP_LISTEN_BACKLOG +    pcb->accepts_pending++; +#endif /* TCP_LISTEN_BACKLOG */ +    /* Set up the new PCB. */ +    ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); +    npcb->local_port = pcb->local_port; +    ip_addr_set(&(npcb->remote_ip), &(iphdr->src)); +    npcb->remote_port = tcphdr->src; +    npcb->state = SYN_RCVD; +    npcb->rcv_nxt = seqno + 1; +    npcb->rcv_ann_right_edge = npcb->rcv_nxt; +    npcb->snd_wnd = tcphdr->wnd; +    npcb->ssthresh = npcb->snd_wnd; +    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ +    npcb->callback_arg = pcb->callback_arg; +#if LWIP_CALLBACK_API +    npcb->accept = pcb->accept; +#endif /* LWIP_CALLBACK_API */ +    /* inherit socket options */ +    npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); +    /* Register the new PCB so that we can begin receiving segments +       for it. */ +    TCP_REG(&tcp_active_pcbs, npcb); + +    /* Parse any options in the SYN. */ +    tcp_parseopt(npcb); +#if TCP_CALCULATE_EFF_SEND_MSS +    npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +    snmp_inc_tcppassiveopens(); + +    /* Send a SYN|ACK together with the MSS option. */ +    rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS +#if LWIP_TCP_TIMESTAMPS +      /* and maybe include the TIMESTAMP option */ +     | (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0) +#endif +      ); +    if (rc != ERR_OK) { +      tcp_abandon(npcb, 0); +      return rc; +    } +    return tcp_output(npcb); +  } +  return ERR_OK; +} + +/** + * Called by tcp_input() when a segment arrives for a connection in + * TIME_WAIT. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + *       involved is passed as a parameter to this function + */ +static err_t +tcp_timewait_input(struct tcp_pcb *pcb) +{ +  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) { +    pcb->rcv_nxt = seqno + tcplen; +  } +  if (tcplen > 0) { +    tcp_ack_now(pcb); +  } +  return tcp_output(pcb); +} + +/** + * Implements the TCP state machine. Called by tcp_input. In some + * states tcp_receive() is called to receive data. The tcp_seg + * argument will be freed by the caller (tcp_input()) unless the + * recv_data pointer in the pcb is set. + * + * @param pcb the tcp_pcb for which a segment arrived + * + * @note the segment which arrived is saved in global variables, therefore only the pcb + *       involved is passed as a parameter to this function + */ +static err_t +tcp_process(struct tcp_pcb *pcb) +{ +  struct tcp_seg *rseg; +  u8_t acceptable = 0; +  err_t err; + +  err = ERR_OK; + +  /* Process incoming RST segments. */ +  if (flags & TCP_RST) { +    /* First, determine if the reset is acceptable. */ +    if (pcb->state == SYN_SENT) { +      if (ackno == pcb->snd_nxt) { +        acceptable = 1; +      } +    } else { +      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,  +                          pcb->rcv_nxt+pcb->rcv_wnd)) { +        acceptable = 1; +      } +    } + +    if (acceptable) { +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); +      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); +      recv_flags |= TF_RESET; +      pcb->flags &= ~TF_ACK_DELAY; +      return ERR_RST; +    } else { +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", +       seqno, pcb->rcv_nxt)); +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", +       seqno, pcb->rcv_nxt)); +      return ERR_OK; +    } +  } + +  if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {  +    /* Cope with new connection attempt after remote end crashed */ +    tcp_ack_now(pcb); +    return ERR_OK; +  } +   +  /* Update the PCB (in)activity timer. */ +  pcb->tmr = tcp_ticks; +  pcb->keep_cnt_sent = 0; + +  tcp_parseopt(pcb); + +  /* Do different things depending on the TCP state. */ +  switch (pcb->state) { +  case SYN_SENT: +    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, +     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); +    /* received SYN ACK with expected sequence number? */ +    if ((flags & TCP_ACK) && (flags & TCP_SYN) +        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { +      pcb->snd_buf++; +      pcb->rcv_nxt = seqno + 1; +      pcb->rcv_ann_right_edge = pcb->rcv_nxt; +      pcb->lastack = ackno; +      pcb->snd_wnd = tcphdr->wnd; +      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ +      pcb->state = ESTABLISHED; + +#if TCP_CALCULATE_EFF_SEND_MSS +      pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +      /* Set ssthresh again after changing pcb->mss (already set in tcp_connect +       * but for the default value of pcb->mss) */ +      pcb->ssthresh = pcb->mss * 10; + +      pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss); +      LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); +      --pcb->snd_queuelen; +      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); +      rseg = pcb->unacked; +      pcb->unacked = rseg->next; + +      /* If there's nothing left to acknowledge, stop the retransmit +         timer, otherwise reset it to start again */ +      if(pcb->unacked == NULL) +        pcb->rtime = -1; +      else { +        pcb->rtime = 0; +        pcb->nrtx = 0; +      } + +      tcp_seg_free(rseg); + +      /* Call the user specified function to call when sucessfully +       * connected. */ +      TCP_EVENT_CONNECTED(pcb, ERR_OK, err); +      tcp_ack_now(pcb); +    } +    /* received ACK? possibly a half-open connection */ +    else if (flags & TCP_ACK) { +      /* send a RST to bring the other side in a non-synchronized state. */ +      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), +        tcphdr->dest, tcphdr->src); +    } +    break; +  case SYN_RCVD: +    if (flags & TCP_ACK) { +      /* expected ACK number? */ +      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { +        u16_t old_cwnd; +        pcb->state = ESTABLISHED; +        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +#if LWIP_CALLBACK_API +        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); +#endif +        /* Call the accept function. */ +        TCP_EVENT_ACCEPT(pcb, ERR_OK, err); +        if (err != ERR_OK) { +          /* If the accept function returns with an error, we abort +           * the connection. */ +          tcp_abort(pcb); +          return ERR_ABRT; +        } +        old_cwnd = pcb->cwnd; +        /* If there was any data contained within this ACK, +         * we'd better pass it on to the application as well. */ +        tcp_receive(pcb); + +        pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); + +        if (recv_flags & TF_GOT_FIN) { +          tcp_ack_now(pcb); +          pcb->state = CLOSE_WAIT; +        } +      } +      /* incorrect ACK number */ +      else { +        /* send RST */ +        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), +                tcphdr->dest, tcphdr->src); +      } +    } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { +      /* Looks like another copy of the SYN - retransmit our SYN-ACK */ +      tcp_rexmit(pcb); +    } +    break; +  case CLOSE_WAIT: +    /* FALLTHROUGH */ +  case ESTABLISHED: +    tcp_receive(pcb); +    if (recv_flags & TF_GOT_FIN) { /* passive close */ +      tcp_ack_now(pcb); +      pcb->state = CLOSE_WAIT; +    } +    break; +  case FIN_WAIT_1: +    tcp_receive(pcb); +    if (recv_flags & TF_GOT_FIN) { +      if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { +        LWIP_DEBUGF(TCP_DEBUG, +          ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +        tcp_ack_now(pcb); +        tcp_pcb_purge(pcb); +        TCP_RMV(&tcp_active_pcbs, pcb); +        pcb->state = TIME_WAIT; +        TCP_REG(&tcp_tw_pcbs, pcb); +      } else { +        tcp_ack_now(pcb); +        pcb->state = CLOSING; +      } +    } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { +      pcb->state = FIN_WAIT_2; +    } +    break; +  case FIN_WAIT_2: +    tcp_receive(pcb); +    if (recv_flags & TF_GOT_FIN) { +      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +      tcp_ack_now(pcb); +      tcp_pcb_purge(pcb); +      TCP_RMV(&tcp_active_pcbs, pcb); +      pcb->state = TIME_WAIT; +      TCP_REG(&tcp_tw_pcbs, pcb); +    } +    break; +  case CLOSING: +    tcp_receive(pcb); +    if (flags & TCP_ACK && ackno == pcb->snd_nxt) { +      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +      tcp_pcb_purge(pcb); +      TCP_RMV(&tcp_active_pcbs, pcb); +      pcb->state = TIME_WAIT; +      TCP_REG(&tcp_tw_pcbs, pcb); +    } +    break; +  case LAST_ACK: +    tcp_receive(pcb); +    if (flags & TCP_ACK && ackno == pcb->snd_nxt) { +      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +      /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ +      recv_flags |= TF_CLOSED; +    } +    break; +  default: +    break; +  } +  return ERR_OK; +} + +/** + * Called by tcp_process. Checks if the given segment is an ACK for outstanding + * data, and if so frees the memory of the buffered data. Next, is places the + * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment + * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until + * i it has been removed from the buffer. + * + * If the incoming segment constitutes an ACK for a segment that was used for RTT + * estimation, the RTT is estimated here as well. + * + * Called from tcp_process(). + * + * @return 1 if the incoming segment is the next in sequence, 0 if not + */ +static u8_t +tcp_receive(struct tcp_pcb *pcb) +{ +  struct tcp_seg *next; +#if TCP_QUEUE_OOSEQ +  struct tcp_seg *prev, *cseg; +#endif +  struct pbuf *p; +  s32_t off; +  s16_t m; +  u32_t right_wnd_edge; +  u16_t new_tot_len; +  u8_t accepted_inseq = 0; + +  if (flags & TCP_ACK) { +    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; + +    /* Update window. */ +    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || +       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || +       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { +      pcb->snd_wnd = tcphdr->wnd; +      pcb->snd_wl1 = seqno; +      pcb->snd_wl2 = ackno; +      if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) { +          pcb->persist_backoff = 0; +      } +      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); +#if TCP_WND_DEBUG +    } else { +      if (pcb->snd_wnd != tcphdr->wnd) { +        LWIP_DEBUGF(TCP_WND_DEBUG,  +                    ("tcp_receive: no window update lastack %"U32_F" ackno %" +                     U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", +                     pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); +      } +#endif /* TCP_WND_DEBUG */ +    } + +    if (pcb->lastack == ackno) { +      pcb->acked = 0; + +      if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ +        ++pcb->dupacks; +        if (pcb->dupacks >= 3 && pcb->unacked != NULL) { +          if (!(pcb->flags & TF_INFR)) { +            /* This is fast retransmit. Retransmit the first unacked segment. */ +            LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n", +                                       (u16_t)pcb->dupacks, pcb->lastack, +                                       ntohl(pcb->unacked->tcphdr->seqno))); +            tcp_rexmit(pcb); +            /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */ +            /*pcb->ssthresh = LWIP_MAX((pcb->snd_max - +                                      pcb->lastack) / 2, +                                      2 * pcb->mss);*/ +            /* Set ssthresh to half of the minimum of the current cwnd and the advertised window */ +            if (pcb->cwnd > pcb->snd_wnd) +              pcb->ssthresh = pcb->snd_wnd / 2; +            else +              pcb->ssthresh = pcb->cwnd / 2; + +            /* The minimum value for ssthresh should be 2 MSS */ +            if (pcb->ssthresh < 2*pcb->mss) { +              LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F" should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss)); +              pcb->ssthresh = 2*pcb->mss; +            } + +            pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; +            pcb->flags |= TF_INFR; +          } else { +            /* Inflate the congestion window, but not if it means that +               the value overflows. */ +            if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { +              pcb->cwnd += pcb->mss; +            } +          } +        } +      } else { +        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n", +                                   pcb->snd_wl2 + pcb->snd_wnd, right_wnd_edge)); +      } +    } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){ +      /* We come here when the ACK acknowledges new data. */ +       +      /* Reset the "IN Fast Retransmit" flag, since we are no longer +         in fast retransmit. Also reset the congestion window to the +         slow start threshold. */ +      if (pcb->flags & TF_INFR) { +        pcb->flags &= ~TF_INFR; +        pcb->cwnd = pcb->ssthresh; +      } + +      /* Reset the number of retransmissions. */ +      pcb->nrtx = 0; + +      /* Reset the retransmission time-out. */ +      pcb->rto = (pcb->sa >> 3) + pcb->sv; + +      /* Update the send buffer space. Diff between the two can never exceed 64K? */ +      pcb->acked = (u16_t)(ackno - pcb->lastack); + +      pcb->snd_buf += pcb->acked; + +      /* Reset the fast retransmit variables. */ +      pcb->dupacks = 0; +      pcb->lastack = ackno; + +      /* Update the congestion control variables (cwnd and +         ssthresh). */ +      if (pcb->state >= ESTABLISHED) { +        if (pcb->cwnd < pcb->ssthresh) { +          if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { +            pcb->cwnd += pcb->mss; +          } +          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd)); +        } else { +          u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); +          if (new_cwnd > pcb->cwnd) { +            pcb->cwnd = new_cwnd; +          } +          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd)); +        } +      } +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", +                                    ackno, +                                    pcb->unacked != NULL? +                                    ntohl(pcb->unacked->tcphdr->seqno): 0, +                                    pcb->unacked != NULL? +                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); + +      /* Remove segment from the unacknowledged list if the incoming +         ACK acknowlegdes them. */ +      while (pcb->unacked != NULL && +             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + +                         TCP_TCPLEN(pcb->unacked), ackno)) { +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", +                                      ntohl(pcb->unacked->tcphdr->seqno), +                                      ntohl(pcb->unacked->tcphdr->seqno) + +                                      TCP_TCPLEN(pcb->unacked))); + +        next = pcb->unacked; +        pcb->unacked = pcb->unacked->next; + +        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); +        LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); +        pcb->snd_queuelen -= pbuf_clen(next->p); +        tcp_seg_free(next); + +        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen)); +        if (pcb->snd_queuelen != 0) { +          LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || +                      pcb->unsent != NULL); +        } +      } + +      /* If there's nothing left to acknowledge, stop the retransmit +         timer, otherwise reset it to start again */ +      if(pcb->unacked == NULL) +        pcb->rtime = -1; +      else +        pcb->rtime = 0; + +      pcb->polltmr = 0; +    } else { +      /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */ +      pcb->acked = 0; +    } + +    /* We go through the ->unsent list to see if any of the segments +       on the list are acknowledged by the ACK. This may seem +       strange since an "unsent" segment shouldn't be acked. The +       rationale is that lwIP puts all outstanding segments on the +       ->unsent list after a retransmission, so these segments may +       in fact have been sent once. */ +    while (pcb->unsent != NULL && +           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +  +                           TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", +                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + +                                    TCP_TCPLEN(pcb->unsent))); + +      next = pcb->unsent; +      pcb->unsent = pcb->unsent->next; +      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); +      LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); +      pcb->snd_queuelen -= pbuf_clen(next->p); +      tcp_seg_free(next); +      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen)); +      if (pcb->snd_queuelen != 0) { +        LWIP_ASSERT("tcp_receive: valid queue length", +          pcb->unacked != NULL || pcb->unsent != NULL); +      } +    } +    /* End of ACK for new data processing. */ + +    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", +                                pcb->rttest, pcb->rtseq, ackno)); + +    /* RTT estimation calculations. This is done by checking if the +       incoming segment acknowledges the segment we use to take a +       round-trip time measurement. */ +    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { +      /* diff between this shouldn't exceed 32K since this are tcp timer ticks +         and a round-trip shouldn't be that long... */ +      m = (s16_t)(tcp_ticks - pcb->rttest); + +      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", +                                  m, m * TCP_SLOW_INTERVAL)); + +      /* This is taken directly from VJs original code in his paper */ +      m = m - (pcb->sa >> 3); +      pcb->sa += m; +      if (m < 0) { +        m = -m; +      } +      m = m - (pcb->sv >> 2); +      pcb->sv += m; +      pcb->rto = (pcb->sa >> 3) + pcb->sv; + +      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", +                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); + +      pcb->rttest = 0; +    } +  } + +  /* If the incoming segment contains data, we must process it +     further. */ +  if (tcplen > 0) { +    /* This code basically does three things: + +    +) If the incoming segment contains data that is the next +    in-sequence data, this data is passed to the application. This +    might involve trimming the first edge of the data. The rcv_nxt +    variable and the advertised window are adjusted. + +    +) If the incoming segment has data that is above the next +    sequence number expected (->rcv_nxt), the segment is placed on +    the ->ooseq queue. This is done by finding the appropriate +    place in the ->ooseq queue (which is ordered by sequence +    number) and trim the segment in both ends if needed. An +    immediate ACK is sent to indicate that we received an +    out-of-sequence segment. + +    +) Finally, we check if the first segment on the ->ooseq queue +    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If +    rcv_nxt > ooseq->seqno, we must trim the first edge of the +    segment on ->ooseq before we adjust rcv_nxt. The data in the +    segments that are now on sequence are chained onto the +    incoming segment so that we only need to call the application +    once. +    */ + +    /* First, we check if we must trim the first edge. We have to do +       this if the sequence number of the incoming segment is less +       than rcv_nxt, and the sequence number plus the length of the +       segment is larger than rcv_nxt. */ +    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ +          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ +    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){ +      /* Trimming the first edge is done by pushing the payload +         pointer in the pbuf downwards. This is somewhat tricky since +         we do not want to discard the full contents of the pbuf up to +         the new starting point of the data since we have to keep the +         TCP header which is present in the first pbuf in the chain. + +         What is done is really quite a nasty hack: the first pbuf in +         the pbuf chain is pointed to by inseg.p. Since we need to be +         able to deallocate the whole pbuf, we cannot change this +         inseg.p pointer to point to any of the later pbufs in the +         chain. Instead, we point the ->payload pointer in the first +         pbuf to data in one of the later pbufs. We also set the +         inseg.data pointer to point to the right place. This way, the +         ->p pointer will still point to the first pbuf, but the +         ->p->payload pointer will point to data in another pbuf. + +         After we are done with adjusting the pbuf pointers we must +         adjust the ->data pointer in the seg and the segment +         length.*/ + +      off = pcb->rcv_nxt - seqno; +      p = inseg.p; +      LWIP_ASSERT("inseg.p != NULL", inseg.p); +      LWIP_ASSERT("insane offset!", (off < 0x7fff)); +      if (inseg.p->len < off) { +        LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); +        new_tot_len = (u16_t)(inseg.p->tot_len - off); +        while (p->len < off) { +          off -= p->len; +          /* KJM following line changed (with addition of new_tot_len var) +             to fix bug #9076 +             inseg.p->tot_len -= p->len; */ +          p->tot_len = new_tot_len; +          p->len = 0; +          p = p->next; +        } +        if(pbuf_header(p, (s16_t)-off)) { +          /* Do we need to cope with this failing?  Assert for now */ +          LWIP_ASSERT("pbuf_header failed", 0); +        } +      } else { +        if(pbuf_header(inseg.p, (s16_t)-off)) { +          /* Do we need to cope with this failing?  Assert for now */ +          LWIP_ASSERT("pbuf_header failed", 0); +        } +      } +      /* KJM following line changed to use p->payload rather than inseg->p->payload +         to fix bug #9076 */ +      inseg.dataptr = p->payload; +      inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); +      inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; +    } +    else { +      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ +        /* the whole segment is < rcv_nxt */ +        /* must be a duplicate of a packet that has already been correctly handled */ + +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); +        tcp_ack_now(pcb); +      } +    } + +    /* The sequence number must be within the window (above rcv_nxt +       and below rcv_nxt + rcv_wnd) in order to be further +       processed. */ +    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,  +                        pcb->rcv_nxt + pcb->rcv_wnd - 1)){ +      if (pcb->rcv_nxt == seqno) { +        accepted_inseq = 1;  +        /* The incoming segment is the next in sequence. We check if +           we have to trim the end of the segment and update rcv_nxt +           and pass the data to the application. */ +        tcplen = TCP_TCPLEN(&inseg); + +        if (tcplen > pcb->rcv_wnd) { +          LWIP_DEBUGF(TCP_INPUT_DEBUG,  +                      ("tcp_receive: other end overran receive window" +                       "seqno %"U32_F" len %"U32_F" right edge %"U32_F"\n", +                       seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); +          if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { +            /* Must remove the FIN from the header as we're trimming  +             * that byte of sequence-space from the packet */ +            TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); +          } +          /* Adjust length of segment to fit in the window. */ +          inseg.len = pcb->rcv_wnd; +          if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { +            inseg.len -= 1; +          } +          pbuf_realloc(inseg.p, inseg.len); +          tcplen = TCP_TCPLEN(&inseg); +          LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", +                      (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); +        } +#if TCP_QUEUE_OOSEQ +        if (pcb->ooseq != NULL) { +          if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { +            LWIP_DEBUGF(TCP_INPUT_DEBUG,  +                        ("tcp_receive: received in-order FIN, binning ooseq queue\n")); +            /* Received in-order FIN means anything that was received +             * out of order must now have been received in-order, so +             * bin the ooseq queue */ +            while (pcb->ooseq != NULL) { +              struct tcp_seg *old_ooseq = pcb->ooseq; +              pcb->ooseq = pcb->ooseq->next; +              memp_free(MEMP_TCP_SEG, old_ooseq); +            }                +          } else if (TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + tcplen)) { +            if (pcb->ooseq->len > 0) { +              /* We have to trim the second edge of the incoming segment. */ +              LWIP_ASSERT("tcp_receive: trimmed segment would have zero length\n", +                          TCP_SEQ_GT(pcb->ooseq->tcphdr->seqno, seqno)); +              /* FIN in inseg already handled by dropping whole ooseq queue */ +              inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno); +              if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { +                inseg.len -= 1; +              } +              pbuf_realloc(inseg.p, inseg.len); +              tcplen = TCP_TCPLEN(&inseg); +              LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", +                          (seqno + tcplen) == pcb->ooseq->tcphdr->seqno); +            } else { +              /* does the ooseq segment contain only flags that are in inseg also? */ +              if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) == +                  (TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) { +                struct tcp_seg *old_ooseq = pcb->ooseq; +                pcb->ooseq = pcb->ooseq->next; +                memp_free(MEMP_TCP_SEG, old_ooseq); +              } +            } +          } +        } +#endif /* TCP_QUEUE_OOSEQ */ + +        pcb->rcv_nxt = seqno + tcplen; + +        /* Update the receiver's (our) window. */ +        LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); +        pcb->rcv_wnd -= tcplen; + +        tcp_update_rcv_ann_wnd(pcb); + +        /* If there is data in the segment, we make preparations to +           pass this up to the application. The ->recv_data variable +           is used for holding the pbuf that goes to the +           application. The code for reassembling out-of-sequence data +           chains its data on this pbuf as well. + +           If the segment was a FIN, we set the TF_GOT_FIN flag that will +           be used to indicate to the application that the remote side has +           closed its end of the connection. */ +        if (inseg.p->tot_len > 0) { +          recv_data = inseg.p; +          /* Since this pbuf now is the responsibility of the +             application, we delete our reference to it so that we won't +             (mistakingly) deallocate it. */ +          inseg.p = NULL; +        } +        if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { +          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); +          recv_flags |= TF_GOT_FIN; +        } + +#if TCP_QUEUE_OOSEQ +        /* We now check if we have segments on the ->ooseq queue that +           is now in sequence. */ +        while (pcb->ooseq != NULL && +               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { + +          cseg = pcb->ooseq; +          seqno = pcb->ooseq->tcphdr->seqno; + +          pcb->rcv_nxt += TCP_TCPLEN(cseg); +          LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", +                      pcb->rcv_wnd >= TCP_TCPLEN(cseg)); +          pcb->rcv_wnd -= TCP_TCPLEN(cseg); + +          tcp_update_rcv_ann_wnd(pcb); + +          if (cseg->p->tot_len > 0) { +            /* Chain this pbuf onto the pbuf that we will pass to +               the application. */ +            if (recv_data) { +              pbuf_cat(recv_data, cseg->p); +            } else { +              recv_data = cseg->p; +            } +            cseg->p = NULL; +          } +          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { +            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); +            recv_flags |= TF_GOT_FIN; +            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ +              pcb->state = CLOSE_WAIT; +            }  +          } + + +          pcb->ooseq = cseg->next; +          tcp_seg_free(cseg); +        } +#endif /* TCP_QUEUE_OOSEQ */ + + +        /* Acknowledge the segment(s). */ +        tcp_ack(pcb); + +      } else { +        /* We get here if the incoming segment is out-of-sequence. */ +        tcp_ack_now(pcb); +#if TCP_QUEUE_OOSEQ +        /* We queue the segment on the ->ooseq queue. */ +        if (pcb->ooseq == NULL) { +          pcb->ooseq = tcp_seg_copy(&inseg); +        } else { +          /* If the queue is not empty, we walk through the queue and +             try to find a place where the sequence number of the +             incoming segment is between the sequence numbers of the +             previous and the next segment on the ->ooseq queue. That is +             the place where we put the incoming segment. If needed, we +             trim the second edges of the previous and the incoming +             segment so that it will fit into the sequence. + +             If the incoming segment has the same sequence number as a +             segment on the ->ooseq queue, we discard the segment that +             contains less data. */ + +          prev = NULL; +          for(next = pcb->ooseq; next != NULL; next = next->next) { +            if (seqno == next->tcphdr->seqno) { +              /* The sequence number of the incoming segment is the +                 same as the sequence number of the segment on +                 ->ooseq. We check the lengths to see which one to +                 discard. */ +              if (inseg.len > next->len) { +                /* The incoming segment is larger than the old +                   segment. We replace the old segment with the new +                   one. */ +                cseg = tcp_seg_copy(&inseg); +                if (cseg != NULL) { +                  cseg->next = next->next; +                  if (prev != NULL) { +                    prev->next = cseg; +                  } else { +                    pcb->ooseq = cseg; +                  } +                  tcp_seg_free(next); +                  if (cseg->next != NULL) { +                    next = cseg->next; +                    if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { +                      /* We need to trim the incoming segment. */ +                      cseg->len = (u16_t)(next->tcphdr->seqno - seqno); +                      pbuf_realloc(cseg->p, cseg->len); +                    } +                  } +                } +                break; +              } else { +                /* Either the lenghts are the same or the incoming +                   segment was smaller than the old one; in either +                   case, we ditch the incoming segment. */ +                break; +              } +            } else { +              if (prev == NULL) { +                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { +                  /* The sequence number of the incoming segment is lower +                     than the sequence number of the first segment on the +                     queue. We put the incoming segment first on the +                     queue. */ + +                  if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { +                    /* We need to trim the incoming segment. */ +                    inseg.len = (u16_t)(next->tcphdr->seqno - seqno); +                    pbuf_realloc(inseg.p, inseg.len); +                  } +                  cseg = tcp_seg_copy(&inseg); +                  if (cseg != NULL) { +                    cseg->next = next; +                    pcb->ooseq = cseg; +                  } +                  break; +                } +              } else  +                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && +                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ +                if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){ +                /* The sequence number of the incoming segment is in +                   between the sequence numbers of the previous and +                   the next segment on ->ooseq. We trim and insert the +                   incoming segment and trim the previous segment, if +                   needed. */ +                if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { +                  /* We need to trim the incoming segment. */ +                  inseg.len = (u16_t)(next->tcphdr->seqno - seqno); +                  pbuf_realloc(inseg.p, inseg.len); +                } + +                cseg = tcp_seg_copy(&inseg); +                if (cseg != NULL) { +                  cseg->next = next; +                  prev->next = cseg; +                  if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { +                    /* We need to trim the prev segment. */ +                    prev->len = (u16_t)(seqno - prev->tcphdr->seqno); +                    pbuf_realloc(prev->p, prev->len); +                  } +                } +                break; +              } +              /* If the "next" segment is the last segment on the +                 ooseq queue, we add the incoming segment to the end +                 of the list. */ +              if (next->next == NULL && +                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { +                next->next = tcp_seg_copy(&inseg); +                if (next->next != NULL) { +                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { +                    /* We need to trim the last segment. */ +                    next->len = (u16_t)(seqno - next->tcphdr->seqno); +                    pbuf_realloc(next->p, next->len); +                  } +                } +                break; +              } +            } +            prev = next; +          } +        } +#endif /* TCP_QUEUE_OOSEQ */ + +      } +    } else { +      tcp_ack_now(pcb); +    } +  } else { +    /* Segments with length 0 is taken care of here. Segments that +       fall out of the window are ACKed. */ +    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || +      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ +    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ +      tcp_ack_now(pcb); +    } +  } +  return accepted_inseq; +} + +/** + * Parses the options contained in the incoming segment.  + * + * Called from tcp_listen_input() and tcp_process(). + * Currently, only the MSS option is supported! + * + * @param pcb the tcp_pcb for which a segment arrived + */ +static void +tcp_parseopt(struct tcp_pcb *pcb) +{ +  u16_t c, max_c; +  u16_t mss; +  u8_t *opts, opt; +#if LWIP_TCP_TIMESTAMPS +  u32_t tsval; +#endif + +  opts = (u8_t *)tcphdr + TCP_HLEN; + +  /* Parse the TCP MSS option, if present. */ +  if(TCPH_HDRLEN(tcphdr) > 0x5) { +    max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; +    for (c = 0; c < max_c; ) { +      opt = opts[c]; +      switch (opt) { +      case 0x00: +        /* End of options. */ +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); +        return; +      case 0x01: +        /* NOP option. */ +        ++c; +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); +        break; +      case 0x02: +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); +        if (opts[c + 1] != 0x04 || c + 0x04 > max_c) { +          /* Bad length */ +          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); +          return; +        } +        /* An MSS option with the right option length. */ +        mss = (opts[c + 2] << 8) | opts[c + 3]; +        /* Limit the mss to the configured TCP_MSS and prevent division by zero */ +        pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; +        /* Advance to next option */ +        c += 0x04; +        break; +#if LWIP_TCP_TIMESTAMPS +      case 0x08: +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); +        if (opts[c + 1] != 0x0A || c + 0x0A > max_c) { +          /* Bad length */ +          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); +          return; +        } +        /* TCP timestamp option with valid length */ +        tsval = (opts[c+2]) | (opts[c+3] << 8) |  +          (opts[c+4] << 16) | (opts[c+5] << 24); +        if (flags & TCP_SYN) { +          pcb->ts_recent = ntohl(tsval); +          pcb->flags |= TF_TIMESTAMP; +        } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { +          pcb->ts_recent = ntohl(tsval); +        } +        /* Advance to next option */ +        c += 0x0A; +        break; +#endif +      default: +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); +        if (opts[c + 1] == 0) { +          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); +          /* If the length field is zero, the options are malformed +             and we don't process them further. */ +          return; +        } +        /* All other options have a length field, so that we easily +           can skip past them. */ +        c += opts[c + 1]; +      } +    } +  } +} + +#endif /* LWIP_TCP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp_out.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp_out.c new file mode 100644 index 000000000..ca72d9dcc --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/tcp_out.c @@ -0,0 +1,981 @@ +/** + * @file + * Transmission Control Protocol, outgoing traffic + * + * The output functions of TCP. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +#include <string.h> + +/* Forward declarations.*/ +static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); + +static struct tcp_hdr * +tcp_output_set_header(struct tcp_pcb *pcb, struct pbuf *p, int optlen, +                      u32_t seqno_be /* already in network byte order */) +{ +  struct tcp_hdr *tcphdr = p->payload; +  tcphdr->src = htons(pcb->local_port); +  tcphdr->dest = htons(pcb->remote_port); +  tcphdr->seqno = seqno_be; +  tcphdr->ackno = htonl(pcb->rcv_nxt); +  TCPH_FLAGS_SET(tcphdr, TCP_ACK); +  tcphdr->wnd = htons(pcb->rcv_ann_wnd); +  tcphdr->urgp = 0; +  TCPH_HDRLEN_SET(tcphdr, (5 + optlen / 4)); +  tcphdr->chksum = 0; + +  /* If we're sending a packet, update the announced right window edge */ +  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + +  return tcphdr; +} + +/** + * Called by tcp_close() to send a segment including flags but not data. + * + * @param pcb the tcp_pcb over which to send a segment + * @param flags the flags to set in the segment header + * @return ERR_OK if sent, another err_t otherwise + */ +err_t +tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) +{ +  /* no data, no length, flags, copy=1, no optdata */ +  return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, 0); +} + +/** + * Write data for sending (but does not send it immediately). + * + * It waits in the expectation of more data being sent soon (as + * it can send them more efficiently by combining them together). + * To prompt the system to send data now, call tcp_output() after + * calling tcp_write(). + *  + * @param pcb Protocol control block of the TCP connection to enqueue data for. + * @param data pointer to the data to send + * @param len length (in bytes) of the data to send + * @param apiflags combination of following flags : + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, + * @return ERR_OK if enqueued, another err_t on error + *  + * @see tcp_write() + */ +err_t +tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) +{ +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb, +    data, len, (u16_t)apiflags)); +  /* connection is in valid state for data transmission? */ +  if (pcb->state == ESTABLISHED || +     pcb->state == CLOSE_WAIT || +     pcb->state == SYN_SENT || +     pcb->state == SYN_RCVD) { +    if (len > 0) { +#if LWIP_TCP_TIMESTAMPS +      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags,  +                         pcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0); +#else +      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, 0); +#endif +    } +    return ERR_OK; +  } else { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | 3, ("tcp_write() called in invalid state\n")); +    return ERR_CONN; +  } +} + +/** + * Enqueue data and/or TCP options for transmission + * + * Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and tcp_write(). + * + * @param pcb Protocol control block for the TCP connection to enqueue data for. + * @param arg Pointer to the data to be enqueued for sending. + * @param len Data length in bytes + * @param flags tcp header flags to set in the outgoing segment + * @param apiflags combination of following flags : + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, + * @param optflags options to include in segment later on (see definition of struct tcp_seg) + */ +err_t +tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, +            u8_t flags, u8_t apiflags, u8_t optflags) +{ +  struct pbuf *p; +  struct tcp_seg *seg, *useg, *queue; +  u32_t seqno; +  u16_t left, seglen; +  void *ptr; +  u16_t queuelen; +  u8_t optlen; + +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG,  +              ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n", +               (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags)); +  LWIP_ERROR("tcp_enqueue: packet needs payload, options, or SYN/FIN (programmer violates API)", +             ((len != 0) || (optflags != 0) || ((flags & (TCP_SYN | TCP_FIN)) != 0)), +             return ERR_ARG;); +  LWIP_ERROR("tcp_enqueue: len != 0 || arg == NULL (programmer violates API)",  +             ((len != 0) || (arg == NULL)), return ERR_ARG;); + +  /* fail on too much data */ +  if (len > pcb->snd_buf) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf)); +    pcb->flags |= TF_NAGLEMEMERR; +    return ERR_MEM; +  } +  left = len; +  ptr = arg; + +  optlen = LWIP_TCP_OPT_LENGTH(optflags); + +  /* seqno will be the sequence number of the first segment enqueued +   * by the call to this function. */ +  seqno = pcb->snd_lbb; + +  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + +  /* If total number of pbufs on the unsent/unacked queues exceeds the +   * configured maximum, return an error */ +  queuelen = pcb->snd_queuelen; +  /* check for configured max queuelen and possible overflow */ +  if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); +    TCP_STATS_INC(tcp.memerr); +    pcb->flags |= TF_NAGLEMEMERR; +    return ERR_MEM; +  } +  if (queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty", +      pcb->unacked != NULL || pcb->unsent != NULL); +  } else { +    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty", +      pcb->unacked == NULL && pcb->unsent == NULL); +  } + +  /* First, break up the data into segments and tuck them together in +   * the local "queue" variable. */ +  useg = queue = seg = NULL; +  seglen = 0; +  while (queue == NULL || left > 0) { +    /* The segment length (including options) should be at most the MSS */ +    seglen = left > (pcb->mss - optlen) ? (pcb->mss - optlen) : left; + +    /* Allocate memory for tcp_seg, and fill in fields. */ +    seg = memp_malloc(MEMP_TCP_SEG); +    if (seg == NULL) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                  ("tcp_enqueue: could not allocate memory for tcp_seg\n")); +      goto memerr; +    } +    seg->next = NULL; +    seg->p = NULL; + +    /* first segment of to-be-queued data? */ +    if (queue == NULL) { +      queue = seg; +    } +    /* subsequent segments of to-be-queued data */ +    else { +      /* Attach the segment to the end of the queued segments */ +      LWIP_ASSERT("useg != NULL", useg != NULL); +      useg->next = seg; +    } +    /* remember last segment of to-be-queued data for next iteration */ +    useg = seg; + +    /* If copy is set, memory should be allocated +     * and data copied into pbuf, otherwise data comes from +     * ROM or other static memory, and need not be copied.  */ +    if (apiflags & TCP_WRITE_FLAG_COPY) { +      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen + optlen, PBUF_RAM)) == NULL) { +        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                    ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); +        goto memerr; +      } +      LWIP_ASSERT("check that first pbuf can hold the complete seglen", +                  (seg->p->len >= seglen + optlen)); +      queuelen += pbuf_clen(seg->p); +      if (arg != NULL) { +        MEMCPY((char *)seg->p->payload + optlen, ptr, seglen); +      } +      seg->dataptr = seg->p->payload; +    } +    /* do not copy data */ +    else { +      /* First, allocate a pbuf for the headers. */ +      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { +        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                    ("tcp_enqueue: could not allocate memory for header pbuf\n")); +        goto memerr; +      } +      queuelen += pbuf_clen(seg->p); + +      /* Second, allocate a pbuf for holding the data. +       * since the referenced data is available at least until it is sent out on the +       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM +       * instead of PBUF_REF here. +       */ +      if (left > 0) { +        if ((p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { +          /* If allocation fails, we have to deallocate the header pbuf as well. */ +          pbuf_free(seg->p); +          seg->p = NULL; +          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                      ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); +          goto memerr; +        } +        ++queuelen; +        /* reference the non-volatile payload data */ +        p->payload = ptr; +        seg->dataptr = ptr; + +        /* Concatenate the headers and data pbufs together. */ +        pbuf_cat(seg->p/*header*/, p/*data*/); +        p = NULL; +      } +    } + +    /* Now that there are more segments queued, we check again if the +    length of the queue exceeds the configured maximum or overflows. */ +    if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); +      goto memerr; +    } + +    seg->len = seglen; + +    /* build TCP header */ +    if (pbuf_header(seg->p, TCP_HLEN)) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n")); +      TCP_STATS_INC(tcp.err); +      goto memerr; +    } +    seg->tcphdr = seg->p->payload; +    seg->tcphdr->src = htons(pcb->local_port); +    seg->tcphdr->dest = htons(pcb->remote_port); +    seg->tcphdr->seqno = htonl(seqno); +    seg->tcphdr->urgp = 0; +    TCPH_FLAGS_SET(seg->tcphdr, flags); +    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */ + +    seg->flags = optflags; + +    /* Set the length of the header */ +    TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4)); +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", +      ntohl(seg->tcphdr->seqno), +      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), +      (u16_t)flags)); + +    left -= seglen; +    seqno += seglen; +    ptr = (void *)((u8_t *)ptr + seglen); +  } + +  /* Now that the data to be enqueued has been broken up into TCP +  segments in the queue variable, we add them to the end of the +  pcb->unsent queue. */ +  if (pcb->unsent == NULL) { +    useg = NULL; +  } +  else { +    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); +  } +  /* { useg is last segment on the unsent queue, NULL if list is empty } */ + +  /* If there is room in the last pbuf on the unsent queue, +  chain the first pbuf on the queue together with that. */ +  if (useg != NULL && +    TCP_TCPLEN(useg) != 0 && +    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && +    !(flags & (TCP_SYN | TCP_FIN)) && +    /* fit within max seg size */ +    (useg->len + queue->len <= pcb->mss) && +    /* only concatenate segments with the same options */ +    (useg->flags == queue->flags)) { +    /* Remove TCP header from first segment of our to-be-queued list */ +    if(pbuf_header(queue->p, -(TCP_HLEN + optlen))) { +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +      TCP_STATS_INC(tcp.err); +      goto memerr; +    } +    if (queue->p->len == 0) { +      /* free the first (header-only) pbuf if it is now empty (contained only headers) */ +      struct pbuf *old_q = queue->p; +      queue->p = queue->p->next; +      old_q->next = NULL; +      queuelen--; +      pbuf_free(old_q); +    } +    LWIP_ASSERT("zero-length pbuf", (queue->p != NULL) && (queue->p->len > 0)); +    pbuf_cat(useg->p, queue->p); +    useg->len += queue->len; +    useg->next = queue->next; + +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len)); +    if (seg == queue) { +      seg = useg; +      seglen = useg->len; +    } +    memp_free(MEMP_TCP_SEG, queue); +  } +  else { +    /* empty list */ +    if (useg == NULL) { +      /* initialize list with this segment */ +      pcb->unsent = queue; +    } +    /* enqueue segment */ +    else { +      useg->next = queue; +    } +  } +  if ((flags & TCP_SYN) || (flags & TCP_FIN)) { +    ++len; +  } +  if (flags & TCP_FIN) { +    pcb->flags |= TF_FIN; +  } +  pcb->snd_lbb += len; + +  pcb->snd_buf -= len; + +  /* update number of segments on the queues */ +  pcb->snd_queuelen = queuelen; +  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); +  if (pcb->snd_queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: valid queue length", +      pcb->unacked != NULL || pcb->unsent != NULL); +  } + +  /* Set the PSH flag in the last segment that we enqueued, but only +  if the segment has data (indicated by seglen > 0). */ +  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { +    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); +  } + +  return ERR_OK; +memerr: +  pcb->flags |= TF_NAGLEMEMERR; +  TCP_STATS_INC(tcp.memerr); + +  if (queue != NULL) { +    tcp_segs_free(queue); +  } +  if (pcb->snd_queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || +      pcb->unsent != NULL); +  } +  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); +  return ERR_MEM; +} + + +#if LWIP_TCP_TIMESTAMPS +/* Build a timestamp option (12 bytes long) at the specified options pointer) + * + * @param pcb tcp_pcb + * @param opts option pointer where to store the timestamp option + */ +static void +tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) +{ +  /* Pad with two NOP options to make everything nicely aligned */ +  opts[0] = htonl(0x0101080A); +  opts[1] = htonl(sys_now()); +  opts[2] = htonl(pcb->ts_recent); +} +#endif + + +/** + * Find out what we can send and send it + * + * @param pcb Protocol control block for the TCP connection to send data + * @return ERR_OK if data has been sent or nothing to send + *         another err_t on error + */ +err_t +tcp_output(struct tcp_pcb *pcb) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; +  struct tcp_seg *seg, *useg; +  u32_t wnd, snd_nxt; +#if TCP_CWND_DEBUG +  s16_t i = 0; +#endif /* TCP_CWND_DEBUG */ +  u8_t optlen = 0; + +  /* First, check if we are invoked by the TCP input processing +     code. If so, we do not output anything. Instead, we rely on the +     input processing code to call us when input processing is done +     with. */ +  if (tcp_input_pcb == pcb) { +    return ERR_OK; +  } + +  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); + +  seg = pcb->unsent; + +  /* useg should point to last segment on unacked queue */ +  useg = pcb->unacked; +  if (useg != NULL) { +    for (; useg->next != NULL; useg = useg->next); +  } + +  /* If the TF_ACK_NOW flag is set and no data will be sent (either +   * because the ->unsent queue is empty or because the window does +   * not allow it), construct an empty ACK segment and send it. +   * +   * If data is to be sent, we will just piggyback the ACK (see below). +   */ +  if (pcb->flags & TF_ACK_NOW && +     (seg == NULL || +      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { +#if LWIP_TCP_TIMESTAMPS +    if (pcb->flags & TF_TIMESTAMP) +      optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); +#endif +    p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM); +    if (p == NULL) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); +      return ERR_BUF; +    } +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG,  +                ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); +    /* remove ACK flags from the PCB, as we send an empty ACK now */ +    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); + +    tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt)); + +    /* NB. MSS option is only sent on SYNs, so ignore it here */ +#if LWIP_TCP_TIMESTAMPS +    pcb->ts_lastacksent = pcb->rcv_nxt; + +    if (pcb->flags & TF_TIMESTAMP) +      tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); +#endif  + +#if CHECKSUM_GEN_TCP +    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), +          IP_PROTO_TCP, p->tot_len); +#endif +#if LWIP_NETIF_HWADDRHINT +    ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +        IP_PROTO_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +        IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ +    pbuf_free(p); + +    return ERR_OK; +  } + +#if TCP_OUTPUT_DEBUG +  if (seg == NULL) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", +                                   (void*)pcb->unsent)); +  } +#endif /* TCP_OUTPUT_DEBUG */ +#if TCP_CWND_DEBUG +  if (seg == NULL) { +    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F +                                 ", cwnd %"U16_F", wnd %"U32_F +                                 ", seg == NULL, ack %"U32_F"\n", +                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); +  } else { +    LWIP_DEBUGF(TCP_CWND_DEBUG,  +                ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F +                 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", +                 pcb->snd_wnd, pcb->cwnd, wnd, +                 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, +                 ntohl(seg->tcphdr->seqno), pcb->lastack)); +  } +#endif /* TCP_CWND_DEBUG */ +  /* data available and window allows it to be sent? */ +  while (seg != NULL && +         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { +    LWIP_ASSERT("RST not expected here!",  +                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); +    /* Stop sending if the nagle algorithm would prevent it +     * Don't stop: +     * - if tcp_enqueue had a memory error before (prevent delayed ACK timeout) or +     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - +     *   either seg->next != NULL or pcb->unacked == NULL; +     *   RST is no sent using tcp_enqueue/tcp_output. +     */ +    if((tcp_do_output_nagle(pcb) == 0) && +      ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){ +      break; +    } +#if TCP_CWND_DEBUG +    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", +                            pcb->snd_wnd, pcb->cwnd, wnd, +                            ntohl(seg->tcphdr->seqno) + seg->len - +                            pcb->lastack, +                            ntohl(seg->tcphdr->seqno), pcb->lastack, i)); +    ++i; +#endif /* TCP_CWND_DEBUG */ + +    pcb->unsent = seg->next; + +    if (pcb->state != SYN_SENT) { +      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); +      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); +    } + +    tcp_output_segment(seg, pcb); +    snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); +    if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { +      pcb->snd_nxt = snd_nxt; +    } +    /* put segment on unacknowledged list if length > 0 */ +    if (TCP_TCPLEN(seg) > 0) { +      seg->next = NULL; +      /* unacked list is empty? */ +      if (pcb->unacked == NULL) { +        pcb->unacked = seg; +        useg = seg; +      /* unacked list is not empty? */ +      } else { +        /* In the case of fast retransmit, the packet should not go to the tail +         * of the unacked queue, but rather somewhere before it. We need to check for +         * this case. -STJ Jul 27, 2004 */ +        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){ +          /* add segment to before tail of unacked list, keeping the list sorted */ +          struct tcp_seg **cur_seg = &(pcb->unacked); +          while (*cur_seg && +            TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { +              cur_seg = &((*cur_seg)->next ); +          } +          seg->next = (*cur_seg); +          (*cur_seg) = seg; +        } else { +          /* add segment to tail of unacked list */ +          useg->next = seg; +          useg = useg->next; +        } +      } +    /* do not queue empty segments on the unacked list */ +    } else { +      tcp_seg_free(seg); +    } +    seg = pcb->unsent; +  } + +  if (seg != NULL && pcb->persist_backoff == 0 &&  +      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { +    /* prepare for persist timer */ +    pcb->persist_cnt = 0; +    pcb->persist_backoff = 1; +  } + +  pcb->flags &= ~TF_NAGLEMEMERR; +  return ERR_OK; +} + +/** + * Called by tcp_output() to actually send a TCP segment over IP. + * + * @param seg the tcp_seg to send + * @param pcb the tcp_pcb for the TCP connection used to send the segment + */ +static void +tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) +{ +  u16_t len; +  struct netif *netif; +  u32_t *opts; + +  /** @bug Exclude retransmitted segments from this count. */ +  snmp_inc_tcpoutsegs(); + +  /* The TCP header has already been constructed, but the ackno and +   wnd fields remain. */ +  seg->tcphdr->ackno = htonl(pcb->rcv_nxt); + +  /* advertise our receive window size in this TCP segment */ +  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); + +  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + +  /* Add any requested options.  NB MSS option is only set on SYN +     packets, so ignore it here */ +  opts = (u32_t *)(seg->tcphdr + 1); +  if (seg->flags & TF_SEG_OPTS_MSS) { +    TCP_BUILD_MSS_OPTION(*opts); +    opts += 1; +  } +#if LWIP_TCP_TIMESTAMPS +  pcb->ts_lastacksent = pcb->rcv_nxt; + +  if (seg->flags & TF_SEG_OPTS_TS) { +    tcp_build_timestamp_option(pcb, opts); +    opts += 3; +  } +#endif + +  /* If we don't have a local IP address, we get one by +     calling ip_route(). */ +  if (ip_addr_isany(&(pcb->local_ip))) { +    netif = ip_route(&(pcb->remote_ip)); +    if (netif == NULL) { +      return; +    } +    ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); +  } + +  /* Set retransmission timer running if it is not currently enabled */ +  if(pcb->rtime == -1) +    pcb->rtime = 0; + +  if (pcb->rttest == 0) { +    pcb->rttest = tcp_ticks; +    pcb->rtseq = ntohl(seg->tcphdr->seqno); + +    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); +  } +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", +          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + +          seg->len)); + +  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); + +  seg->p->len -= len; +  seg->p->tot_len -= len; + +  seg->p->payload = seg->tcphdr; + +  seg->tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP +  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, +             &(pcb->local_ip), +             &(pcb->remote_ip), +             IP_PROTO_TCP, seg->p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); + +#if LWIP_NETIF_HWADDRHINT +  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +      IP_PROTO_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, +      IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ +} + +/** + * Send a TCP RESET packet (empty segment with RST flag set) either to + * abort a connection or to show that there is no matching local connection + * for a received segment. + * + * Called by tcp_abort() (to abort a local connection), tcp_input() (if no + * matching local pcb was found), tcp_listen_input() (if incoming segment + * has ACK flag set) and tcp_process() (received segment in the wrong state) + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip the local IP address to send the segment from + * @param remote_ip the remote IP address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst(u32_t seqno, u32_t ackno, +  struct ip_addr *local_ip, struct ip_addr *remote_ip, +  u16_t local_port, u16_t remote_port) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; +  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); +  if (p == NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); +      return; +  } +  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", +              (p->len >= sizeof(struct tcp_hdr))); + +  tcphdr = p->payload; +  tcphdr->src = htons(local_port); +  tcphdr->dest = htons(remote_port); +  tcphdr->seqno = htonl(seqno); +  tcphdr->ackno = htonl(ackno); +  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK); +  tcphdr->wnd = htons(TCP_WND); +  tcphdr->urgp = 0; +  TCPH_HDRLEN_SET(tcphdr, 5); + +  tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP +  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, +              IP_PROTO_TCP, p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); +  snmp_inc_tcpoutrsts(); +   /* Send output with hardcoded TTL since we have no access to the pcb */ +  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); +  pbuf_free(p); +  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); +} + +/** + * Requeue all unacked segments for retransmission + * + * Called by tcp_slowtmr() for slow retransmission. + * + * @param pcb the tcp_pcb for which to re-enqueue all unacked segments + */ +void +tcp_rexmit_rto(struct tcp_pcb *pcb) +{ +  struct tcp_seg *seg; + +  if (pcb->unacked == NULL) { +    return; +  } + +  /* Move all unacked segments to the head of the unsent queue */ +  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); +  /* concatenate unsent queue after unacked queue */ +  seg->next = pcb->unsent; +  /* unsent queue is the concatenated queue (of unacked, unsent) */ +  pcb->unsent = pcb->unacked; +  /* unacked queue is now empty */ +  pcb->unacked = NULL; + +  /* increment number of retransmissions */ +  ++pcb->nrtx; + +  /* Don't take any RTT measurements after retransmitting. */ +  pcb->rttest = 0; + +  /* Do the actual retransmission */ +  tcp_output(pcb); +} + +/** + * Requeue the first unacked segment for retransmission + * + * Called by tcp_receive() for fast retramsmit. + * + * @param pcb the tcp_pcb for which to retransmit the first unacked segment + */ +void +tcp_rexmit(struct tcp_pcb *pcb) +{ +  struct tcp_seg *seg; +  struct tcp_seg **cur_seg; + +  if (pcb->unacked == NULL) { +    return; +  } + +  /* Move the first unacked segment to the unsent queue */ +  /* Keep the unsent queue sorted. */ +  seg = pcb->unacked; +  pcb->unacked = seg->next; + +  cur_seg = &(pcb->unsent); +  while (*cur_seg && +    TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { +      cur_seg = &((*cur_seg)->next ); +  } +  seg->next = *cur_seg; +  *cur_seg = seg; + +  ++pcb->nrtx; + +  /* Don't take any rtt measurements after retransmitting. */ +  pcb->rttest = 0; + +  /* Do the actual retransmission. */ +  snmp_inc_tcpretranssegs(); +  tcp_output(pcb); +} + +/** + * Send keepalive packets to keep a connection active although + * no data is sent over it. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a keepalive packet + */ +void +tcp_keepalive(struct tcp_pcb *pcb) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +                          ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +                          ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",  +                          tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); +    +  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); +    +  if(p == NULL) { +    LWIP_DEBUGF(TCP_DEBUG,  +                ("tcp_keepalive: could not allocate memory for pbuf\n")); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", +              (p->len >= sizeof(struct tcp_hdr))); + +  tcphdr = tcp_output_set_header(pcb, p, 0, htonl(pcb->snd_nxt - 1)); + +#if CHECKSUM_GEN_TCP +  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, +                                      IP_PROTO_TCP, p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); + +  /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT +  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, +    &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + +  pbuf_free(p); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", +                          pcb->snd_nxt - 1, pcb->rcv_nxt)); +} + + +/** + * Send persist timer zero-window probes to keep a connection active + * when a window update is lost. + * + * Called by tcp_slowtmr() + * + * @param pcb the tcp_pcb for which to send a zero-window probe packet + */ +void +tcp_zero_window_probe(struct tcp_pcb *pcb) +{ +  struct pbuf *p; +  struct tcp_hdr *tcphdr; +  struct tcp_seg *seg; + +  LWIP_DEBUGF(TCP_DEBUG,  +              ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" +               U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +               ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +               ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + +  LWIP_DEBUGF(TCP_DEBUG,  +              ("tcp_zero_window_probe: tcp_ticks %"U32_F +               "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",  +               tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); + +  seg = pcb->unacked; + +  if(seg == NULL) +    seg = pcb->unsent; + +  if(seg == NULL) +    return; + +  p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM); +    +  if(p == NULL) { +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", +              (p->len >= sizeof(struct tcp_hdr))); + +  tcphdr = tcp_output_set_header(pcb, p, 0, seg->tcphdr->seqno); + +  /* Copy in one byte from the head of the unacked queue */ +  *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr; + +#if CHECKSUM_GEN_TCP +  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, +                                      IP_PROTO_TCP, p->tot_len); +#endif +  TCP_STATS_INC(tcp.xmit); + +  /* Send output to IP */ +#if LWIP_NETIF_HWADDRHINT +  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, +    &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ +  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + +  pbuf_free(p); + +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F +                          " ackno %"U32_F".\n", +                          pcb->snd_nxt - 1, pcb->rcv_nxt)); +} +#endif /* LWIP_TCP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/core/udp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/core/udp.c new file mode 100644 index 000000000..d8d644d44 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/core/udp.c @@ -0,0 +1,840 @@ +/** + * @file + * User Datagram Protocol module + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ + + +/* udp.c + * + * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828). + * + */ + +/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! + */ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/udp.h" +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/icmp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "arch/perf.h" +#include "lwip/dhcp.h" + +#include <string.h> + +/* The list of UDP PCBs */ +/* exported in udp.h (was static) */ +struct udp_pcb *udp_pcbs; + +/** + * Process an incoming UDP datagram. + * + * Given an incoming UDP datagram (as a chain of pbufs) this function + * finds a corresponding UDP PCB and hands over the pbuf to the pcbs + * recv function. If no pcb is found or the datagram is incorrect, the + * pbuf is freed. + * + * @param p pbuf to be demultiplexed to a UDP PCB. + * @param inp network interface on which the datagram was received. + * + */ +void +udp_input(struct pbuf *p, struct netif *inp) +{ +  struct udp_hdr *udphdr; +  struct udp_pcb *pcb, *prev; +  struct udp_pcb *uncon_pcb; +  struct ip_hdr *iphdr; +  u16_t src, dest; +  u8_t local_match; +  u8_t broadcast; + +  PERF_START; + +  UDP_STATS_INC(udp.recv); + +  iphdr = p->payload; + +  /* Check minimum length (IP header + UDP header) +   * and move payload pointer to UDP header */ +  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { +    /* drop short packets */ +    LWIP_DEBUGF(UDP_DEBUG, +                ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); +    UDP_STATS_INC(udp.lenerr); +    UDP_STATS_INC(udp.drop); +    snmp_inc_udpinerrors(); +    pbuf_free(p); +    goto end; +  } + +  udphdr = (struct udp_hdr *)p->payload; + +  /* is broadcast packet ? */ +  broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp); + +  LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); + +  /* convert src and dest ports to host byte order */ +  src = ntohs(udphdr->src); +  dest = ntohs(udphdr->dest); + +  udp_debug_print(udphdr); + +  /* print the UDP source and destination */ +  LWIP_DEBUGF(UDP_DEBUG, +              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " +               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", +               ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest), +               ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), +               ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), +               ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src))); + +#if LWIP_DHCP +  pcb = NULL; +  /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by +     the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ +  if (dest == DHCP_CLIENT_PORT) { +    /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ +    if (src == DHCP_SERVER_PORT) { +      if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { +        /* accept the packe if  +           (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! +           - inp->dhcp->pcb->remote == ANY or iphdr->src */ +        if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || +           ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) { +          pcb = inp->dhcp->pcb; +        } +      } +    } +  } else +#endif /* LWIP_DHCP */ +  { +    prev = NULL; +    local_match = 0; +    uncon_pcb = NULL; +    /* Iterate through the UDP pcb list for a matching pcb. +     * 'Perfect match' pcbs (connected to the remote port & ip address) are +     * preferred. If no perfect match is found, the first unconnected pcb that +     * matches the local port and ip address gets the datagram. */ +    for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { +      local_match = 0; +      /* print the PCB local and remote address */ +      LWIP_DEBUGF(UDP_DEBUG, +                  ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " +                   "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", +                   ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), +                   ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, +                   ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +                   ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port)); + +      /* compare PCB local addr+port to UDP destination addr+port */ +      if ((pcb->local_port == dest) && +          ((!broadcast && ip_addr_isany(&pcb->local_ip)) || +           ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || +#if LWIP_IGMP +           ip_addr_ismulticast(&(iphdr->dest)) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV +           (broadcast && (pcb->so_options & SOF_BROADCAST)))) { +#else  /* IP_SOF_BROADCAST_RECV */ +           (broadcast))) { +#endif /* IP_SOF_BROADCAST_RECV */ +        local_match = 1; +        if ((uncon_pcb == NULL) &&  +            ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { +          /* the first unconnected matching PCB */ +          uncon_pcb = pcb; +        } +      } +      /* compare PCB remote addr+port to UDP source addr+port */ +      if ((local_match != 0) && +          (pcb->remote_port == src) && +          (ip_addr_isany(&pcb->remote_ip) || +           ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) { +        /* the first fully matching PCB */ +        if (prev != NULL) { +          /* move the pcb to the front of udp_pcbs so that is +             found faster next time */ +          prev->next = pcb->next; +          pcb->next = udp_pcbs; +          udp_pcbs = pcb; +        } else { +          UDP_STATS_INC(udp.cachehit); +        } +        break; +      } +      prev = pcb; +    } +    /* no fully matching pcb found? then look for an unconnected pcb */ +    if (pcb == NULL) { +      pcb = uncon_pcb; +    } +  } + +  /* Check checksum if this is a match or if it was directed at us. */ +  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) { +    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); +#if LWIP_UDPLITE +    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { +      /* Do the UDP Lite checksum */ +#if CHECKSUM_CHECK_UDP +      u16_t chklen = ntohs(udphdr->len); +      if (chklen < sizeof(struct udp_hdr)) { +        if (chklen == 0) { +          /* For UDP-Lite, checksum length of 0 means checksum +             over the complete packet (See RFC 3828 chap. 3.1) */ +          chklen = p->tot_len; +        } else { +          /* At least the UDP-Lite header must be covered by the +             checksum! (Again, see RFC 3828 chap. 3.1) */ +          UDP_STATS_INC(udp.chkerr); +          UDP_STATS_INC(udp.drop); +          snmp_inc_udpinerrors(); +          pbuf_free(p); +          goto end; +        } +      } +      if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src), +                             (struct ip_addr *)&(iphdr->dest), +                             IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { +        LWIP_DEBUGF(UDP_DEBUG | 2, +                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); +        UDP_STATS_INC(udp.chkerr); +        UDP_STATS_INC(udp.drop); +        snmp_inc_udpinerrors(); +        pbuf_free(p); +        goto end; +      } +#endif /* CHECKSUM_CHECK_UDP */ +    } else +#endif /* LWIP_UDPLITE */ +    { +#if CHECKSUM_CHECK_UDP +      if (udphdr->chksum != 0) { +        if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), +                               (struct ip_addr *)&(iphdr->dest), +                               IP_PROTO_UDP, p->tot_len) != 0) { +          LWIP_DEBUGF(UDP_DEBUG | 2, +                      ("udp_input: UDP datagram discarded due to failing checksum\n")); +          UDP_STATS_INC(udp.chkerr); +          UDP_STATS_INC(udp.drop); +          snmp_inc_udpinerrors(); +          pbuf_free(p); +          goto end; +        } +      } +#endif /* CHECKSUM_CHECK_UDP */ +    } +    if(pbuf_header(p, -UDP_HLEN)) { +      /* Can we cope with this failing? Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +      UDP_STATS_INC(udp.drop); +      snmp_inc_udpinerrors(); +      pbuf_free(p); +      goto end; +    } +    if (pcb != NULL) { +      snmp_inc_udpindatagrams(); +      /* callback */ +      if (pcb->recv != NULL) { +        /* now the recv function is responsible for freeing p */ +        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); +      } else { +        /* no recv function registered? then we have to free the pbuf! */ +        pbuf_free(p); +        goto end; +      } +    } else { +      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); + +#if LWIP_ICMP +      /* No match was found, send ICMP destination port unreachable unless +         destination address was broadcast/multicast. */ +      if (!broadcast && +          !ip_addr_ismulticast(&iphdr->dest)) { +        /* move payload pointer back to ip header */ +        pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); +        LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); +        icmp_dest_unreach(p, ICMP_DUR_PORT); +      } +#endif /* LWIP_ICMP */ +      UDP_STATS_INC(udp.proterr); +      UDP_STATS_INC(udp.drop); +      snmp_inc_udpnoports(); +      pbuf_free(p); +    } +  } else { +    pbuf_free(p); +  } +end: +  PERF_STOP("udp_input"); +} + +/** + * Send data using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * + * The datagram will be sent to the current remote_ip & remote_port + * stored in pcb. If the pcb is not bound to a port, it will + * automatically be bound to a random port. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_MEM. Out of memory. + * - ERR_RTE. Could not find route to destination address. + * - More errors could be returned by lower protocol layers. + * + * @see udp_disconnect() udp_sendto() + */ +err_t +udp_send(struct udp_pcb *pcb, struct pbuf *p) +{ +  /* send to the packet using remote ip and port stored in the pcb */ +  return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); +} + +/** + * Send data to a specified address using UDP. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * If the PCB already has a remote address association, it will + * be restored after the data is sent. + *  + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t +udp_sendto(struct udp_pcb *pcb, struct pbuf *p, +  struct ip_addr *dst_ip, u16_t dst_port) +{ +  struct netif *netif; + +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n")); + +  /* find the outgoing network interface for this packet */ +#if LWIP_IGMP +  netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip)); +#else +  netif = ip_route(dst_ip); +#endif /* LWIP_IGMP */ + +  /* no outgoing network interface could be found? */ +  if (netif == NULL) { +    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr)); +    UDP_STATS_INC(udp.rterr); +    return ERR_RTE; +  } +  return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +} + +/** + * Send data to a specified address using UDP. + * The netif used for sending can be specified. + * + * This function exists mainly for DHCP, to be able to send UDP packets + * on a netif that is still down. + * + * @param pcb UDP PCB used to send the data. + * @param p chain of pbuf's to be sent. + * @param dst_ip Destination IP address. + * @param dst_port Destination UDP port. + * @param netif the netif used for sending. + * + * dst_ip & dst_port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code (@see udp_send for possible error codes) + * + * @see udp_disconnect() udp_send() + */ +err_t +udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, +  struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif) +{ +  struct udp_hdr *udphdr; +  struct ip_addr *src_ip; +  err_t err; +  struct pbuf *q; /* q will be sent down the stack */ + +#if IP_SOF_BROADCAST +  /* broadcast filter? */ +  if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { +    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); +    return ERR_VAL; +  } +#endif /* IP_SOF_BROADCAST */ + +  /* if the PCB is not yet bound to a port, bind it here */ +  if (pcb->local_port == 0) { +    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n")); +    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); +    if (err != ERR_OK) { +      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n")); +      return err; +    } +  } + +  /* not enough space to add an UDP header to first pbuf in given p chain? */ +  if (pbuf_header(p, UDP_HLEN)) { +    /* allocate header in a separate new pbuf */ +    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); +    /* new header pbuf could not be allocated? */ +    if (q == NULL) { +      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n")); +      return ERR_MEM; +    } +    /* chain header q in front of given pbuf p */ +    pbuf_chain(q, p); +    /* first pbuf q points to header pbuf */ +    LWIP_DEBUGF(UDP_DEBUG, +                ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); +  } else { +    /* adding space for header within p succeeded */ +    /* first pbuf q equals given pbuf */ +    q = p; +    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); +  } +  LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", +              (q->len >= sizeof(struct udp_hdr))); +  /* q now represents the packet to be sent */ +  udphdr = q->payload; +  udphdr->src = htons(pcb->local_port); +  udphdr->dest = htons(dst_port); +  /* in UDP, 0 checksum means 'no checksum' */ +  udphdr->chksum = 0x0000;  + +  /* PCB local address is IP_ANY_ADDR? */ +  if (ip_addr_isany(&pcb->local_ip)) { +    /* use outgoing network interface IP address as source address */ +    src_ip = &(netif->ip_addr); +  } else { +    /* check if UDP PCB local IP address is correct +     * this could be an old address if netif->ip_addr has changed */ +    if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { +      /* local_ip doesn't match, drop the packet */ +      if (q != p) { +        /* free the header pbuf */ +        pbuf_free(q); +        q = NULL; +        /* p is still referenced by the caller, and will live on */ +      } +      return ERR_VAL; +    } +    /* use UDP PCB local IP address as source address */ +    src_ip = &(pcb->local_ip); +  } + +  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); + +#if LWIP_UDPLITE +  /* UDP Lite protocol? */ +  if (pcb->flags & UDP_FLAGS_UDPLITE) { +    u16_t chklen, chklen_hdr; +    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); +    /* set UDP message length in UDP header */ +    chklen_hdr = chklen = pcb->chksum_len_tx; +    if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { +      if (chklen != 0) { +        LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); +      } +      /* For UDP-Lite, checksum length of 0 means checksum +         over the complete packet. (See RFC 3828 chap. 3.1) +         At least the UDP-Lite header must be covered by the +         checksum, therefore, if chksum_len has an illegal +         value, we generate the checksum over the complete +         packet to be safe. */ +      chklen_hdr = 0; +      chklen = q->tot_len; +    } +    udphdr->len = htons(chklen_hdr); +    /* calculate checksum */ +#if CHECKSUM_GEN_UDP +    udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, +                                        IP_PROTO_UDPLITE, q->tot_len, chklen); +    /* chksum zero must become 0xffff, as zero means 'no checksum' */ +    if (udphdr->chksum == 0x0000) +      udphdr->chksum = 0xffff; +#endif /* CHECKSUM_CHECK_UDP */ +    /* output to IP */ +    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ +    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ +  } else +#endif /* LWIP_UDPLITE */ +  {      /* UDP */ +    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); +    udphdr->len = htons(q->tot_len); +    /* calculate checksum */ +#if CHECKSUM_GEN_UDP +    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { +      udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); +      /* chksum zero must become 0xffff, as zero means 'no checksum' */ +      if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; +    } +#endif /* CHECKSUM_CHECK_UDP */ +    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); +    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); +    /* output to IP */ +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ +    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ +  } +  /* TODO: must this be increased even if error occured? */ +  snmp_inc_udpoutdatagrams(); + +  /* did we chain a separate header pbuf earlier? */ +  if (q != p) { +    /* free the header pbuf */ +    pbuf_free(q); +    q = NULL; +    /* p is still referenced by the caller, and will live on */ +  } + +  UDP_STATS_INC(udp.xmit); +  return err; +} + +/** + * Bind an UDP PCB. + * + * @param pcb UDP PCB to be bound with a local address ipaddr and port. + * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to + * bind to all local interfaces. + * @param port local UDP port to bind with. Use 0 to automatically bind + * to a random port between UDP_LOCAL_PORT_RANGE_START and + * UDP_LOCAL_PORT_RANGE_END. + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * @return lwIP error code. + * - ERR_OK. Successful. No error occured. + * - ERR_USE. The specified ipaddr and port are already bound to by + * another UDP PCB. + * + * @see udp_disconnect() + */ +err_t +udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ +  struct udp_pcb *ipcb; +  u8_t rebind; + +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = ")); +  ip_addr_debug_print(UDP_DEBUG, ipaddr); +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port)); + +  rebind = 0; +  /* Check for double bind and rebind of the same pcb */ +  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { +    /* is this UDP PCB already on active list? */ +    if (pcb == ipcb) { +      /* pcb may occur at most once in active list */ +      LWIP_ASSERT("rebind == 0", rebind == 0); +      /* pcb already in list, just rebind */ +      rebind = 1; +    } + +    /* this code does not allow upper layer to share a UDP port for +       listening to broadcast or multicast traffic (See SO_REUSE_ADDR and +       SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR +       combine with implementation of UDP PCB flags. Leon Woestenberg. */ +#ifdef LWIP_UDP_TODO +    /* port matches that of PCB in list? */ +    else +      if ((ipcb->local_port == port) && +          /* IP address matches, or one is IP_ADDR_ANY? */ +          (ip_addr_isany(&(ipcb->local_ip)) || +           ip_addr_isany(ipaddr) || +           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { +        /* other PCB already binds to this local IP and port */ +        LWIP_DEBUGF(UDP_DEBUG, +                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); +        return ERR_USE; +      } +#endif +  } + +  ip_addr_set(&pcb->local_ip, ipaddr); + +  /* no port specified? */ +  if (port == 0) { +#ifndef UDP_LOCAL_PORT_RANGE_START +#define UDP_LOCAL_PORT_RANGE_START 4096 +#define UDP_LOCAL_PORT_RANGE_END   0x7fff +#endif +    port = UDP_LOCAL_PORT_RANGE_START; +    ipcb = udp_pcbs; +    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) { +      if (ipcb->local_port == port) { +        /* port is already used by another udp_pcb */ +        port++; +        /* restart scanning all udp pcbs */ +        ipcb = udp_pcbs; +      } else +        /* go on with next udp pcb */ +        ipcb = ipcb->next; +    } +    if (ipcb != NULL) { +      /* no more ports available in local range */ +      LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); +      return ERR_USE; +    } +  } +  pcb->local_port = port; +  snmp_insert_udpidx_tree(pcb); +  /* pcb not active yet? */ +  if (rebind == 0) { +    /* place the PCB on the active list if not already there */ +    pcb->next = udp_pcbs; +    udp_pcbs = pcb; +  } +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, +              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", +               (u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff), +               (u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff), +               (u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff), +               (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port)); +  return ERR_OK; +} +/** + * Connect an UDP PCB. + * + * This will associate the UDP PCB with the remote address. + * + * @param pcb UDP PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * @param port remote UDP port to connect with. + * + * @return lwIP error code + * + * ipaddr & port are expected to be in the same byte order as in the pcb. + * + * The udp pcb is bound to a random local port if not already bound. + * + * @see udp_disconnect() + */ +err_t +udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ +  struct udp_pcb *ipcb; + +  if (pcb->local_port == 0) { +    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); +    if (err != ERR_OK) +      return err; +  } + +  ip_addr_set(&pcb->remote_ip, ipaddr); +  pcb->remote_port = port; +  pcb->flags |= UDP_FLAGS_CONNECTED; +/** TODO: this functionality belongs in upper layers */ +#ifdef LWIP_UDP_TODO +  /* Nail down local IP for netconn_addr()/getsockname() */ +  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) { +    struct netif *netif; + +    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) { +      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr)); +      UDP_STATS_INC(udp.rterr); +      return ERR_RTE; +    } +    /** TODO: this will bind the udp pcb locally, to the interface which +        is used to route output packets to the remote address. However, we +        might want to accept incoming packets on any interface! */ +    pcb->local_ip = netif->ip_addr; +  } else if (ip_addr_isany(&pcb->remote_ip)) { +    pcb->local_ip.addr = 0; +  } +#endif +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, +              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", +               (u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff), +               (u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff), +               (u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff), +               (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port)); + +  /* Insert UDP PCB into the list of active UDP PCBs. */ +  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { +    if (pcb == ipcb) { +      /* already on the list, just return */ +      return ERR_OK; +    } +  } +  /* PCB not yet on the list, add PCB now */ +  pcb->next = udp_pcbs; +  udp_pcbs = pcb; +  return ERR_OK; +} + +/** + * Disconnect a UDP PCB + * + * @param pcb the udp pcb to disconnect. + */ +void +udp_disconnect(struct udp_pcb *pcb) +{ +  /* reset remote address association */ +  ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY); +  pcb->remote_port = 0; +  /* mark PCB as unconnected */ +  pcb->flags &= ~UDP_FLAGS_CONNECTED; +} + +/** + * Set a receive callback for a UDP PCB + * + * This callback will be called when receiving a datagram for the pcb. + * + * @param pcb the pcb for wich to set the recv callback + * @param recv function pointer of the callback function + * @param recv_arg additional argument to pass to the callback function + */ +void +udp_recv(struct udp_pcb *pcb, +         void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, +                       struct ip_addr *addr, u16_t port), +         void *recv_arg) +{ +  /* remember recv() callback and user data */ +  pcb->recv = recv; +  pcb->recv_arg = recv_arg; +} + +/** + * Remove an UDP PCB. + * + * @param pcb UDP PCB to be removed. The PCB is removed from the list of + * UDP PCB's and the data structure is freed from memory. + * + * @see udp_new() + */ +void +udp_remove(struct udp_pcb *pcb) +{ +  struct udp_pcb *pcb2; + +  snmp_delete_udpidx_tree(pcb); +  /* pcb to be removed is first in list? */ +  if (udp_pcbs == pcb) { +    /* make list start at 2nd pcb */ +    udp_pcbs = udp_pcbs->next; +    /* pcb not 1st in list */ +  } else +    for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { +      /* find pcb in udp_pcbs list */ +      if (pcb2->next != NULL && pcb2->next == pcb) { +        /* remove pcb from list */ +        pcb2->next = pcb->next; +      } +    } +  memp_free(MEMP_UDP_PCB, pcb); +} + +/** + * Create a UDP PCB. + * + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * +udp_new(void) +{ +  struct udp_pcb *pcb; +  pcb = memp_malloc(MEMP_UDP_PCB); +  /* could allocate UDP PCB? */ +  if (pcb != NULL) { +    /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 +     * which means checksum is generated over the whole datagram per default +     * (recommended as default by RFC 3828). */ +    /* initialize PCB to all zeroes */ +    memset(pcb, 0, sizeof(struct udp_pcb)); +    pcb->ttl = UDP_TTL; +  } +  return pcb; +} + +#if UDP_DEBUG +/** + * Print UDP header information for debug purposes. + * + * @param udphdr pointer to the udp header in memory. + */ +void +udp_debug_print(struct udp_hdr *udphdr) +{ +  LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); +  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     %5"U16_F"     | (src port, dest port)\n", +                          ntohs(udphdr->src), ntohs(udphdr->dest))); +  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     0x%04"X16_F"    | (len, chksum)\n", +                          ntohs(udphdr->len), ntohs(udphdr->chksum))); +  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* UDP_DEBUG */ + +#endif /* LWIP_UDP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/autoip.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/autoip.h new file mode 100644 index 000000000..076a2ed23 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/autoip.h @@ -0,0 +1,105 @@ +/** + * @file + * + * AutoIP Automatic LinkLocal IP Configuration + */ + +/* + * + * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Dominik Spies <kontakt@dspies.de> + * + * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform + * with RFC 3927. + * + * + * Please coordinate changes and requests with Dominik Spies + * <kontakt@dspies.de> + */ +  +#ifndef __LWIP_AUTOIP_H__ +#define __LWIP_AUTOIP_H__ + +#include "lwip/opt.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "netif/etharp.h" + +/* AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL      100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/* RFC 3927 Constants */ +#define PROBE_WAIT               1   /* second   (initial random delay)                 */ +#define PROBE_MIN                1   /* second   (minimum delay till repeated probe)    */ +#define PROBE_MAX                2   /* seconds  (maximum delay till repeated probe)    */ +#define PROBE_NUM                3   /*          (number of probe packets)              */ +#define ANNOUNCE_NUM             2   /*          (number of announcement packets)       */ +#define ANNOUNCE_INTERVAL        2   /* seconds  (time between announcement packets)    */ +#define ANNOUNCE_WAIT            2   /* seconds  (delay before announcing)              */ +#define MAX_CONFLICTS            10  /*          (max conflicts before rate limiting)   */ +#define RATE_LIMIT_INTERVAL      60  /* seconds  (delay between successive attempts)    */ +#define DEFEND_INTERVAL          10  /* seconds  (min. wait between defensive ARPs)     */ + +/* AutoIP client states */ +#define AUTOIP_STATE_OFF         0 +#define AUTOIP_STATE_PROBING     1 +#define AUTOIP_STATE_ANNOUNCING  2 +#define AUTOIP_STATE_BOUND       3 + +struct autoip +{ +  struct ip_addr llipaddr;  /* the currently selected, probed, announced or used LL IP-Address */ +  u8_t state;               /* current AutoIP state machine state */ +  u8_t sent_num;            /* sent number of probes or announces, dependent on state */ +  u16_t ttw;                /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ +  u8_t lastconflict;        /* ticks until a conflict can be solved by defending */ +  u8_t tried_llipaddr;      /* total number of probed/used Link Local IP-Addresses */ +}; + + +/** Init srand, has to be called before entering mainloop */ +void autoip_init(void); + +/** Start AutoIP client */ +err_t autoip_start(struct netif *netif); + +/** Stop AutoIP client */ +err_t autoip_stop(struct netif *netif); + +/** Handles every incoming ARP Packet, called by etharp_arp_input */ +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); + +/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ +void autoip_tmr(void); + +#endif /* LWIP_AUTOIP */ + +#endif /* __LWIP_AUTOIP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/icmp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/icmp.h new file mode 100644 index 000000000..ff838f43a --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/icmp.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/opt.h" + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0      /* echo reply */ +#define ICMP_DUR 3     /* destination unreachable */ +#define ICMP_SQ 4      /* source quench */ +#define ICMP_RD 5      /* redirect */ +#define ICMP_ECHO 8    /* echo */ +#define ICMP_TE 11     /* time exceeded */ +#define ICMP_PP 12     /* parameter problem */ +#define ICMP_TS 13     /* timestamp */ +#define ICMP_TSR 14    /* timestamp reply */ +#define ICMP_IRQ 15    /* information request */ +#define ICMP_IR 16     /* information reply */ + +enum icmp_dur_type { +  ICMP_DUR_NET = 0,    /* net unreachable */ +  ICMP_DUR_HOST = 1,   /* host unreachable */ +  ICMP_DUR_PROTO = 2,  /* protocol unreachable */ +  ICMP_DUR_PORT = 3,   /* port unreachable */ +  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */ +  ICMP_DUR_SR = 5      /* source route failed */ +}; + +enum icmp_te_type { +  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */ +  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */ +}; + +void icmp_input(struct pbuf *p, struct netif *inp); + +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + *  is splitted to two u16_t like ICMP echo needs it. + *  This header is also used for other ICMP types that do not + *  use the data part. + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { +  PACK_STRUCT_FIELD(u8_t type); +  PACK_STRUCT_FIELD(u8_t code); +  PACK_STRUCT_FIELD(u16_t chksum); +  PACK_STRUCT_FIELD(u16_t id); +  PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) + +/** Combines type and code to an u16_t */ +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ICMP */ + +#endif /* __LWIP_ICMP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/igmp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/igmp.h new file mode 100644 index 000000000..59c933f35 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/igmp.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2002 CITEL Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without  + * modification, are permitted provided that the following conditions  + * are met:  + * 1. Redistributions of source code must retain the above copyright  + *    notice, this list of conditions and the following disclaimer.  + * 2. Redistributions in binary form must reproduce the above copyright  + *    notice, this list of conditions and the following disclaimer in the  + *    documentation and/or other materials provided with the distribution.  + * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors  + *    may be used to endorse or promote products derived from this software  + *    without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  + * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE  + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  + * SUCH DAMAGE.  + * + * This file is a contribution to the lwIP TCP/IP stack. + * The Swedish Institute of Computer Science and Adam Dunkels + * are specifically granted permission to redistribute this + * source code. +*/ + +#ifndef __LWIP_IGMP_H__ +#define __LWIP_IGMP_H__ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*  + * IGMP constants + */ +#define IP_PROTO_IGMP                  2 +#define IGMP_TTL                       1 +#define IGMP_MINLEN                    8 +#define ROUTER_ALERT                   0x9404 +#define ROUTER_ALERTLEN                4 + +/* + * IGMP message types, including version number. + */ +#define IGMP_MEMB_QUERY                0x11 /* Membership query         */ +#define IGMP_V1_MEMB_REPORT            0x12 /* Ver. 1 membership report */ +#define IGMP_V2_MEMB_REPORT            0x16 /* Ver. 2 membership report */ +#define IGMP_LEAVE_GROUP               0x17 /* Leave-group message      */ + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL              100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR   (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* MAC Filter Actions */ +#define IGMP_DEL_MAC_FILTER            0 +#define IGMP_ADD_MAC_FILTER            1 + +/* Group  membership states */ +#define IGMP_GROUP_NON_MEMBER          0 +#define IGMP_GROUP_DELAYING_MEMBER     1 +#define IGMP_GROUP_IDLE_MEMBER         2 + +/* + * IGMP packet format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_msg { + PACK_STRUCT_FIELD(u8_t           igmp_msgtype); + PACK_STRUCT_FIELD(u8_t           igmp_maxresp); + PACK_STRUCT_FIELD(u16_t          igmp_checksum); + PACK_STRUCT_FIELD(struct ip_addr igmp_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/*  + * now a group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + *  + * There will be a group for the all systems group address but this  + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ + +struct igmp_group { +  struct igmp_group *next; +  struct netif      *interface; +  struct ip_addr     group_address; +  u8_t               last_reporter_flag; /* signifies we were the last person to report */ +  u8_t               group_state; +  u16_t              timer; +  u8_t               use; /* counter of simultaneous uses */ +}; + + +/*  Prototypes */ +void   igmp_init(void); + +err_t  igmp_start( struct netif *netif); + +err_t  igmp_stop( struct netif *netif); + +void   igmp_report_groups( struct netif *netif); + +struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr); + +struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr); + +err_t  igmp_remove_group( struct igmp_group *group); + +void   igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest); + +err_t  igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr); + +err_t  igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr); + +void   igmp_tmr(void); + +void   igmp_timeout( struct igmp_group *group); + +void   igmp_start_timer( struct igmp_group *group, u8_t max_time); + +void   igmp_stop_timer( struct igmp_group *group); + +void   igmp_delaying_member( struct igmp_group *group, u8_t maxresp); + +err_t  igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif); + +void   igmp_send( struct igmp_group *group, u8_t type); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IGMP */ + +#endif /* __LWIP_IGMP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet.h new file mode 100644 index 000000000..6f30d0d12 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* For compatibility with BSD code */ +struct in_addr { +  u32_t s_addr; +}; + +#define INADDR_NONE         ((u32_t)0xffffffffUL)  /* 255.255.255.255 */ +#define INADDR_LOOPBACK     ((u32_t)0x7f000001UL)  /* 127.0.0.1 */ +#define INADDR_ANY          ((u32_t)0x00000000UL)  /* 0.0.0.0 */ +#define INADDR_BROADCAST    ((u32_t)0xffffffffUL)  /* 255.255.255.255 */ + +u32_t inet_addr(const char *cp); +int inet_aton(const char *cp, struct in_addr *addr); +char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#ifndef LWIP_PLATFORM_BYTESWAP +#define LWIP_PLATFORM_BYTESWAP 0 +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define htons(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define ntohl(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#ifdef LWIP_PREFIX_BYTEORDER_FUNCS +/* workaround for naming collisions on some platforms */ +#define htons lwip_htons +#define ntohs lwip_ntohs +#define htonl lwip_htonl +#define ntohl lwip_ntohl +#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ +#if LWIP_PLATFORM_BYTESWAP +#define htons(x) LWIP_PLATFORM_HTONS(x) +#define ntohs(x) LWIP_PLATFORM_HTONS(x) +#define htonl(x) LWIP_PLATFORM_HTONL(x) +#define ntohl(x) LWIP_PLATFORM_HTONL(x) +#else /* LWIP_PLATFORM_BYTESWAP */ +u16_t htons(u16_t x); +u16_t ntohs(u16_t x); +u32_t htonl(u32_t x); +u32_t ntohl(u32_t x); +#endif /* LWIP_PLATFORM_BYTESWAP */ + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet_chksum.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet_chksum.h new file mode 100644 index 000000000..5cae59cbd --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet_chksum.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_INET_CHKSUM_H__ +#define __LWIP_INET_CHKSUM_H__ + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(void *dataptr, u16_t len); +u16_t inet_chksum_pbuf(struct pbuf *p); +u16_t inet_chksum_pseudo(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len); +#if LWIP_UDPLITE +u16_t inet_chksum_pseudo_partial(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len, u16_t chksum_len); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip.h new file mode 100644 index 000000000..14eba3ca5 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND   LWIP_IGMP + +#define IP_HLEN 20 + +#define IP_PROTO_ICMP    1 +#define IP_PROTO_UDP     17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP     6 + +/* This is passed as the destination address to ip_output_if (not +   to ip_output), meaning that an IP header already is constructed +   in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL  NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/* This is the common part of all PCB types. It needs to be at the +   beginning of a PCB type definition. It is located here so that +   changes to this common part are made in one location instead of +   having to change all PCB structs. */ +#define IP_PCB \ +  /* ip addresses in network byte order */ \ +  struct ip_addr local_ip; \ +  struct ip_addr remote_ip; \ +   /* Socket options */  \ +  u16_t so_options;      \ +   /* Type Of Service */ \ +  u8_t tos;              \ +  /* Time To Live */     \ +  u8_t ttl               \ +  /* link layer address resolution hint */ \ +  IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ +  IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +#define SOF_DEBUG       (u16_t)0x0001U    /* turn on debugging info recording */ +#define SOF_ACCEPTCONN  (u16_t)0x0002U    /* socket has had listen() */ +#define SOF_REUSEADDR   (u16_t)0x0004U    /* allow local address reuse */ +#define SOF_KEEPALIVE   (u16_t)0x0008U    /* keep connections alive */ +#define SOF_DONTROUTE   (u16_t)0x0010U    /* just use interface addresses */ +#define SOF_BROADCAST   (u16_t)0x0020U    /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define SOF_USELOOPBACK (u16_t)0x0040U    /* bypass hardware when possible */ +#define SOF_LINGER      (u16_t)0x0080U    /* linger on close if data present */ +#define SOF_OOBINLINE   (u16_t)0x0100U    /* leave received OOB data in line */ +#define SOF_REUSEPORT   (u16_t)0x0200U    /* allow local address & port reuse */ + + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_hdr { +  /* version / header length / type of service */ +  PACK_STRUCT_FIELD(u16_t _v_hl_tos); +  /* total length */ +  PACK_STRUCT_FIELD(u16_t _len); +  /* identification */ +  PACK_STRUCT_FIELD(u16_t _id); +  /* fragment offset field */ +  PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000        /* reserved fragment flag */ +#define IP_DF 0x4000        /* dont fragment flag */ +#define IP_MF 0x2000        /* more fragments flag */ +#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */ +  /* time to live / protocol*/ +  PACK_STRUCT_FIELD(u16_t _ttl_proto); +  /* checksum */ +  PACK_STRUCT_FIELD(u16_t _chksum); +  /* source and destination IP addresses */ +  PACK_STRUCT_FIELD(struct ip_addr src); +  PACK_STRUCT_FIELD(struct ip_addr dest);  +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define IPH_V(hdr)  (ntohs((hdr)->_v_hl_tos) >> 12) +#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) +#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8) +#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8))) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8))) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + +#define ip_init() /* Compatibility define, not init needed. */ +struct netif *ip_route(struct ip_addr *dest); +err_t ip_input(struct pbuf *p, struct netif *inp); +err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto); +err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto, +       struct netif *netif); +#if LWIP_NETIF_HWADDRHINT +err_t ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, +       u16_t optlen); +#endif /* IP_OPTIONS_SEND */ +struct netif *ip_current_netif(void); +const struct ip_hdr *ip_current_header(void); +#if IP_DEBUG +void ip_debug_print(struct pbuf *p); +#else +#define ip_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_addr.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_addr.h new file mode 100644 index 000000000..f2e4c2233 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_addr.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" + +#include "lwip/inet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr { +  PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/* + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { +  PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +struct netif; + +extern const struct ip_addr ip_addr_any; +extern const struct ip_addr ip_addr_broadcast; + +/** IP_ADDR_ can be used as a fixed IP address + *  for the wildcard and the broadcast address + */ +#define IP_ADDR_ANY         ((struct ip_addr *)&ip_addr_any) +#define IP_ADDR_BROADCAST   ((struct ip_addr *)&ip_addr_broadcast) + +/* Definitions of the bits in an Internet address integer. + +   On subnets, host and network parts are found according to +   the subnet mask, not these masks.  */ + +#define IN_CLASSA(a)        ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IN_CLASSA_NET       0xff000000 +#define IN_CLASSA_NSHIFT    24 +#define IN_CLASSA_HOST      (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX       128 + +#define IN_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IN_CLASSB_NET       0xffff0000 +#define IN_CLASSB_NSHIFT    16 +#define IN_CLASSB_HOST      (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX       65536 + +#define IN_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IN_CLASSC_NET       0xffffff00 +#define IN_CLASSC_NSHIFT    8 +#define IN_CLASSC_HOST      (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a)        (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IN_CLASSD_NET       0xf0000000          /* These ones aren't really */ +#define IN_CLASSD_NSHIFT    28                  /*   net and host fields, but */ +#define IN_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */ +#define IN_MULTICAST(a)     IN_CLASSD(a) + +#define IN_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IN_BADCLASS(a)      (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IN_LOOPBACKNET      127                 /* official! */ + +#define IP4_ADDR(ipaddr, a,b,c,d) \ +        (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \ +                               ((u32_t)((b) & 0xff) << 16) | \ +                               ((u32_t)((c) & 0xff) << 8) | \ +                                (u32_t)((d) & 0xff)) + +#define ip_addr_set(dest, src) (dest)->addr = \ +                               ((src) == NULL? 0:\ +                               (src)->addr) +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ +                                              (mask)->addr) == \ +                                             ((addr2)->addr & \ +                                              (mask)->addr)) +#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0) + +u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *); + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL)) + +#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL)) + +#define ip_addr_debug_print(debug, ipaddr) \ +  LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F,              \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0,  \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0,  \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0,   \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)ntohl((ipaddr)->addr) & 0xff : 0)) + +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff) +#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff) +#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff) +#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_frag.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_frag.h new file mode 100644 index 000000000..380e604dc --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_frag.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Jani Monoses <jani@iv.ro> + * + */ + +#ifndef __LWIP_IP_FRAG_H__ +#define __LWIP_IP_FRAG_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/* IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { +  struct ip_reassdata *next; +  struct pbuf *p; +  struct ip_hdr iphdr; +  u16_t datagram_len; +  u8_t flags; +  u8_t timer; +}; + +void ip_reass_init(void); +void ip_reass_tmr(void); +struct pbuf * ip_reass(struct pbuf *p); +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest); +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_FRAG_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/icmp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/icmp.h new file mode 100644 index 000000000..87e9ffd96 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/icmp.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/opt.h" + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP6_DUR  1 +#define ICMP6_TE   3 +#define ICMP6_ECHO 128    /* echo */ +#define ICMP6_ER   129      /* echo reply */ + + +enum icmp_dur_type { +  ICMP_DUR_NET = 0,    /* net unreachable */ +  ICMP_DUR_HOST = 1,   /* host unreachable */ +  ICMP_DUR_PROTO = 2,  /* protocol unreachable */ +  ICMP_DUR_PORT = 3,   /* port unreachable */ +  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */ +  ICMP_DUR_SR = 5      /* source route failed */ +}; + +enum icmp_te_type { +  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */ +  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */ +}; + +void icmp_input(struct pbuf *p, struct netif *inp); + +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +struct icmp_echo_hdr { +  u8_t type; +  u8_t icode; +  u16_t chksum; +  u16_t id; +  u16_t seqno; +}; + +struct icmp_dur_hdr { +  u8_t type; +  u8_t icode; +  u16_t chksum; +  u32_t unused; +}; + +struct icmp_te_hdr { +  u8_t type; +  u8_t icode; +  u16_t chksum; +  u32_t unused; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ICMP */ + +#endif /* __LWIP_ICMP_H__ */ + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/inet.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/inet.h new file mode 100644 index 000000000..de1a0b636 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/inet.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(void *data, u16_t len); +u16_t inet_chksum_pbuf(struct pbuf *p); +u16_t inet_chksum_pseudo(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u32_t proto_len); + +u32_t inet_addr(const char *cp); +s8_t inet_aton(const char *cp, struct in_addr *addr); + +#ifndef _MACHINE_ENDIAN_H_ +#ifndef _NETINET_IN_H +#ifndef _LINUX_BYTEORDER_GENERIC_H +u16_t htons(u16_t n); +u16_t ntohs(u16_t n); +u32_t htonl(u32_t n); +u32_t ntohl(u32_t n); +#endif /* _LINUX_BYTEORDER_GENERIC_H */ +#endif /* _NETINET_IN_H */ +#endif /* _MACHINE_ENDIAN_H_ */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip.h new file mode 100644 index 000000000..a01cfc65b --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_HLEN 40 + +#define IP_PROTO_ICMP    58 +#define IP_PROTO_UDP     17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP     6 + +/* This is passed as the destination address to ip_output_if (not +   to ip_output), meaning that an IP header already is constructed +   in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL  NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/* This is the common part of all PCB types. It needs to be at the +   beginning of a PCB type definition. It is located here so that +   changes to this common part are made in one location instead of +   having to change all PCB structs. */ +#define IP_PCB struct ip_addr local_ip; \ +  struct ip_addr remote_ip; \ +   /* Socket options */  \ +  u16_t so_options;      \ +   /* Type Of Service */ \ +  u8_t tos;              \ +  /* Time To Live */     \ +  u8_t ttl;              \ +  /* link layer address resolution hint */ \ +  IP_PCB_ADDRHINT + + +/* The IPv6 header. */ +struct ip_hdr { +#if BYTE_ORDER == LITTLE_ENDIAN +  u8_t tclass1:4, v:4; +  u8_t flow1:4, tclass2:4;   +#else +  u8_t v:4, tclass1:4; +  u8_t tclass2:8, flow1:4; +#endif +  u16_t flow2; +  u16_t len;                /* payload length */ +  u8_t nexthdr;             /* next header */ +  u8_t hoplim;              /* hop limit (TTL) */ +  struct ip_addr src, dest;          /* source and destination IP addresses */ +}; + +#define IPH_PROTO(hdr) (iphdr->nexthdr) + +void ip_init(void); + +#include "lwip/netif.h" + +struct netif *ip_route(struct ip_addr *dest); + +void ip_input(struct pbuf *p, struct netif *inp); + +/* source and destination addresses in network byte order, please */ +err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +         u8_t ttl, u8_t proto); + +err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +      u8_t ttl, u8_t proto, +      struct netif *netif); + +#define ip_current_netif() NULL +#define ip_current_header() NULL + +#if IP_DEBUG +void ip_debug_print(struct pbuf *p); +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip_addr.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip_addr.h new file mode 100644 index 000000000..b2d8ae566 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip_addr.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_ADDR_ANY 0 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN + struct ip_addr { +  PACK_STRUCT_FIELD(u32_t addr[4]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/* + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { +  PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \ +                                               (ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \ +                                               (ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \ +                                               (ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0) + +u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2, +        struct ip_addr *mask); +u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2); +void ip_addr_set(struct ip_addr *dest, struct ip_addr *src); +u8_t ip_addr_isany(struct ip_addr *addr); + +#define ip_addr_debug_print(debug, ipaddr) \ +        LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \ +         (ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[0]) & 0xffff, \ +         (ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[1]) & 0xffff, \ +         (ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[2]) & 0xffff, \ +         (ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[3]) & 0xffff)); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/api.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/api.h new file mode 100644 index 000000000..f6b1f7434 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/api.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_API_H__ +#define __LWIP_API_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include <stddef.h> /* for size_t */ + +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY   0x01 +#define NETCONN_MORE   0x02 + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t)    (t&0xF0) +#define NETCONNTYPE_DATAGRAM(t) (t&0xE0) + +enum netconn_type { +  NETCONN_INVALID    = 0, +  /* NETCONN_TCP Group */ +  NETCONN_TCP        = 0x10, +  /* NETCONN_UDP Group */ +  NETCONN_UDP        = 0x20, +  NETCONN_UDPLITE    = 0x21, +  NETCONN_UDPNOCHKSUM= 0x22, +  /* NETCONN_RAW Group */ +  NETCONN_RAW        = 0x40 +}; + +enum netconn_state { +  NETCONN_NONE, +  NETCONN_WRITE, +  NETCONN_LISTEN, +  NETCONN_CONNECT, +  NETCONN_CLOSE +}; + +enum netconn_evt { +  NETCONN_EVT_RCVPLUS, +  NETCONN_EVT_RCVMINUS, +  NETCONN_EVT_SENDPLUS, +  NETCONN_EVT_SENDMINUS +}; + +#if LWIP_IGMP +enum netconn_igmp { +  NETCONN_JOIN, +  NETCONN_LEAVE +}; +#endif /* LWIP_IGMP */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { +  /** type of the netconn (TCP, UDP or RAW) */ +  enum netconn_type type; +  /** current state of the netconn */ +  enum netconn_state state; +  /** the lwIP internal protocol control block */ +  union { +    struct ip_pcb  *ip; +    struct tcp_pcb *tcp; +    struct udp_pcb *udp; +    struct raw_pcb *raw; +  } pcb; +  /** the last error this netconn had */ +  err_t err; +  /** sem that is used to synchroneously execute functions in the core context */ +  sys_sem_t op_completed; +  /** mbox where received packets are stored until they are fetched +      by the netconn application thread (can grow quite big) */ +  sys_mbox_t recvmbox; +  /** mbox where new connections are stored until processed +      by the application thread */ +  sys_mbox_t acceptmbox; +  /** only used for socket layer */ +  int socket; +#if LWIP_SO_RCVTIMEO +  /** timeout to wait for new data to be received +      (or connections to arrive for listening netconns) */ +  int recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +  /** maximum amount of bytes queued in recvmbox */ +  int recv_bufsize; +#endif /* LWIP_SO_RCVBUF */ +  s16_t recv_avail; +#if LWIP_TCP +  /** TCP: when data passed to netconn_write doesn't fit into the send buffer, +      this temporarily stores the message. */ +  struct api_msg_msg *write_msg; +  /** TCP: when data passed to netconn_write doesn't fit into the send buffer, +      this temporarily stores how much is already sent. */ +  size_t write_offset; +#if LWIP_TCPIP_CORE_LOCKING +  /** TCP: when data passed to netconn_write doesn't fit into the send buffer, +      this temporarily stores whether to wake up the original application task +      if data couldn't be sent in the first try. */ +  u8_t write_delayed; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_TCP */ +  /** A callback function that is informed about events for this netconn */ +  netconn_callback callback; +}; + +/* Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) {         \ +                           (*c->callback)(c, e, l); \ +                         } + +/* Network connection functions: */ +#define netconn_new(t)                  netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct +netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, +                                   netconn_callback callback); +err_t             netconn_delete  (struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t             netconn_getaddr (struct netconn *conn, +                                   struct ip_addr *addr, +                                   u16_t *port, +                                   u8_t local); +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t             netconn_bind    (struct netconn *conn, +                                   struct ip_addr *addr, +                                   u16_t port); +err_t             netconn_connect (struct netconn *conn, +                                   struct ip_addr *addr, +                                   u16_t port); +err_t             netconn_disconnect (struct netconn *conn); +err_t             netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +struct netconn *  netconn_accept  (struct netconn *conn); +struct netbuf *   netconn_recv    (struct netconn *conn); +err_t             netconn_sendto  (struct netconn *conn, +                                   struct netbuf *buf, struct ip_addr *addr, u16_t port); +err_t             netconn_send    (struct netconn *conn, +                                   struct netbuf *buf); +err_t             netconn_write   (struct netconn *conn, +                                   const void *dataptr, size_t size, +                                   u8_t apiflags); +err_t             netconn_close   (struct netconn *conn); + +#if LWIP_IGMP +err_t             netconn_join_leave_group (struct netconn *conn, +                                            struct ip_addr *multiaddr, +                                            struct ip_addr *interface, +                                            enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP */ +#if LWIP_DNS +err_t             netconn_gethostbyname(const char *name, struct ip_addr *addr); +#endif /* LWIP_DNS */ + +#define netconn_err(conn)          ((conn)->err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/api_msg.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/api_msg.h new file mode 100644 index 000000000..4272d77cc --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/api_msg.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_API_MSG_H__ +#define __LWIP_API_MSG_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include <stddef.h> /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function +    for a netconn in another thread context (mainly used to process netconns +    in the tcpip_thread context to be thread safe). */ +struct api_msg_msg { +  /** The netconn which to process - always needed: it includes the semaphore +      which is used to block the application thread until the function finished. */ +  struct netconn *conn; +  /** Depending on the executed function, one of these union members is used */ +  union { +    /** used for do_send */ +    struct netbuf *b; +    /** used for do_newconn */ +    struct { +      u8_t proto; +    } n; +    /** used for do_bind and do_connect */ +    struct { +      struct ip_addr *ipaddr; +      u16_t port; +    } bc; +    /** used for do_getaddr */ +    struct { +      struct ip_addr *ipaddr; +      u16_t *port; +      u8_t local; +    } ad; +    /** used for do_write */ +    struct { +      const void *dataptr; +      size_t len; +      u8_t apiflags; +    } w; +    /** used ofr do_recv */ +    struct { +      u16_t len; +    } r; +#if LWIP_IGMP +    /** used for do_join_leave_group */ +    struct { +      struct ip_addr *multiaddr; +      struct ip_addr *interface; +      enum netconn_igmp join_or_leave; +    } jl; +#endif /* LWIP_IGMP */ +#if TCP_LISTEN_BACKLOG +    struct { +      u8_t backlog; +    } lb; +#endif /* TCP_LISTEN_BACKLOG */ +  } msg; +}; + +/** This struct contains a function to execute in another thread context and +    a struct api_msg_msg that serves as an argument for this function. +    This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ +struct api_msg { +  /** function to execute in tcpip_thread context */ +  void (* function)(struct api_msg_msg *msg); +  /** arguments for this function */ +  struct api_msg_msg msg; +}; + +#if LWIP_DNS +/** As do_gethostbyname requires more arguments but doesn't require a netconn, +    it has its own struct (to avoid struct api_msg getting bigger than necessary). +    do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg +    (see netconn_gethostbyname). */ +struct dns_api_msg { +  /** Hostname to query or dotted IP address string */ +  const char *name; +  /** Rhe resolved address is stored here */ +  struct ip_addr *addr; +  /** This semaphore is posted when the name is resolved, the application thread +      should wait on it. */ +  sys_sem_t sem; +  /** Errors are given back here */ +  err_t *err; +}; +#endif /* LWIP_DNS */ + +void do_newconn         ( struct api_msg_msg *msg); +void do_delconn         ( struct api_msg_msg *msg); +void do_bind            ( struct api_msg_msg *msg); +void do_connect         ( struct api_msg_msg *msg); +void do_disconnect      ( struct api_msg_msg *msg); +void do_listen          ( struct api_msg_msg *msg); +void do_send            ( struct api_msg_msg *msg); +void do_recv            ( struct api_msg_msg *msg); +void do_write           ( struct api_msg_msg *msg); +void do_getaddr         ( struct api_msg_msg *msg); +void do_close           ( struct api_msg_msg *msg); +#if LWIP_IGMP +void do_join_leave_group( struct api_msg_msg *msg); +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +void do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_MSG_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/arch.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/arch.h new file mode 100644 index 000000000..3a5a0e4f2 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/arch.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_ARCH_H__ +#define __LWIP_ARCH_H__ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** Temporary: define format string for size_t if not defined in cc.h */ +#ifndef SZT_F +#define SZT_F U32_F +#endif /* SZT_F */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + + +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */  + + +#ifdef LWIP_PROVIDE_ERRNO + +#define  EPERM     1  /* Operation not permitted */ +#define  ENOENT     2  /* No such file or directory */ +#define  ESRCH     3  /* No such process */ +#define  EINTR     4  /* Interrupted system call */ +#define  EIO     5  /* I/O error */ +#define  ENXIO     6  /* No such device or address */ +#define  E2BIG     7  /* Arg list too long */ +#define  ENOEXEC     8  /* Exec format error */ +#define  EBADF     9  /* Bad file number */ +#define  ECHILD    10  /* No child processes */ +#define  EAGAIN    11  /* Try again */ +#define  ENOMEM    12  /* Out of memory */ +#define  EACCES    13  /* Permission denied */ +#define  EFAULT    14  /* Bad address */ +#define  ENOTBLK    15  /* Block device required */ +#define  EBUSY    16  /* Device or resource busy */ +#define  EEXIST    17  /* File exists */ +#define  EXDEV    18  /* Cross-device link */ +#define  ENODEV    19  /* No such device */ +#define  ENOTDIR    20  /* Not a directory */ +#define  EISDIR    21  /* Is a directory */ +#define  EINVAL    22  /* Invalid argument */ +#define  ENFILE    23  /* File table overflow */ +#define  EMFILE    24  /* Too many open files */ +#define  ENOTTY    25  /* Not a typewriter */ +#define  ETXTBSY    26  /* Text file busy */ +#define  EFBIG    27  /* File too large */ +#define  ENOSPC    28  /* No space left on device */ +#define  ESPIPE    29  /* Illegal seek */ +#define  EROFS    30  /* Read-only file system */ +#define  EMLINK    31  /* Too many links */ +#define  EPIPE    32  /* Broken pipe */ +#define  EDOM    33  /* Math argument out of domain of func */ +#define  ERANGE    34  /* Math result not representable */ +#define  EDEADLK    35  /* Resource deadlock would occur */ +#define  ENAMETOOLONG  36  /* File name too long */ +#define  ENOLCK    37  /* No record locks available */ +#define  ENOSYS    38  /* Function not implemented */ +#define  ENOTEMPTY  39  /* Directory not empty */ +#define  ELOOP    40  /* Too many symbolic links encountered */ +#define  EWOULDBLOCK  EAGAIN  /* Operation would block */ +#define  ENOMSG    42  /* No message of desired type */ +#define  EIDRM    43  /* Identifier removed */ +#define  ECHRNG    44  /* Channel number out of range */ +#define  EL2NSYNC  45  /* Level 2 not synchronized */ +#define  EL3HLT    46  /* Level 3 halted */ +#define  EL3RST    47  /* Level 3 reset */ +#define  ELNRNG    48  /* Link number out of range */ +#define  EUNATCH    49  /* Protocol driver not attached */ +#define  ENOCSI    50  /* No CSI structure available */ +#define  EL2HLT    51  /* Level 2 halted */ +#define  EBADE    52  /* Invalid exchange */ +#define  EBADR    53  /* Invalid request descriptor */ +#define  EXFULL    54  /* Exchange full */ +#define  ENOANO    55  /* No anode */ +#define  EBADRQC    56  /* Invalid request code */ +#define  EBADSLT    57  /* Invalid slot */ + +#define  EDEADLOCK  EDEADLK + +#define  EBFONT    59  /* Bad font file format */ +#define  ENOSTR    60  /* Device not a stream */ +#define  ENODATA    61  /* No data available */ +#define  ETIME    62  /* Timer expired */ +#define  ENOSR    63  /* Out of streams resources */ +#define  ENONET    64  /* Machine is not on the network */ +#define  ENOPKG    65  /* Package not installed */ +#define  EREMOTE    66  /* Object is remote */ +#define  ENOLINK    67  /* Link has been severed */ +#define  EADV    68  /* Advertise error */ +#define  ESRMNT    69  /* Srmount error */ +#define  ECOMM    70  /* Communication error on send */ +#define  EPROTO    71  /* Protocol error */ +#define  EMULTIHOP  72  /* Multihop attempted */ +#define  EDOTDOT    73  /* RFS specific error */ +#define  EBADMSG    74  /* Not a data message */ +#define  EOVERFLOW  75  /* Value too large for defined data type */ +#define  ENOTUNIQ  76  /* Name not unique on network */ +#define  EBADFD    77  /* File descriptor in bad state */ +#define  EREMCHG    78  /* Remote address changed */ +#define  ELIBACC    79  /* Can not access a needed shared library */ +#define  ELIBBAD    80  /* Accessing a corrupted shared library */ +#define  ELIBSCN    81  /* .lib section in a.out corrupted */ +#define  ELIBMAX    82  /* Attempting to link in too many shared libraries */ +#define  ELIBEXEC  83  /* Cannot exec a shared library directly */ +#define  EILSEQ    84  /* Illegal byte sequence */ +#define  ERESTART  85  /* Interrupted system call should be restarted */ +#define  ESTRPIPE  86  /* Streams pipe error */ +#define  EUSERS    87  /* Too many users */ +#define  ENOTSOCK  88  /* Socket operation on non-socket */ +#define  EDESTADDRREQ  89  /* Destination address required */ +#define  EMSGSIZE  90  /* Message too long */ +#define  EPROTOTYPE  91  /* Protocol wrong type for socket */ +#define  ENOPROTOOPT  92  /* Protocol not available */ +#define  EPROTONOSUPPORT  93  /* Protocol not supported */ +#define  ESOCKTNOSUPPORT  94  /* Socket type not supported */ +#define  EOPNOTSUPP  95  /* Operation not supported on transport endpoint */ +#define  EPFNOSUPPORT  96  /* Protocol family not supported */ +#define  EAFNOSUPPORT  97  /* Address family not supported by protocol */ +#define  EADDRINUSE  98  /* Address already in use */ +#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */ +#define  ENETDOWN  100  /* Network is down */ +#define  ENETUNREACH  101  /* Network is unreachable */ +#define  ENETRESET  102  /* Network dropped connection because of reset */ +#define  ECONNABORTED  103  /* Software caused connection abort */ +#define  ECONNRESET  104  /* Connection reset by peer */ +#define  ENOBUFS    105  /* No buffer space available */ +#define  EISCONN    106  /* Transport endpoint is already connected */ +#define  ENOTCONN  107  /* Transport endpoint is not connected */ +#define  ESHUTDOWN  108  /* Cannot send after transport endpoint shutdown */ +#define  ETOOMANYREFS  109  /* Too many references: cannot splice */ +#define  ETIMEDOUT  110  /* Connection timed out */ +#define  ECONNREFUSED  111  /* Connection refused */ +#define  EHOSTDOWN  112  /* Host is down */ +#define  EHOSTUNREACH  113  /* No route to host */ +#define  EALREADY  114  /* Operation already in progress */ +#define  EINPROGRESS  115  /* Operation now in progress */ +#define  ESTALE    116  /* Stale NFS file handle */ +#define  EUCLEAN    117  /* Structure needs cleaning */ +#define  ENOTNAM    118  /* Not a XENIX named type file */ +#define  ENAVAIL    119  /* No XENIX semaphores available */ +#define  EISNAM    120  /* Is a named type file */ +#define  EREMOTEIO  121  /* Remote I/O error */ +#define  EDQUOT    122  /* Quota exceeded */ + +#define  ENOMEDIUM  123  /* No medium found */ +#define  EMEDIUMTYPE  124  /* Wrong medium type */ + + +#define ENSROK    0 /* DNS server returned answer with no data */ +#define ENSRNODATA  160 /* DNS server returned answer with no data */ +#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ +#define ENSRSERVFAIL 162  /* DNS server returned general failure */ +#define ENSRNOTFOUND 163  /* Domain name not found */ +#define ENSRNOTIMP  164 /* DNS server does not implement requested operation */ +#define ENSRREFUSED 165 /* DNS server refused query */ +#define ENSRBADQUERY 166  /* Misformatted DNS query */ +#define ENSRBADNAME 167 /* Misformatted domain name */ +#define ENSRBADFAMILY 168 /* Unsupported address family */ +#define ENSRBADRESP 169 /* Misformatted DNS reply */ +#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ +#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ +#define ENSROF    172 /* End of file */ +#define ENSRFILE  173 /* Error reading file */ +#define ENSRNOMEM 174 /* Out of memory */ +#define ENSRDESTRUCTION 175 /* Application terminated lookup */ +#define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */ +#define ENSRCNAMELOOP 177 /* Domain name is too long */ + +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ARCH_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/debug.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/debug.h new file mode 100644 index 000000000..d5c4e4747 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/debug.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_DEBUG_H__ +#define __LWIP_DEBUG_H__ + +#include "lwip/arch.h" + +/** lower two bits indicate debug level + * - 0 off + * - 1 warning + * - 2 serious + * - 3 severe + */ +#define LWIP_DBG_LEVEL_OFF     0x00 +#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SEVERE  0x03 +#define LWIP_DBG_MASK_LEVEL    0x03 + +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON            0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF           0x00U + +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE         0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE         0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH         0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT          0x08U + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ +  LWIP_PLATFORM_ASSERT(message); } while(0) +#else  /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion)  +#endif /* LWIP_NOASSERT */ + +/** if "expression" isn't true, then print "message" and execute "handler" expression */ +#ifndef LWIP_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ +  LWIP_PLATFORM_ASSERT(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +#ifdef LWIP_DEBUG +/** print debug message only if debug message type is enabled... + *  AND is of correct type AND is at least LWIP_DBG_LEVEL + */ +#define LWIP_DEBUGF(debug, message) do { \ +                               if ( \ +                                   ((debug) & LWIP_DBG_ON) && \ +                                   ((debug) & LWIP_DBG_TYPES_ON) && \ +                                   ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ +                                 LWIP_PLATFORM_DIAG(message); \ +                                 if ((debug) & LWIP_DBG_HALT) { \ +                                   while(1); \ +                                 } \ +                               } \ +                             } while(0) + +#else  /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message)  +#endif /* LWIP_DEBUG */ + +#endif /* __LWIP_DEBUG_H__ */ + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/def.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/def.h new file mode 100644 index 000000000..d2ed251df --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/def.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_DEF_H__ +#define __LWIP_DEF_H__ + +/* this might define NULL already */ +#include "lwip/arch.h" + +#define LWIP_MAX(x , y)  (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y)  (((x) < (y)) ? (x) : (y)) + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +#endif /* __LWIP_DEF_H__ */ + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/dhcp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/dhcp.h new file mode 100644 index 000000000..825dba6ec --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/dhcp.h @@ -0,0 +1,246 @@ +/** @file + */ + +#ifndef __LWIP_DHCP_H__ +#define __LWIP_DHCP_H__ + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60  +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500  + +struct dhcp +{ +  /** current DHCP state machine state */ +  u8_t state; +  /** retries of current request */ +  u8_t tries; +  /** transaction identifier of last sent request */  +  u32_t xid; +  /** our connection to the DHCP server */  +  struct udp_pcb *pcb; +  /** (first) pbuf of incoming msg */ +  struct pbuf *p; +  /** incoming msg */ +  struct dhcp_msg *msg_in; +  /** incoming msg options */ +  struct dhcp_msg *options_in;  +  /** ingoing msg options length */ +  u16_t options_in_len; + +  struct pbuf *p_out; /* pbuf of outcoming msg */ +  struct dhcp_msg *msg_out; /* outgoing msg */ +  u16_t options_out_len; /* outgoing msg options length */ +  u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ +  u16_t t1_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ +  u16_t t2_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ +  struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */ +  struct ip_addr offered_ip_addr; +  struct ip_addr offered_sn_mask; +  struct ip_addr offered_gw_addr; +  struct ip_addr offered_bc_addr; +#define DHCP_MAX_DNS 2 +  u32_t dns_count; /* actual number of DNS servers obtained */ +  struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */ +  +  u32_t offered_t0_lease; /* lease period (in seconds) */ +  u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ +  u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period)  */ +#if LWIP_DHCP_AUTOIP_COOP +  u8_t autoip_coop_state; +#endif +/** Patch #1308 + *  TODO: See dhcp.c "TODO"s + */ +#if 0 +  struct ip_addr offered_si_addr; +  u8_t *boot_file_name; +#endif +}; + +/* MUST be compiled with "pack structs" or equivalent! */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ +  PACK_STRUCT_FIELD(u8_t op); +  PACK_STRUCT_FIELD(u8_t htype); +  PACK_STRUCT_FIELD(u8_t hlen); +  PACK_STRUCT_FIELD(u8_t hops); +  PACK_STRUCT_FIELD(u32_t xid); +  PACK_STRUCT_FIELD(u16_t secs); +  PACK_STRUCT_FIELD(u16_t flags); +  PACK_STRUCT_FIELD(struct ip_addr ciaddr); +  PACK_STRUCT_FIELD(struct ip_addr yiaddr); +  PACK_STRUCT_FIELD(struct ip_addr siaddr); +  PACK_STRUCT_FIELD(struct ip_addr giaddr); +#define DHCP_CHADDR_LEN 16U +  PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); +#define DHCP_SNAME_LEN 64U +  PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); +#define DHCP_FILE_LEN 128U +  PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); +  PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +#  undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +#  define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif +  PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/** start DHCP configuration */ +err_t dhcp_start(struct netif *netif); +/** enforce early lease renewal (not needed normally)*/ +err_t dhcp_renew(struct netif *netif); +/** release the DHCP lease, usually called before dhcp_stop()*/ +err_t dhcp_release(struct netif *netif); +/** stop DHCP configuration */ +void dhcp_stop(struct netif *netif); +/** inform server of our manual IP address */ +void dhcp_inform(struct netif *netif); + +/** if enabled, check whether the offered IP address is not in use, using ARP */ +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr); +#endif + +/** to be called every minute */ +void dhcp_coarse_tmr(void); +/** to be called every half second */ +void dhcp_fine_tmr(void); +  +/** DHCP message item offsets and length */ +#define DHCP_MSG_OFS (UDP_DATA_OFS)   +  #define DHCP_OP_OFS (DHCP_MSG_OFS + 0) +  #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1) +  #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2) +  #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3) +  #define DHCP_XID_OFS (DHCP_MSG_OFS + 4) +  #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8) +  #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10) +  #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12) +  #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16) +  #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20) +  #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24) +  #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28) +  #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44) +  #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108) +#define DHCP_MSG_LEN 236 + +#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN) +#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4) + +#define DHCP_CLIENT_PORT 68   +#define DHCP_SERVER_PORT 67 + +/** DHCP client states */ +#define DHCP_REQUESTING 1 +#define DHCP_INIT 2 +#define DHCP_REBOOTING 3 +#define DHCP_REBINDING 4 +#define DHCP_RENEWING 5 +#define DHCP_SELECTING 6 +#define DHCP_INFORMING 7 +#define DHCP_CHECKING 8 +#define DHCP_PERMANENT 9 +#define DHCP_BOUND 10 +/** not yet implemented #define DHCP_RELEASING 11 */ +#define DHCP_BACKING_OFF 12 +#define DHCP_OFF 13 + +/** AUTOIP cooperatation flags */ +#define DHCP_AUTOIP_COOP_STATE_OFF 0 +#define DHCP_AUTOIP_COOP_STATE_ON 1 +  +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE_ETH 1 + +#define DHCP_HLEN_ETH 6 + +#define DHCP_BROADCAST_FLAG 15 +#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST) + +/** BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6  +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_END 255 + +/** DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/** possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME  2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*__LWIP_DHCP_H__*/ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/dns.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/dns.h new file mode 100644 index 000000000..e5f4b7a3d --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/dns.h @@ -0,0 +1,97 @@ +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato  + *   April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + *    products derived from this software without specific prior + *    written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LWIP_DNS_H__ +#define __LWIP_DNS_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +/** DNS timer period */ +#define DNS_TMR_INTERVAL          1000 + +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A              1     /* a host address */ +#define DNS_RRTYPE_NS             2     /* an authoritative name server */ +#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS            11    /* a well known service description */ +#define DNS_RRTYPE_PTR            12    /* a domain name pointer */ +#define DNS_RRTYPE_HINFO          13    /* host information */ +#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */ +#define DNS_RRTYPE_MX             15    /* mail exchange */ +#define DNS_RRTYPE_TXT            16    /* text strings */ + +/** DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN            1     /* the Internet */ +#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH            3     /* the CHAOS class */ +#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname, + *        or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg); + + +void           dns_init(void); + +void           dns_tmr(void); + +void           dns_setserver(u8_t numdns, struct ip_addr *dnsserver); + +struct ip_addr dns_getserver(u8_t numdns); + +err_t          dns_gethostbyname(const char *hostname, struct ip_addr *addr, +                                 dns_found_callback found, void *callback_arg); + +#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int            dns_local_removehost(const char *hostname, const struct ip_addr *addr); +err_t          dns_local_addhost(const char *hostname, const struct ip_addr *addr); +#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#endif /* LWIP_DNS */ + +#endif /* __LWIP_DNS_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/err.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/err.h new file mode 100644 index 000000000..696764454 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/err.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_ERR_H__ +#define __LWIP_ERR_H__ + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define LWIP_ERR_T in cc.h if you want to use + *  a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ + typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/* Definitions for error constants. */ + +#define ERR_OK          0    /* No error, everything OK. */ +#define ERR_MEM        -1    /* Out of memory error.     */ +#define ERR_BUF        -2    /* Buffer error.            */ +#define ERR_TIMEOUT    -3    /* Timeout.                 */ +#define ERR_RTE        -4    /* Routing problem.         */ + +#define ERR_IS_FATAL(e) ((e) < ERR_RTE) + +#define ERR_ABRT       -5    /* Connection aborted.      */ +#define ERR_RST        -6    /* Connection reset.        */ +#define ERR_CLSD       -7    /* Connection closed.       */ +#define ERR_CONN       -8    /* Not connected.           */ + +#define ERR_VAL        -9    /* Illegal value.           */ + +#define ERR_ARG        -10   /* Illegal argument.        */ + +#define ERR_USE        -11   /* Address in use.          */ + +#define ERR_IF         -12   /* Low-level netif error    */ +#define ERR_ISCONN     -13   /* Already connected.       */ + +#define ERR_INPROGRESS -14   /* Operation in progress    */ + + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ERR_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/init.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/init.h new file mode 100644 index 000000000..a4dc0577f --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/init.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_INIT_H__ +#define __LWIP_INIT_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR      1U +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR      3U +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION   1U +/** For release candidates, this is set to 1..254 +  * For official releases, this is set to 255 (LWIP_RC_RELEASE) +  * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC         255U + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE         255U +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ +#define LWIP_RC_DEVELOPMENT     0U + +#define LWIP_VERSION_IS_RELEASE     (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC          ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/** Provides the version of the stack */ +#define LWIP_VERSION   (LWIP_VERSION_MAJOR << 24   | LWIP_VERSION_MINOR << 16 | \ +                        LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + +/* Modules initialization */ +void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INIT_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/mem.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/mem.h new file mode 100644 index 000000000..327c2049f --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/mem.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include <stddef.h> /* for size_t */ + +typedef size_t mem_size_t; + +/* aliases for C library malloc() */ +#define mem_init() +/* in case C library malloc() needs extra protection, + * allow these defines to be overridden. + */ +#ifndef mem_free +#define mem_free free +#endif +#ifndef mem_malloc +#define mem_malloc malloc +#endif +#ifndef mem_calloc +#define mem_calloc calloc +#endif +#ifndef mem_realloc +static void *mem_realloc(void *mem, mem_size_t size) +{ +  LWIP_UNUSED_ARG(size); +  return mem; +} +#endif +#else /* MEM_LIBC_MALLOC */ + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000l +typedef u32_t mem_size_t; +#else +typedef u16_t mem_size_t; +#endif /* MEM_SIZE > 64000 */ + +#if MEM_USE_POOLS +/** mem_init is not used when using pools instead of a heap */ +#define mem_init() +/** mem_realloc is not used when using pools instead of a heap: +    we can't free part of a pool element and don't want to copy the rest */ +#define mem_realloc(mem, size) (mem) +#else /* MEM_USE_POOLS */ +/* lwIP alternative malloc */ +void  mem_init(void); +void *mem_realloc(void *mem, mem_size_t size); +#endif /* MEM_USE_POOLS */ +void *mem_malloc(mem_size_t size); +void *mem_calloc(mem_size_t count, mem_size_t size); +void  mem_free(void *mem); +#endif /* MEM_LIBC_MALLOC */ + +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) +#endif + +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEM_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/memp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/memp.h new file mode 100644 index 000000000..f0d073994 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/memp.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#ifndef __LWIP_MEMP_H__ +#define __LWIP_MEMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_##name, +#include "lwip/memp_std.h" +  MEMP_MAX +} memp_t; + +#if MEM_USE_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { +    /* Get the first (via: +       MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ +    MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/memp_std.h" +    ) , +    /* Get the last (via: +       MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ +    MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/memp_std.h" +    ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) +   We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST   ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC || MEM_USE_POOLS +extern const u16_t memp_sizes[MEMP_MAX]; +#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC + +#include "mem.h" + +#define memp_init() +#define memp_malloc(type)     mem_malloc(memp_sizes[type]) +#define memp_free(type, mem)  mem_free(mem) + +#else /* MEMP_MEM_MALLOC */ + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. */ +struct memp_malloc_helper +{ +   memp_t poolnr; +}; +#endif /* MEM_USE_POOLS */ + +void  memp_init(void); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line); +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type); +#endif +void  memp_free(memp_t type, void *mem); + +#endif /* MEMP_MEM_MALLOC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEMP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/memp_std.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/memp_std.h new file mode 100644 index 000000000..344690328 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/memp_std.h @@ -0,0 +1,102 @@ +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + *   1) MEMPOOL - standard pools + *   2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + *   3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. +   The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */  + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + *     creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        "RAW_PCB") +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB") +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        "TCP_PCB") +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") +LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG") +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip_reassdata),   "REASSDATA") +#endif /* IP_REASSEMBLY */ + +#if LWIP_NETCONN +LWIP_MEMPOOL(NETBUF,         MEMP_NUM_NETBUF,          sizeof(struct netbuf),         "NETBUF") +LWIP_MEMPOOL(NETCONN,        MEMP_NUM_NETCONN,         sizeof(struct netconn),        "NETCONN") +#endif /* LWIP_NETCONN */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API,  MEMP_NUM_TCPIP_MSG_API,   sizeof(struct tcpip_msg),      "TCPIP_MSG_API") +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),      "TCPIP_MSG_INPKT") +#endif /* NO_SYS==0 */ + +#if ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE,      MEMP_NUM_ARP_QUEUE,       sizeof(struct etharp_q_entry), "ARP_QUEUE") +#endif /* ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP,     MEMP_NUM_IGMP_GROUP,      sizeof(struct igmp_group),     "IGMP_GROUP") +#endif /* LWIP_IGMP */ + +#if NO_SYS==0 +LWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      "SYS_TIMEOUT") +#endif /* NO_SYS==0 */ + + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + *     creates a pool name MEMP_pool_name. description is used in stats.c + *     This allocates enough space for the pbuf struct and a payload. + *     (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_PBUF_MEMPOOL(PBUF,      MEMP_NUM_PBUF,            0,                             "PBUF_REF/ROM") +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE,           PBUF_POOL_BUFSIZE,             "PBUF_POOL") + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netbuf.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netbuf.h new file mode 100644 index 000000000..6d84dd073 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netbuf.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_NETBUF_H__ +#define __LWIP_NETBUF_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netbuf { +  struct pbuf *p, *ptr; +  struct ip_addr *addr; +  u16_t port; +}; + +/* Network buffer functions: */ +struct netbuf *   netbuf_new      (void); +void              netbuf_delete   (struct netbuf *buf); +void *            netbuf_alloc    (struct netbuf *buf, u16_t size); +void              netbuf_free     (struct netbuf *buf); +err_t             netbuf_ref      (struct netbuf *buf, +           const void *dataptr, u16_t size); +void              netbuf_chain    (struct netbuf *head, +           struct netbuf *tail); + +u16_t             netbuf_len      (struct netbuf *buf); +err_t             netbuf_data     (struct netbuf *buf, +           void **dataptr, u16_t *len); +s8_t              netbuf_next     (struct netbuf *buf); +void              netbuf_first    (struct netbuf *buf); + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ +  pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf)              ((buf)->p->tot_len) +#define netbuf_fromaddr(buf)         ((buf)->addr) +#define netbuf_fromport(buf)         ((buf)->port) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETBUF_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netdb.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netdb.h new file mode 100644 index 000000000..0f7b2ec04 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netdb.h @@ -0,0 +1,111 @@ +/* + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include <stddef.h> /* for size_t */ + +#include "lwip/sockets.h" + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME      200 +#define EAI_SERVICE     201 +#define EAI_FAIL        202 +#define EAI_MEMORY      203 + +#define HOST_NOT_FOUND  210 +#define NO_DATA         211 +#define NO_RECOVERY     212 +#define TRY_AGAIN       213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { +    char  *h_name;      /* Official name of the host. */ +    char **h_aliases;   /* A pointer to an array of pointers to alternative host names, +                           terminated by a null pointer. */ +    int    h_addrtype;  /* Address type. */ +    int    h_length;    /* The length, in bytes, of the address. */ +    char **h_addr_list; /* A pointer to an array of pointers to network addresses (in +                           network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { +    int               ai_flags;      /* Input flags. */ +    int               ai_family;     /* Address family of socket. */ +    int               ai_socktype;   /* Socket type. */ +    int               ai_protocol;   /* Protocol of socket. */ +    socklen_t         ai_addrlen;    /* Length of socket address. */ +    struct sockaddr  *ai_addr;       /* Socket address of socket. */ +    char             *ai_canonname;  /* Canonical name of service location. */ +    struct addrinfo  *ai_next;       /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessable error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, +                size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, +       const char *servname, +       const struct addrinfo *hints, +       struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +#define gethostbyname(name) lwip_gethostbyname(name) +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ +       lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a) +#define getaddrinfo(nodname, servname, hints, res) \ +       lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netif.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netif.h new file mode 100644 index 000000000..a32503052 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netif.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_NETIF_H__ +#define __LWIP_NETIF_H__ + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/inet.h" +#include "lwip/pbuf.h" +#if LWIP_DHCP +struct dhcp; +#endif +#if LWIP_AUTOIP +struct autoip; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** must be the maximum of all used hardware address lengths +    across all types of interfaces in use */ +#define NETIF_MAX_HWADDR_LEN 6U + +/** TODO: define the use (where, when, whom) of netif flags */ + +/** whether the network interface is 'up'. this is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + */ +#define NETIF_FLAG_UP           0x01U +/** if set, the netif has broadcast capability */ +#define NETIF_FLAG_BROADCAST    0x02U +/** if set, the netif is one end of a point-to-point connection */ +#define NETIF_FLAG_POINTTOPOINT 0x04U +/** if set, the interface is configured using DHCP */ +#define NETIF_FLAG_DHCP         0x08U +/** if set, the interface has an active link + *  (set by the network interface driver) */ +#define NETIF_FLAG_LINK_UP      0x10U +/** if set, the netif is an device using ARP */ +#define NETIF_FLAG_ETHARP       0x20U +/** if set, the netif has IGMP capability */ +#define NETIF_FLAG_IGMP         0x40U + +/** Generic data structure used for all lwIP network interfaces. + *  The following fields should be filled in by the initialization + *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ + +struct netif { +  /** pointer to next in linked list */ +  struct netif *next; + +  /** IP address configuration in network byte order */ +  struct ip_addr ip_addr; +  struct ip_addr netmask; +  struct ip_addr gw; + +  /** This function is called by the network device driver +   *  to pass a packet up the TCP/IP stack. */ +  err_t (* input)(struct pbuf *p, struct netif *inp); +  /** This function is called by the IP module when it wants +   *  to send a packet on the interface. This function typically +   *  first resolves the hardware address, then sends the packet. */ +  err_t (* output)(struct netif *netif, struct pbuf *p, +       struct ip_addr *ipaddr); +  /** This function is called by the ARP module when it wants +   *  to send a packet on the interface. This function outputs +   *  the pbuf as-is on the link medium. */ +  err_t (* linkoutput)(struct netif *netif, struct pbuf *p); +#if LWIP_NETIF_STATUS_CALLBACK +  /** This function is called when the netif state is set to up or down +   */ +  void (* status_callback)(struct netif *netif); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK +  /** This function is called when the netif link is set to up or down +   */ +  void (* link_callback)(struct netif *netif); +#endif /* LWIP_NETIF_LINK_CALLBACK */ +  /** This field can be set by the device driver and could point +   *  to state information for the device. */ +  void *state; +#if LWIP_DHCP +  /** the DHCP client state information for this netif */ +  struct dhcp *dhcp; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP +  /** the AutoIP client state information for this netif */ +  struct autoip *autoip; +#endif +#if LWIP_NETIF_HOSTNAME +  /* the hostname for this netif, NULL is a valid value */ +  char*  hostname; +#endif /* LWIP_NETIF_HOSTNAME */ +  /** number of bytes used in hwaddr */ +  u8_t hwaddr_len; +  /** link level hardware address of this interface */ +  u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; +  /** maximum transfer unit (in bytes) */ +  u16_t mtu; +  /** flags (see NETIF_FLAG_ above) */ +  u8_t flags; +  /** descriptive abbreviation */ +  char name[2]; +  /** number of this interface */ +  u8_t num; +#if LWIP_SNMP +  /** link type (from "snmp_ifType" enum from snmp.h) */ +  u8_t link_type; +  /** (estimate) link speed */ +  u32_t link_speed; +  /** timestamp at last change made (up/down) */ +  u32_t ts; +  /** counters */ +  u32_t ifinoctets; +  u32_t ifinucastpkts; +  u32_t ifinnucastpkts; +  u32_t ifindiscards; +  u32_t ifoutoctets; +  u32_t ifoutucastpkts; +  u32_t ifoutnucastpkts; +  u32_t ifoutdiscards; +#endif /* LWIP_SNMP */ +#if LWIP_IGMP +  /* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/ +  err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action); +#endif /* LWIP_IGMP */ +#if LWIP_NETIF_HWADDRHINT +  u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK +  /* List of packets to be queued for ourselves. */ +  struct pbuf *loop_first; +  struct pbuf *loop_last; +#if LWIP_LOOPBACK_MAX_PBUFS +  u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_SNMP +#define NETIF_INIT_SNMP(netif, type, speed) \ +  /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ +  netif->link_type = type;    \ +  /* your link speed here (units: bits per second) */  \ +  netif->link_speed = speed;  \ +  netif->ts = 0;              \ +  netif->ifinoctets = 0;      \ +  netif->ifinucastpkts = 0;   \ +  netif->ifinnucastpkts = 0;  \ +  netif->ifindiscards = 0;    \ +  netif->ifoutoctets = 0;     \ +  netif->ifoutucastpkts = 0;  \ +  netif->ifoutnucastpkts = 0; \ +  netif->ifoutdiscards = 0 +#else /* LWIP_SNMP */ +#define NETIF_INIT_SNMP(netif, type, speed) +#endif /* LWIP_SNMP */ + + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +#define netif_init() /* Compatibility define, not init needed. */ + +struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, +      struct ip_addr *gw, +      void *state, +      err_t (* init)(struct netif *netif), +      err_t (* input)(struct pbuf *p, struct netif *netif)); + +void +netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask, +    struct ip_addr *gw); +void netif_remove(struct netif * netif); + +/* Returns a network interface given its name. The name is of the form +   "et0", where the first two letters are the "name" field in the +   netif structure, and the digit is in the num field in the same +   structure. */ +struct netif *netif_find(char *name); + +void netif_set_default(struct netif *netif); + +void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr); +void netif_set_netmask(struct netif *netif, struct ip_addr *netmask); +void netif_set_gw(struct netif *netif, struct ip_addr *gw); + +void netif_set_up(struct netif *netif); +void netif_set_down(struct netif *netif); +u8_t netif_is_up(struct netif *netif); + +#if LWIP_NETIF_STATUS_CALLBACK +/* + * Set callback to be called when interface is brought up/down + */ +void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif)); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_up(struct netif *netif); +void netif_set_link_down(struct netif *netif); +u8_t netif_is_link_up(struct netif *netif); +/* + * Set callback to be called when link is brought up/down + */ +void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif)); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#ifdef __cplusplus +} +#endif + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip); +void netif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#endif /* __LWIP_NETIF_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netifapi.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netifapi.h new file mode 100644 index 000000000..36c6bd0a2 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/netifapi.h @@ -0,0 +1,100 @@ +/* + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + */ +  +#ifndef __LWIP_NETIFAPI_H__ +#define __LWIP_NETIFAPI_H__ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netifapi_msg_msg { +#if !LWIP_TCPIP_CORE_LOCKING +  sys_sem_t sem; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +  err_t err; +  struct netif *netif; +  union { +    struct { +      struct ip_addr *ipaddr; +      struct ip_addr *netmask; +      struct ip_addr *gw; +      void *state; +      err_t (* init) (struct netif *netif); +      err_t (* input)(struct pbuf *p, struct netif *netif); +    } add; +    struct { +      void  (* voidfunc)(struct netif *netif); +      err_t (* errtfunc)(struct netif *netif); +    } common; +  } msg; +}; + +struct netifapi_msg { +  void (* function)(struct netifapi_msg_msg *msg); +  struct netifapi_msg_msg msg; +}; + + +/* API for application */ +err_t netifapi_netif_add       ( struct netif *netif, +                                 struct ip_addr *ipaddr, +                                 struct ip_addr *netmask, +                                 struct ip_addr *gw, +                                 void *state, +                                 err_t (* init)(struct netif *netif), +                                 err_t (* input)(struct pbuf *p, struct netif *netif) ); + +err_t netifapi_netif_common    ( struct netif *netif, +                                 void  (* voidfunc)(struct netif *netif), +                                 err_t (* errtfunc)(struct netif *netif) ); + +#define netifapi_netif_remove(n)      netifapi_netif_common(n, netif_remove, NULL) +#define netifapi_netif_set_up(n)      netifapi_netif_common(n, netif_set_up, NULL) +#define netifapi_netif_set_down(n)    netifapi_netif_common(n, netif_set_down, NULL) +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +#define netifapi_dhcp_start(n)        netifapi_netif_common(n, NULL, dhcp_start) +#define netifapi_dhcp_stop(n)         netifapi_netif_common(n, dhcp_stop, NULL) +#define netifapi_autoip_start(n)      netifapi_netif_common(n, NULL, autoip_start) +#define netifapi_autoip_stop(n)       netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* __LWIP_NETIFAPI_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/opt.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/opt.h new file mode 100644 index 000000000..e8bd8b89e --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/opt.h @@ -0,0 +1,1820 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_OPT_H__ +#define __LWIP_OPT_H__ + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you dont like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/* +   ----------------------------------------------- +   ---------- Platform specific locking ---------- +   ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT            0 +#endif + +/**  + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS                          0 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len)             memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len)            memcpy(dst,src,len) +#endif + +/* +   ------------------------------------ +   ---------- Memory options ---------- +   ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC                 0 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC                 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + *    4 byte alignment -> #define MEM_ALIGNMENT 4 + *    2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT                   1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE                        1600 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + *    MEMP_OVERFLOW_CHECK == 0 no checking + *    MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + *    MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + *      memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK             0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK               0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS                   0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL   0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your  + * inlude path somewhere.  + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS           0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* +   ------------------------------------------------ +   ---------- Internal Memory Pool Sizes ---------- +   ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF                   16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB                4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB                4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB                5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN         8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG                16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA              5 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE              30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP             8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT            3 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF                 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN                4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication.  + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API          8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets.  + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT        8 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.  + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE                  16 +#endif + +/* +   --------------------------------- +   ---------- ARP options ---------- +   --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP                        1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE                  10 +#endif + +/** + * ARP_QUEUEING==1: Outgoing packets are queued during hardware address + * resolution. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING                    1 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC             1 +#endif + +/* +   -------------------------------- +   ---------- IP options ---------- +   -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD                      0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED              1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY                   1 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG                         1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE                 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS              10 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented. + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF         1 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU                 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL                  255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST                0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV           0 +#endif + +/* +   ---------------------------------- +   ---------- ICMP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP                       1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL                       (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING             0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING             0 +#endif + +/* +   --------------------------------- +   ---------- RAW options ---------- +   --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW                        1 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL                        (IP_DEFAULT_TTL) +#endif + +/* +   ---------------------------------- +   ---------- DHCP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP                       0 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK             ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/* +   ------------------------------------ +   ---------- AUTOIP options ---------- +   ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP                     0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP           0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES     9 +#endif + +/* +   ---------------------------------- +   ---------- SNMP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP                       0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required.  + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS        1 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS          1 +#endif + +/** + * SNMP_PRIVATE_MIB:  + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB                0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS              1 +#endif + +/* +   ---------------------------------- +   ---------- IGMP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module.  + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP                       0 +#endif + +/* +   ---------------------------------- +   ---------- DNS options ----------- +   ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS                        0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE                  4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH             256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS                 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK             1 +#endif + +/** DNS use a local buffer if DNS_USES_STATIC_BUF=0, a static one if +    DNS_USES_STATIC_BUF=1, or a dynamic one if DNS_USES_STATIC_BUF=2. +    The buffer will be of size DNS_MSG_SIZE */ +#ifndef DNS_USES_STATIC_BUF +#define DNS_USES_STATIC_BUF             1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE                    512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + *  you have to define + *    #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + *  (an array of structs name/address, where address is an u32_t in network + *  byte order). + * + *  Instead, you can also use an external function: + *  #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + *  that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST              0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + *  at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC   0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* +   --------------------------------- +   ---------- UDP options ---------- +   --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP                        1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE                    0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL                         (IP_DEFAULT_TTL) +#endif + +/* +   --------------------------------- +   ---------- TCP options ---------- +   --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP                        1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL                         (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window.  This must be at least  + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND                         2048 +#endif  + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX                      12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX                   6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ                 (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 128, a *very* + * conservative default.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS                         128 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS      1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes).  + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF                     256 +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN                (4 * (TCP_SND_BUF/TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than or equal + * to TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable. + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT                    (TCP_SND_BUF/2) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG              0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG      0xff +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS             0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD   (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + *     LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + *         events (accept, sent, etc) that happen in the system. + *     LWIP_CALLBACK_API==1: The PCB callback function is called directly + *         for the event. + */ +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API                  0 +#define LWIP_CALLBACK_API               1 +#else  +#define LWIP_EVENT_API                  1 +#define LWIP_CALLBACK_API               0 +#endif + + +/* +   ---------------------------------- +   ---------- Pbuf options ---------- +   ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN                  14 +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* +   ------------------------------------------------ +   ---------- Network Interfaces options ---------- +   ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME             0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API                  0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK      0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK        0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT           0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK             0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS         0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + *    LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + *       multithreaded environment like tcpip.c. In this case, netif->input() + *       is called directly. + *    LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + *       The packets are put on a list and netif_poll() must be called in + *       the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING    (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF             0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* +   ------------------------------------ +   ---------- LOOPIF options ---------- +   ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF                0 +#endif + +/* +   ------------------------------------ +   ---------- SLIPIF options ---------- +   ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF                0 +#endif + +/* +   ------------------------------------ +   ---------- Thread options ---------- +   ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME              "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE          0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO               1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE                 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME             "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE         0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO              1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppMain thread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME                "pppMain" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppMain thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE            0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppMain thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO                 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME            "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE        0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO             1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE       0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE       0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE       0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE         0 +#endif + +/* +   ---------------------------------------------- +   ---------- Sequential layer options ---------- +   ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING         0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN                    1 +#endif + +/* +   ------------------------------------ +   ---------- Socket options ---------- +   ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET                     1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS             1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES     1 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE              0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO                0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF                  0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT            INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE! + */ +#ifndef SO_REUSE +#define SO_REUSE                        0 +#endif + +/* +   ---------------------------------------- +   ---------- Statistics options ---------- +   ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS                      1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY              0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS                      1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS                    (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS                        1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS                    (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS                      1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS                      (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS                       (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS                       (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS                       1 +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS                      1 +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS                       1 +#endif + +#else + +#define LINK_STATS                      0 +#define IP_STATS                        0 +#define IPFRAG_STATS                    0 +#define ICMP_STATS                      0 +#define IGMP_STATS                      0 +#define UDP_STATS                       0 +#define TCP_STATS                       0 +#define MEM_STATS                       0 +#define MEMP_STATS                      0 +#define SYS_STATS                       0 +#define LWIP_STATS_DISPLAY              0 + +#endif /* LWIP_STATS */ + +/* +   --------------------------------- +   ---------- PPP options ---------- +   --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT                     0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT                   0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT                   PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP                         1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT                     0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT                    0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT                  0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT                    0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT                     0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT                      0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT                     0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT                  6       /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS              2       /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS              10      /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS              5       /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT                 6       /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME                 30      /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT                 6       /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS               10      /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL                0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS                3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG                 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + *    limits.  See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + *    of living in lcp.h) + */ +#define PPP_MTU                         1500     /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU  65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU                      1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU                      64 +#define PPP_MRU                         1500     /* default MRU = max length of info field */ +#define PPP_MAXMRU                      1500     /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU                      296             /* Try for this */ +#endif +#define PPP_MINMRU                      128             /* No MRUs below this */ + + +#define MAXNAMELEN                      256     /* max length of hostname or name for auth */ +#define MAXSECRETLEN                    256     /* max length of password or secret */ + +#endif /* PPP_SUPPORT */ + +/* +   -------------------------------------- +   ---------- Checksum options ---------- +   -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP                 1 +#endif +  +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP                1 +#endif +  +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP                1 +#endif +  +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP               1 +#endif +  +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP              1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP              1 +#endif + +/* +   --------------------------------------- +   ---------- Debugging options ---------- +   --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_OFF +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG                    LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG                     LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG                        LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG                    LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG                     LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG                    LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG                       LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/pbuf.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/pbuf.h new file mode 100644 index 000000000..8380f65da --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/pbuf.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#ifndef __LWIP_PBUF_H__ +#define __LWIP_PBUF_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PBUF_TRANSPORT_HLEN 20 +#define PBUF_IP_HLEN        20 + +typedef enum { +  PBUF_TRANSPORT, +  PBUF_IP, +  PBUF_LINK, +  PBUF_RAW +} pbuf_layer; + +typedef enum { +  PBUF_RAM, /* pbuf data is stored in RAM */ +  PBUF_ROM, /* pbuf data is stored in ROM */ +  PBUF_REF, /* pbuf comes from the pbuf pool */ +  PBUF_POOL /* pbuf payload refers to RAM */ +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U + +struct pbuf { +  /** next pbuf in singly linked pbuf chain */ +  struct pbuf *next; + +  /** pointer to the actual data in the buffer */ +  void *payload; +   +  /** +   * total length of this buffer and all next buffers in chain +   * belonging to the same packet. +   * +   * For non-queue packet chains this is the invariant: +   * p->tot_len == p->len + (p->next? p->next->tot_len: 0) +   */ +  u16_t tot_len; +   +  /** length of this buffer */ +  u16_t len;   + +  /** pbuf_type as u8_t instead of enum to save space */ +  u8_t /*pbuf_type*/ type; + +  /** misc flags */ +  u8_t flags; + +  /** +   * the reference count always equals the number of pointers +   * that refer to this pbuf. This can be pointers from an application, +   * the stack itself, or pbuf->next pointers from a chain. +   */ +  u16_t ref; +   +}; + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type); +void pbuf_realloc(struct pbuf *p, u16_t size);  +u8_t pbuf_header(struct pbuf *p, s16_t header_size); +void pbuf_ref(struct pbuf *p); +void pbuf_ref_chain(struct pbuf *p); +u8_t pbuf_free(struct pbuf *p); +u8_t pbuf_clen(struct pbuf *p);   +void pbuf_cat(struct pbuf *head, struct pbuf *tail); +void pbuf_chain(struct pbuf *head, struct pbuf *tail); +struct pbuf *pbuf_dechain(struct pbuf *p); +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); +u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_PBUF_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/raw.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/raw.h new file mode 100644 index 000000000..20b0a11bb --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/raw.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_RAW_H__ +#define __LWIP_RAW_H__ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/inet.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct raw_pcb { +/* Common members of all PCB types */ +  IP_PCB; + +  struct raw_pcb *next; + +  u8_t protocol; + +  /* receive callback function +   * @param arg user supplied argument (raw_pcb.recv_arg) +   * @param pcb the raw_pcb which received data +   * @param p the packet buffer that was received +   * @param addr the remote IP address from which the packet was received +   * @return 1 if the packet was 'eaten' (aka. deleted), +   *         0 if the packet lives on +   * If returning 1, the callback is responsible for freeing the pbuf +   * if it's not used any more. +   */ +  u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p, +    struct ip_addr *addr); +  /* user-supplied argument for the recv callback */ +  void *recv_arg; +}; + +/* The following functions is the application layer interface to the +   RAW code. */ +struct raw_pcb * raw_new        (u8_t proto); +void             raw_remove     (struct raw_pcb *pcb); +err_t            raw_bind       (struct raw_pcb *pcb, struct ip_addr *ipaddr); +err_t            raw_connect    (struct raw_pcb *pcb, struct ip_addr *ipaddr); + +void             raw_recv       (struct raw_pcb *pcb, +                                 u8_t (* recv)(void *arg, struct raw_pcb *pcb, +                                              struct pbuf *p, +                                              struct ip_addr *addr), +                                 void *recv_arg); +err_t            raw_sendto     (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr); +err_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p); + +/* The following functions are the lower layer interface to RAW. */ +u8_t             raw_input      (struct pbuf *p, struct netif *inp); +#define raw_init() /* Compatibility define, not init needed. */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* __LWIP_RAW_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sio.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sio.h new file mode 100644 index 000000000..7d9162e49 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sio.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef __SIO_H__ +#define __SIO_H__ + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, +   define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file +   or be implemented in your custom sio.c file. */ + +#ifndef sio_open +sio_fd_t sio_open(u8_t); +#endif + +#ifndef sio_send +void sio_send(u8_t, sio_fd_t); +#endif + +#ifndef sio_recv +u8_t sio_recv(sio_fd_t); +#endif + +#ifndef sio_read +u32_t sio_read(sio_fd_t, u8_t *, u32_t); +#endif + +#ifndef sio_write +u32_t sio_write(sio_fd_t, u8_t *, u32_t); +#endif + +#ifndef sio_read_abort +void sio_read_abort(sio_fd_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __SIO_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp.h new file mode 100644 index 000000000..dd03d5d70 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp.h @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv> + * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Leon Woestenberg <leon.woestenberg@axon.tv> + * + */ +#ifndef __LWIP_SNMP_H__ +#define __LWIP_SNMP_H__ + +#include "lwip/opt.h" +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { +  snmp_ifType_other=1,                /* none of the following */ +  snmp_ifType_regular1822, +  snmp_ifType_hdh1822, +  snmp_ifType_ddn_x25, +  snmp_ifType_rfc877_x25, +  snmp_ifType_ethernet_csmacd, +  snmp_ifType_iso88023_csmacd, +  snmp_ifType_iso88024_tokenBus, +  snmp_ifType_iso88025_tokenRing, +  snmp_ifType_iso88026_man, +  snmp_ifType_starLan, +  snmp_ifType_proteon_10Mbit, +  snmp_ifType_proteon_80Mbit, +  snmp_ifType_hyperchannel, +  snmp_ifType_fddi, +  snmp_ifType_lapb, +  snmp_ifType_sdlc, +  snmp_ifType_ds1,                    /* T-1 */ +  snmp_ifType_e1,                     /* european equiv. of T-1 */ +  snmp_ifType_basicISDN, +  snmp_ifType_primaryISDN,            /* proprietary serial */ +  snmp_ifType_propPointToPointSerial, +  snmp_ifType_ppp, +  snmp_ifType_softwareLoopback, +  snmp_ifType_eon,                    /* CLNP over IP [11] */ +  snmp_ifType_ethernet_3Mbit, +  snmp_ifType_nsip,                   /* XNS over IP */ +  snmp_ifType_slip,                   /* generic SLIP */ +  snmp_ifType_ultra,                  /* ULTRA technologies */ +  snmp_ifType_ds3,                    /* T-3 */ +  snmp_ifType_sip,                    /* SMDS */ +  snmp_ifType_frame_relay +}; + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** SNMP "sysuptime" Interval */ +#define SNMP_SYSUPTIME_INTERVAL 10 + +/** fixed maximum length for object identifier type */ +#define LWIP_SNMP_OBJ_ID_LEN 32 + +/** internal object identifier representation */ +struct snmp_obj_id +{ +  u8_t len; +  s32_t id[LWIP_SNMP_OBJ_ID_LEN]; +}; + +/* system */ +void snmp_set_sysdesr(u8_t* str, u8_t* len); +void snmp_set_sysobjid(struct snmp_obj_id *oid); +void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid); +void snmp_inc_sysuptime(void); +void snmp_add_sysuptime(u32_t value); +void snmp_get_sysuptime(u32_t *value); +void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen); + +/* network interface */ +void snmp_add_ifinoctets(struct netif *ni, u32_t value);  +void snmp_inc_ifinucastpkts(struct netif *ni); +void snmp_inc_ifinnucastpkts(struct netif *ni); +void snmp_inc_ifindiscards(struct netif *ni); +void snmp_add_ifoutoctets(struct netif *ni, u32_t value); +void snmp_inc_ifoutucastpkts(struct netif *ni); +void snmp_inc_ifoutnucastpkts(struct netif *ni); +void snmp_inc_ifoutdiscards(struct netif *ni); +void snmp_inc_iflist(void); +void snmp_dec_iflist(void); + +/* ARP (for atTable and ipNetToMediaTable) */ +void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip); +void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip); + +/* IP */ +void snmp_inc_ipinreceives(void); +void snmp_inc_ipinhdrerrors(void); +void snmp_inc_ipinaddrerrors(void); +void snmp_inc_ipforwdatagrams(void); +void snmp_inc_ipinunknownprotos(void); +void snmp_inc_ipindiscards(void); +void snmp_inc_ipindelivers(void); +void snmp_inc_ipoutrequests(void); +void snmp_inc_ipoutdiscards(void); +void snmp_inc_ipoutnoroutes(void); +void snmp_inc_ipreasmreqds(void); +void snmp_inc_ipreasmoks(void); +void snmp_inc_ipreasmfails(void); +void snmp_inc_ipfragoks(void); +void snmp_inc_ipfragfails(void); +void snmp_inc_ipfragcreates(void); +void snmp_inc_iproutingdiscards(void); +void snmp_insert_ipaddridx_tree(struct netif *ni); +void snmp_delete_ipaddridx_tree(struct netif *ni); +void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni); +void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni); + +/* ICMP */ +void snmp_inc_icmpinmsgs(void); +void snmp_inc_icmpinerrors(void); +void snmp_inc_icmpindestunreachs(void); +void snmp_inc_icmpintimeexcds(void); +void snmp_inc_icmpinparmprobs(void); +void snmp_inc_icmpinsrcquenchs(void); +void snmp_inc_icmpinredirects(void); +void snmp_inc_icmpinechos(void); +void snmp_inc_icmpinechoreps(void); +void snmp_inc_icmpintimestamps(void); +void snmp_inc_icmpintimestampreps(void); +void snmp_inc_icmpinaddrmasks(void); +void snmp_inc_icmpinaddrmaskreps(void); +void snmp_inc_icmpoutmsgs(void); +void snmp_inc_icmpouterrors(void); +void snmp_inc_icmpoutdestunreachs(void); +void snmp_inc_icmpouttimeexcds(void); +void snmp_inc_icmpoutparmprobs(void); +void snmp_inc_icmpoutsrcquenchs(void); +void snmp_inc_icmpoutredirects(void);  +void snmp_inc_icmpoutechos(void); +void snmp_inc_icmpoutechoreps(void); +void snmp_inc_icmpouttimestamps(void); +void snmp_inc_icmpouttimestampreps(void); +void snmp_inc_icmpoutaddrmasks(void); +void snmp_inc_icmpoutaddrmaskreps(void); + +/* TCP */ +void snmp_inc_tcpactiveopens(void); +void snmp_inc_tcppassiveopens(void); +void snmp_inc_tcpattemptfails(void); +void snmp_inc_tcpestabresets(void); +void snmp_inc_tcpinsegs(void); +void snmp_inc_tcpoutsegs(void); +void snmp_inc_tcpretranssegs(void); +void snmp_inc_tcpinerrs(void); +void snmp_inc_tcpoutrsts(void); + +/* UDP */ +void snmp_inc_udpindatagrams(void); +void snmp_inc_udpnoports(void); +void snmp_inc_udpinerrors(void); +void snmp_inc_udpoutdatagrams(void); +void snmp_insert_udpidx_tree(struct udp_pcb *pcb); +void snmp_delete_udpidx_tree(struct udp_pcb *pcb); + +/* SNMP */ +void snmp_inc_snmpinpkts(void); +void snmp_inc_snmpoutpkts(void); +void snmp_inc_snmpinbadversions(void); +void snmp_inc_snmpinbadcommunitynames(void); +void snmp_inc_snmpinbadcommunityuses(void); +void snmp_inc_snmpinasnparseerrs(void); +void snmp_inc_snmpintoobigs(void); +void snmp_inc_snmpinnosuchnames(void); +void snmp_inc_snmpinbadvalues(void); +void snmp_inc_snmpinreadonlys(void); +void snmp_inc_snmpingenerrs(void); +void snmp_add_snmpintotalreqvars(u8_t value); +void snmp_add_snmpintotalsetvars(u8_t value); +void snmp_inc_snmpingetrequests(void); +void snmp_inc_snmpingetnexts(void); +void snmp_inc_snmpinsetrequests(void); +void snmp_inc_snmpingetresponses(void); +void snmp_inc_snmpintraps(void); +void snmp_inc_snmpouttoobigs(void); +void snmp_inc_snmpoutnosuchnames(void); +void snmp_inc_snmpoutbadvalues(void); +void snmp_inc_snmpoutgenerrs(void); +void snmp_inc_snmpoutgetrequests(void); +void snmp_inc_snmpoutgetnexts(void); +void snmp_inc_snmpoutsetrequests(void); +void snmp_inc_snmpoutgetresponses(void); +void snmp_inc_snmpouttraps(void); +void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid); +void snmp_set_snmpenableauthentraps(u8_t *value); +void snmp_get_snmpenableauthentraps(u8_t *value); + +/* LWIP_SNMP support not available */ +/* define everything to be empty */ +#else + +/* system */ +#define snmp_set_sysdesr(str, len) +#define snmp_set_sysobjid(oid); +#define snmp_get_sysobjid_ptr(oid) +#define snmp_inc_sysuptime() +#define snmp_add_sysuptime(value) +#define snmp_get_sysuptime(value) +#define snmp_set_syscontact(ocstr, ocstrlen); +#define snmp_set_sysname(ocstr, ocstrlen); +#define snmp_set_syslocation(ocstr, ocstrlen); + +/* network interface */ +#define snmp_add_ifinoctets(ni,value)  +#define snmp_inc_ifinucastpkts(ni) +#define snmp_inc_ifinnucastpkts(ni) +#define snmp_inc_ifindiscards(ni) +#define snmp_add_ifoutoctets(ni,value) +#define snmp_inc_ifoutucastpkts(ni) +#define snmp_inc_ifoutnucastpkts(ni) +#define snmp_inc_ifoutdiscards(ni) +#define snmp_inc_iflist() +#define snmp_dec_iflist() + +/* ARP */ +#define snmp_insert_arpidx_tree(ni,ip) +#define snmp_delete_arpidx_tree(ni,ip) + +/* IP */ +#define snmp_inc_ipinreceives() +#define snmp_inc_ipinhdrerrors() +#define snmp_inc_ipinaddrerrors() +#define snmp_inc_ipforwdatagrams() +#define snmp_inc_ipinunknownprotos() +#define snmp_inc_ipindiscards() +#define snmp_inc_ipindelivers() +#define snmp_inc_ipoutrequests() +#define snmp_inc_ipoutdiscards() +#define snmp_inc_ipoutnoroutes() +#define snmp_inc_ipreasmreqds() +#define snmp_inc_ipreasmoks() +#define snmp_inc_ipreasmfails() +#define snmp_inc_ipfragoks() +#define snmp_inc_ipfragfails() +#define snmp_inc_ipfragcreates() +#define snmp_inc_iproutingdiscards() +#define snmp_insert_ipaddridx_tree(ni) +#define snmp_delete_ipaddridx_tree(ni) +#define snmp_insert_iprteidx_tree(dflt, ni) +#define snmp_delete_iprteidx_tree(dflt, ni) + +/* ICMP */ +#define snmp_inc_icmpinmsgs() +#define snmp_inc_icmpinerrors()  +#define snmp_inc_icmpindestunreachs()  +#define snmp_inc_icmpintimeexcds() +#define snmp_inc_icmpinparmprobs()  +#define snmp_inc_icmpinsrcquenchs()  +#define snmp_inc_icmpinredirects()  +#define snmp_inc_icmpinechos()  +#define snmp_inc_icmpinechoreps() +#define snmp_inc_icmpintimestamps()  +#define snmp_inc_icmpintimestampreps() +#define snmp_inc_icmpinaddrmasks() +#define snmp_inc_icmpinaddrmaskreps() +#define snmp_inc_icmpoutmsgs() +#define snmp_inc_icmpouterrors() +#define snmp_inc_icmpoutdestunreachs()  +#define snmp_inc_icmpouttimeexcds()  +#define snmp_inc_icmpoutparmprobs() +#define snmp_inc_icmpoutsrcquenchs() +#define snmp_inc_icmpoutredirects()  +#define snmp_inc_icmpoutechos()  +#define snmp_inc_icmpoutechoreps() +#define snmp_inc_icmpouttimestamps() +#define snmp_inc_icmpouttimestampreps() +#define snmp_inc_icmpoutaddrmasks() +#define snmp_inc_icmpoutaddrmaskreps() +/* TCP */ +#define snmp_inc_tcpactiveopens() +#define snmp_inc_tcppassiveopens() +#define snmp_inc_tcpattemptfails() +#define snmp_inc_tcpestabresets() +#define snmp_inc_tcpinsegs() +#define snmp_inc_tcpoutsegs() +#define snmp_inc_tcpretranssegs() +#define snmp_inc_tcpinerrs() +#define snmp_inc_tcpoutrsts() + +/* UDP */ +#define snmp_inc_udpindatagrams() +#define snmp_inc_udpnoports() +#define snmp_inc_udpinerrors() +#define snmp_inc_udpoutdatagrams() +#define snmp_insert_udpidx_tree(pcb) +#define snmp_delete_udpidx_tree(pcb) + +/* SNMP */ +#define snmp_inc_snmpinpkts() +#define snmp_inc_snmpoutpkts() +#define snmp_inc_snmpinbadversions() +#define snmp_inc_snmpinbadcommunitynames() +#define snmp_inc_snmpinbadcommunityuses() +#define snmp_inc_snmpinasnparseerrs() +#define snmp_inc_snmpintoobigs() +#define snmp_inc_snmpinnosuchnames() +#define snmp_inc_snmpinbadvalues() +#define snmp_inc_snmpinreadonlys() +#define snmp_inc_snmpingenerrs() +#define snmp_add_snmpintotalreqvars(value) +#define snmp_add_snmpintotalsetvars(value) +#define snmp_inc_snmpingetrequests() +#define snmp_inc_snmpingetnexts() +#define snmp_inc_snmpinsetrequests() +#define snmp_inc_snmpingetresponses() +#define snmp_inc_snmpintraps() +#define snmp_inc_snmpouttoobigs() +#define snmp_inc_snmpoutnosuchnames() +#define snmp_inc_snmpoutbadvalues() +#define snmp_inc_snmpoutgenerrs() +#define snmp_inc_snmpoutgetrequests() +#define snmp_inc_snmpoutgetnexts() +#define snmp_inc_snmpoutsetrequests() +#define snmp_inc_snmpoutgetresponses() +#define snmp_inc_snmpouttraps() +#define snmp_get_snmpgrpid_ptr(oid) +#define snmp_set_snmpenableauthentraps(value) +#define snmp_get_snmpenableauthentraps(value) + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SNMP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_asn1.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_asn1.h new file mode 100644 index 000000000..8a602881f --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_asn1.h @@ -0,0 +1,101 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) codec. + */ +  +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#ifndef __LWIP_SNMP_ASN1_H__ +#define __LWIP_SNMP_ASN1_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/snmp.h" + +#if LWIP_SNMP + +#ifdef __cplusplus +extern "C" { +#endif + +#define SNMP_ASN1_UNIV   (!0x80 | !0x40) +#define SNMP_ASN1_APPLIC (!0x80 |  0x40) +#define SNMP_ASN1_CONTXT ( 0x80 | !0x40) + +#define SNMP_ASN1_CONSTR (0x20) +#define SNMP_ASN1_PRIMIT (!0x20) + +/* universal tags */ +#define SNMP_ASN1_INTEG  2 +#define SNMP_ASN1_OC_STR 4 +#define SNMP_ASN1_NUL    5 +#define SNMP_ASN1_OBJ_ID 6 +#define SNMP_ASN1_SEQ    16 + +/* application specific (SNMP) tags */ +#define SNMP_ASN1_IPADDR 0    /* octet string size(4) */ +#define SNMP_ASN1_COUNTER 1   /* u32_t */ +#define SNMP_ASN1_GAUGE 2     /* u32_t */ +#define SNMP_ASN1_TIMETICKS 3 /* u32_t */ +#define SNMP_ASN1_OPAQUE 4    /* octet string */ + +/* context specific (SNMP) tags */ +#define SNMP_ASN1_PDU_GET_REQ 0 +#define SNMP_ASN1_PDU_GET_NEXT_REQ 1 +#define SNMP_ASN1_PDU_GET_RESP 2 +#define SNMP_ASN1_PDU_SET_REQ 3 +#define SNMP_ASN1_PDU_TRAP 4 + +err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type); +err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length); +err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value); +err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value); +err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid); +err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw); + +void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); +void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); +void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); +void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); +err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); +err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); +err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value); +err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value); +err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); +err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_ASN1_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_msg.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_msg.h new file mode 100644 index 000000000..b2f69c4be --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_msg.h @@ -0,0 +1,311 @@ +/** + * @file + * SNMP Agent message handling structures. + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#ifndef __LWIP_SNMP_MSG_H__ +#define __LWIP_SNMP_MSG_H__ + +#include "lwip/opt.h" +#include "lwip/snmp.h" +#include "lwip/snmp_structs.h" + +#if LWIP_SNMP + +#if SNMP_PRIVATE_MIB +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The listen port of the SNMP agent. Clients have to make their requests to +   this port. Most standard clients won't work if you change this! */ +#ifndef SNMP_IN_PORT +#define SNMP_IN_PORT 161 +#endif +/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't +   work if you change this! */ +#ifndef SNMP_TRAP_PORT +#define SNMP_TRAP_PORT 162 +#endif + +#define SNMP_ES_NOERROR 0 +#define SNMP_ES_TOOBIG 1 +#define SNMP_ES_NOSUCHNAME 2 +#define SNMP_ES_BADVALUE 3 +#define SNMP_ES_READONLY 4 +#define SNMP_ES_GENERROR 5 + +#define SNMP_GENTRAP_COLDSTART 0 +#define SNMP_GENTRAP_WARMSTART 1 +#define SNMP_GENTRAP_AUTHFAIL 4 +#define SNMP_GENTRAP_ENTERPRISESPC 6 + +struct snmp_varbind +{ +  /* next pointer, NULL for last in list */ +  struct snmp_varbind *next; +  /* previous pointer, NULL for first in list */ +  struct snmp_varbind *prev; + +  /* object identifier length (in s32_t) */ +  u8_t ident_len; +  /* object identifier array */ +  s32_t *ident; + +  /* object value ASN1 type */ +  u8_t value_type; +  /* object value length (in u8_t) */ +  u8_t value_len; +  /* object value */ +  void *value; + +  /* encoding varbind seq length length */ +  u8_t seqlenlen; +  /* encoding object identifier length length */ +  u8_t olenlen; +  /* encoding object value length length */ +  u8_t vlenlen; +  /* encoding varbind seq length */ +  u16_t seqlen; +  /* encoding object identifier length */ +  u16_t olen; +  /* encoding object value length */ +  u16_t vlen; +}; + +struct snmp_varbind_root +{ +  struct snmp_varbind *head; +  struct snmp_varbind *tail; +  /* number of variable bindings in list */ +  u8_t count; +  /* encoding varbind-list seq length length */ +  u8_t seqlenlen; +  /* encoding varbind-list seq length */ +  u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_resp_header_lengths +{ +  /* encoding error-index length length */ +  u8_t erridxlenlen; +  /* encoding error-status length length */ +  u8_t errstatlenlen; +  /* encoding request id length length */ +  u8_t ridlenlen; +  /* encoding pdu length length */ +  u8_t pdulenlen; +  /* encoding community length length */ +  u8_t comlenlen; +  /* encoding version length length */ +  u8_t verlenlen; +  /* encoding sequence length length */ +  u8_t seqlenlen; + +  /* encoding error-index length */ +  u16_t erridxlen; +  /* encoding error-status length */ +  u16_t errstatlen; +  /* encoding request id length */ +  u16_t ridlen; +  /* encoding pdu length */ +  u16_t pdulen; +  /* encoding community length */ +  u16_t comlen; +  /* encoding version length */ +  u16_t verlen; +  /* encoding sequence length */ +  u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_trap_header_lengths +{ +  /* encoding timestamp length length */ +  u8_t tslenlen; +  /* encoding specific-trap length length */ +  u8_t strplenlen; +  /* encoding generic-trap length length */ +  u8_t gtrplenlen; +  /* encoding agent-addr length length */ +  u8_t aaddrlenlen; +  /* encoding enterprise-id length length */ +  u8_t eidlenlen; +  /* encoding pdu length length */ +  u8_t pdulenlen; +  /* encoding community length length */ +  u8_t comlenlen; +  /* encoding version length length */ +  u8_t verlenlen; +  /* encoding sequence length length */ +  u8_t seqlenlen; + +  /* encoding timestamp length */ +  u16_t tslen; +  /* encoding specific-trap length */ +  u16_t strplen; +  /* encoding generic-trap length */ +  u16_t gtrplen; +  /* encoding agent-addr length */ +  u16_t aaddrlen; +  /* encoding enterprise-id length */ +  u16_t eidlen; +  /* encoding pdu length */ +  u16_t pdulen; +  /* encoding community length */ +  u16_t comlen; +  /* encoding version length */ +  u16_t verlen; +  /* encoding sequence length */ +  u16_t seqlen; +}; + +/* Accepting new SNMP messages. */ +#define SNMP_MSG_EMPTY                 0 +/* Search for matching object for variable binding. */ +#define SNMP_MSG_SEARCH_OBJ            1 +/* Perform SNMP operation on in-memory object. +   Pass-through states, for symmetry only. */ +#define SNMP_MSG_INTERNAL_GET_OBJDEF   2 +#define SNMP_MSG_INTERNAL_GET_VALUE    3 +#define SNMP_MSG_INTERNAL_SET_TEST     4 +#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5 +#define SNMP_MSG_INTERNAL_SET_VALUE    6 +/* Perform SNMP operation on object located externally. +   In theory this could be used for building a proxy agent. +   Practical use is for an enterprise spc. app. gateway. */ +#define SNMP_MSG_EXTERNAL_GET_OBJDEF   7 +#define SNMP_MSG_EXTERNAL_GET_VALUE    8 +#define SNMP_MSG_EXTERNAL_SET_TEST     9 +#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10 +#define SNMP_MSG_EXTERNAL_SET_VALUE    11 + +#define SNMP_COMMUNITY_STR_LEN 64 +struct snmp_msg_pstat +{ +  /* lwIP local port (161) binding */ +  struct udp_pcb *pcb; +  /* source IP address */ +  struct ip_addr sip; +  /* source UDP port */ +  u16_t sp; +  /* request type */ +  u8_t rt; +  /* request ID */ +  s32_t rid; +  /* error status */ +  s32_t error_status; +  /* error index */ +  s32_t error_index; +  /* community name (zero terminated) */ +  u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; +  /* community string length (exclusive zero term) */ +  u8_t com_strlen; +  /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ +  u8_t state; +  /* saved arguments for MSG_EXTERNAL_x */ +  struct mib_external_node *ext_mib_node; +  struct snmp_name_ptr ext_name_ptr; +  struct obj_def ext_object_def; +  struct snmp_obj_id ext_oid; +  /* index into input variable binding list */ +  u8_t vb_idx; +  /* ptr into input variable binding list */ +  struct snmp_varbind *vb_ptr; +  /* list of variable bindings from input */ +  struct snmp_varbind_root invb; +  /* list of variable bindings to output */ +  struct snmp_varbind_root outvb; +  /* output response lengths used in ASN encoding */ +  struct snmp_resp_header_lengths rhl; +}; + +struct snmp_msg_trap +{ +  /* lwIP local port (161) binding */ +  struct udp_pcb *pcb; +  /* destination IP address in network order */ +  struct ip_addr dip; + +  /* source enterprise ID (sysObjectID) */ +  struct snmp_obj_id *enterprise; +  /* source IP address, raw network order format */ +  u8_t sip_raw[4]; +  /* generic trap code */ +  u32_t gen_trap; +  /* specific trap code */ +  u32_t spc_trap; +  /* timestamp */ +  u32_t ts; +  /* list of variable bindings to output */ +  struct snmp_varbind_root outvb; +  /* output trap lengths used in ASN encoding */ +  struct snmp_trap_header_lengths thl; +}; + +/** Agent Version constant, 0 = v1 oddity */ +extern const s32_t snmp_version; +/** Agent default "public" community string */ +extern const char snmp_publiccommunity[7]; + +extern struct snmp_msg_trap trap_msg; + +/** Agent setup, start listening to port 161. */ +void snmp_init(void); +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst); + +/** Varbind-list functions. */ +struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); +void snmp_varbind_free(struct snmp_varbind *vb); +void snmp_varbind_list_free(struct snmp_varbind_root *root); +void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb); +struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); + +/** Handle an internal (recv) or external (private response) event. */ +void snmp_msg_event(u8_t request_id); +err_t snmp_send_response(struct snmp_msg_pstat *m_stat); +err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap); +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_MSG_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_structs.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_structs.h new file mode 100644 index 000000000..9f3f8a94e --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/snmp_structs.h @@ -0,0 +1,262 @@ +/** + * @file + * Generic MIB tree structures. + * + * @todo namespace prefixes + */ + +/* + * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Christiaan Simons <christiaan.simons@axon.tv> + */ + +#ifndef __LWIP_SNMP_STRUCTS_H__ +#define __LWIP_SNMP_STRUCTS_H__ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" + +#if SNMP_PRIVATE_MIB +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* MIB object instance */ +#define MIB_OBJECT_NONE 0  +#define MIB_OBJECT_SCALAR 1 +#define MIB_OBJECT_TAB 2 + +/* MIB object access */ +#define MIB_OBJECT_READ_ONLY 0 +#define MIB_OBJECT_READ_WRITE 1 +#define MIB_OBJECT_WRITE_ONLY 2 +#define MIB_OBJECT_NOT_ACCESSIBLE 3 + +/** object definition returned by (get_object_def)() */ +struct obj_def +{ +  /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */ +  u8_t instance; +  /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */ +  u8_t access; +  /* ASN type for this object */ +  u8_t asn_type; +  /* value length (host length) */ +  u16_t v_len; +  /* length of instance part of supplied object identifier */ +  u8_t  id_inst_len; +  /* instance part of supplied object identifier */ +  s32_t *id_inst_ptr; +}; + +struct snmp_name_ptr +{ +  u8_t ident_len; +  s32_t *ident; +}; + +/** MIB const scalar (.0) node */ +#define MIB_NODE_SC 0x01 +/** MIB const array node */ +#define MIB_NODE_AR 0x02 +/** MIB array node (mem_malloced from RAM) */ +#define MIB_NODE_RA 0x03 +/** MIB list root node (mem_malloced from RAM) */ +#define MIB_NODE_LR 0x04 +/** MIB node for external objects */ +#define MIB_NODE_EX 0x05 + +/** node "base class" layout, the mandatory fields for a node  */ +struct mib_node +{ +  /** returns struct obj_def for the given object identifier */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  /** returns object value for the given object identifier, +     @note the caller must allocate at least len bytes for the value */ +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  /** tests length and/or range BEFORE setting */ +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  /** sets object value, only to be called when set_test()  */ +  void (*set_value)(struct obj_def *od, u16_t len, void *value);   +  /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ +  const u8_t node_type; +  /* array or max list length */ +  const u16_t maxlength; +}; + +/** derived node for scalars .0 index */ +typedef struct mib_node mib_scalar_node; + +/** derived node, points to a fixed size const array +    of sub-identifiers plus a 'child' pointer */ +struct mib_array_node +{ +  /* inherited "base class" members */ +  void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (* const get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  const u8_t node_type; +  const u16_t maxlength; + +  /* aditional struct members */ +  const s32_t *objid; +  struct mib_node* const *nptr; +}; + +/** derived node, points to a fixed size mem_malloced array +    of sub-identifiers plus a 'child' pointer */ +struct mib_ram_array_node +{ +  /* inherited "base class" members */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  u8_t node_type; +  u16_t maxlength; + +  /* aditional struct members */ +  s32_t *objid; +  struct mib_node **nptr; +}; + +struct mib_list_node +{ +  struct mib_list_node *prev;   +  struct mib_list_node *next; +  s32_t objid; +  struct mib_node *nptr; +}; + +/** derived node, points to a doubly linked list +    of sub-identifiers plus a 'child' pointer */ +struct mib_list_rootnode +{ +  /* inherited "base class" members */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  u8_t node_type; +  u16_t maxlength; + +  /* aditional struct members */ +  struct mib_list_node *head; +  struct mib_list_node *tail; +  /* counts list nodes in list  */ +  u16_t count; +}; + +/** derived node, has access functions for mib object in external memory or device +    using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */ +struct mib_external_node +{ +  /* inherited "base class" members */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  u8_t node_type; +  u16_t maxlength; + +  /* aditional struct members */ +  /** points to an extenal (in memory) record of some sort of addressing +      information, passed to and interpreted by the funtions below */ +  void* addr_inf; +  /** tree levels under this node */ +  u8_t tree_levels; +  /** number of objects at this level */ +  u16_t (*level_length)(void* addr_inf, u8_t level); +  /** compares object sub identifier with external id +      return zero when equal, nonzero when unequal */ +  s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); +  void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); + +  /** async Questions */ +  void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); +  void (*get_value_q)(u8_t rid, struct obj_def *od); +  void (*set_test_q)(u8_t rid, struct obj_def *od); +  void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  /** async Answers */ +  void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  /** async Panic Close (agent returns error reply,  +      e.g. used for external transaction cleanup) */ +  void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident); +  void (*get_value_pc)(u8_t rid, struct obj_def *od); +  void (*set_test_pc)(u8_t rid, struct obj_def *od); +  void (*set_value_pc)(u8_t rid, struct obj_def *od); +}; + +/** export MIB tree from mib2.c */ +extern const struct mib_array_node internet; + +/** dummy function pointers for non-leaf MIB nodes from mib2.c */ +void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +void noleafs_get_value(struct obj_def *od, u16_t len, void *value); +u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); +void noleafs_set_value(struct obj_def *od, u16_t len, void *value); + +void snmp_oidtoip(s32_t *ident, struct ip_addr *ip); +void snmp_iptooid(struct ip_addr *ip, s32_t *ident); +void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); +void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); + +struct mib_list_node* snmp_mib_ln_alloc(s32_t id); +void snmp_mib_ln_free(struct mib_list_node *ln); +struct mib_list_rootnode* snmp_mib_lrn_alloc(void); +void snmp_mib_lrn_free(struct mib_list_rootnode *lrn); + +s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn); +s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn); +struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n); + +struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np); +struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); +u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident); +u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_STRUCTS_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sockets.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sockets.h new file mode 100644 index 000000000..7b52e151c --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sockets.h @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + + +#ifndef __LWIP_SOCKETS_H__ +#define __LWIP_SOCKETS_H__ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include <stddef.h> /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* members are in network byte order */ +struct sockaddr_in { +  u8_t sin_len; +  u8_t sin_family; +  u16_t sin_port; +  struct in_addr sin_addr; +  char sin_zero[8]; +}; + +struct sockaddr { +  u8_t sa_len; +  u8_t sa_family; +  char sa_data[14]; +}; + +#ifndef socklen_t +#  define socklen_t u32_t +#endif + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM     1 +#define SOCK_DGRAM      2 +#define SOCK_RAW        3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h! + */ +#define  SO_DEBUG       0x0001 /* Unimplemented: turn on debugging info recording */ +#define  SO_ACCEPTCONN  0x0002 /* socket has had listen() */ +#define  SO_REUSEADDR   0x0004 /* Unimplemented: allow local address reuse */ +#define  SO_KEEPALIVE   0x0008 /* keep connections alive */ +#define  SO_DONTROUTE   0x0010 /* Unimplemented: just use interface addresses */ +#define  SO_BROADCAST   0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define  SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define  SO_LINGER      0x0080 /* linger on close if data present */ +#define  SO_OOBINLINE   0x0100 /* Unimplemented: leave received OOB data in line */ +#define  SO_REUSEPORT   0x0200 /* Unimplemented: allow local address & port reuse */ + +#define SO_DONTLINGER   ((int)(~SO_LINGER)) + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF    0x1001    /* Unimplemented: send buffer size */ +#define SO_RCVBUF    0x1002    /* receive buffer size */ +#define SO_SNDLOWAT  0x1003    /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT  0x1004    /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO  0x1005    /* Unimplemented: send timeout */ +#define SO_RCVTIMEO  0x1006    /* receive timeout */ +#define SO_ERROR     0x1007    /* get error status and clear */ +#define SO_TYPE      0x1008    /* get socket type */ +#define SO_CONTIMEO  0x1009    /* Unimplemented: connect timeout */ +#define SO_NO_CHECK  0x100a    /* don't create UDP checksum */ + + +/* + * Structure used for manipulating linger option. + */ +struct linger { +       int l_onoff;                /* option on/off */ +       int l_linger;               /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define  SOL_SOCKET  0xfff    /* options for socket level */ + + +#define AF_UNSPEC       0 +#define AF_INET         2 +#define PF_INET         AF_INET +#define PF_UNSPEC       AF_UNSPEC + +#define IPPROTO_IP      0 +#define IPPROTO_TCP     6 +#define IPPROTO_UDP     17 +#define IPPROTO_UDPLITE 136 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK       0x01    /* Peeks at an incoming message */ +#define MSG_WAITALL    0x02    /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB        0x04    /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT   0x08    /* Nonblocking i/o for this operation only */ +#define MSG_MORE       0x10    /* Sender will send more */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS             1 +#define IP_TTL             2 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE   0x03    /* set pcb->keep_idle  - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL  0x04    /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT    0x05    /* set pcb->keep_cnt   - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_IGMP +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_ADD_MEMBERSHIP  3 +#define IP_DROP_MEMBERSHIP 4 +#define IP_MULTICAST_TTL   5 +#define IP_MULTICAST_IF    6 +#define IP_MULTICAST_LOOP  7 + +typedef struct ip_mreq { +    struct in_addr imr_multiaddr; /* IP multicast address of group */ +    struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired.  These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network.  Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load).  The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service.  In many networks + * better performance for one of these parameters is coupled with worse + * performance on another.  Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK          0x1E +#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY          0x10 +#define IPTOS_THROUGHPUT        0x08 +#define IPTOS_RELIABILITY       0x04 +#define IPTOS_LOWCOST           0x02 +#define IPTOS_MINCOST           IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only.  The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK                 0xe0 +#define IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL           0xe0 +#define IPTOS_PREC_INTERNETCONTROL      0xc0 +#define IPTOS_PREC_CRITIC_ECP           0xa0 +#define IPTOS_PREC_FLASHOVERRIDE        0x80 +#define IPTOS_PREC_FLASH                0x60 +#define IPTOS_PREC_IMMEDIATE            0x40 +#define IPTOS_PREC_PRIORITY             0x20 +#define IPTOS_PREC_ROUTINE              0x00 + + +/* + * Commands for ioctlsocket(),  taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word.  The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK    0x7fU           /* parameters must be < 128 bytes */ +#define IOC_VOID        0x20000000UL    /* no parameters */ +#define IOC_OUT         0x40000000UL    /* copy out parameters */ +#define IOC_IN          0x80000000UL    /* copy in parameters */ +#define IOC_INOUT       (IOC_IN|IOC_OUT) +                                        /* 0x20000000 distinguishes new & +                                           old ioctl's */ +#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD    _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO     _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT  _IOW('s',  0, unsigned long)  /* set high watermark */ +#define SIOCGHIWAT  _IOR('s',  1, unsigned long)  /* get high watermark */ +#define SIOCSLOWAT  _IOW('s',  2, unsigned long)  /* set low watermark */ +#define SIOCGLOWAT  _IOR('s',  3, unsigned long)  /* get low watermark */ +#define SIOCATMARK  _IOR('s',  7, unsigned long)  /* at oob mark? */ +#endif + +/* Socket flags: */ +#ifndef O_NONBLOCK +#define O_NONBLOCK    04000U +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET +  #undef  FD_SETSIZE +  /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ +  #define FD_SETSIZE    MEMP_NUM_NETCONN +  #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7))) +  #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) +  #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7))) +  #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p))) + +  typedef struct fd_set { +          unsigned char fd_bits [(FD_SETSIZE+7)/8]; +        } fd_set; + +#endif /* FD_SET */ + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include <sys/time.h> in cc.h */  +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { +  long    tv_sec;         /* seconds */ +  long    tv_usec;        /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +void lwip_socket_init(void); + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, +      struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, +    const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, +                struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); + +#if LWIP_COMPAT_SOCKETS +#define accept(a,b,c)         lwip_accept(a,b,c) +#define bind(a,b,c)           lwip_bind(a,b,c) +#define shutdown(a,b)         lwip_shutdown(a,b) +#define closesocket(s)        lwip_close(s) +#define connect(a,b,c)        lwip_connect(a,b,c) +#define getsockname(a,b,c)    lwip_getsockname(a,b,c) +#define getpeername(a,b,c)    lwip_getpeername(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) +#define listen(a,b)           lwip_listen(a,b) +#define recv(a,b,c,d)         lwip_recv(a,b,c,d) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) +#define send(a,b,c,d)         lwip_send(a,b,c,d) +#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f) +#define socket(a,b,c)         lwip_socket(a,b,c) +#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e) +#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define read(a,b,c)           lwip_read(a,b,c) +#define write(a,b,c)          lwip_write(a,b,c) +#define close(s)              lwip_close(s) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* __LWIP_SOCKETS_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/stats.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/stats.h new file mode 100644 index 000000000..aa179f5c0 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/stats.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_STATS_H__ +#define __LWIP_STATS_H__ + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER     u32_t +#define STAT_COUNTER_F   U32_F +#else +#define STAT_COUNTER     u16_t +#define STAT_COUNTER_F   U16_F +#endif  + +struct stats_proto { +  STAT_COUNTER xmit;             /* Transmitted packets. */ +  STAT_COUNTER recv;             /* Received packets. */ +  STAT_COUNTER fw;               /* Forwarded packets. */ +  STAT_COUNTER drop;             /* Dropped packets. */ +  STAT_COUNTER chkerr;           /* Checksum error. */ +  STAT_COUNTER lenerr;           /* Invalid length error. */ +  STAT_COUNTER memerr;           /* Out of memory error. */ +  STAT_COUNTER rterr;            /* Routing error. */ +  STAT_COUNTER proterr;          /* Protocol error. */ +  STAT_COUNTER opterr;           /* Error in options. */ +  STAT_COUNTER err;              /* Misc error. */ +  STAT_COUNTER cachehit; +}; + +struct stats_igmp { +  STAT_COUNTER lenerr;           /* Invalid length error. */ +  STAT_COUNTER chkerr;           /* Checksum error. */ +  STAT_COUNTER v1_rxed;          /* */ +  STAT_COUNTER join_sent;        /* */ +  STAT_COUNTER leave_sent;       /* */ +  STAT_COUNTER unicast_query;    /* */ +  STAT_COUNTER report_sent;      /* */ +  STAT_COUNTER report_rxed;      /* */ +  STAT_COUNTER group_query_rxed; /* */ +}; + +struct stats_mem { +  mem_size_t avail; +  mem_size_t used; +  mem_size_t max; +  STAT_COUNTER err; +  STAT_COUNTER illegal; +}; + +struct stats_syselem { +  STAT_COUNTER used; +  STAT_COUNTER max; +  STAT_COUNTER err; +}; + +struct stats_sys { +  struct stats_syselem sem; +  struct stats_syselem mbox; +}; + +struct stats_ { +#if LINK_STATS +  struct stats_proto link; +#endif +#if ETHARP_STATS +  struct stats_proto etharp; +#endif +#if IPFRAG_STATS +  struct stats_proto ip_frag; +#endif +#if IP_STATS +  struct stats_proto ip; +#endif +#if ICMP_STATS +  struct stats_proto icmp; +#endif +#if IGMP_STATS +  struct stats_igmp igmp; +#endif +#if UDP_STATS +  struct stats_proto udp; +#endif +#if TCP_STATS +  struct stats_proto tcp; +#endif +#if MEM_STATS +  struct stats_mem mem; +#endif +#if MEMP_STATS +  struct stats_mem memp[MEMP_MAX]; +#endif +#if SYS_STATS +  struct stats_sys sys; +#endif +}; + +extern struct stats_ lwip_stats; + +#define stats_init() /* Compatibility define, not init needed. */ + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#else +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) do { lwip_stats.mem.used += y; \ +                                    if (lwip_stats.mem.max < lwip_stats.mem.used) { \ +                                        lwip_stats.mem.max = lwip_stats.mem.used; \ +                                    } \ +                                 } while(0) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + +#if MEMP_STATS +#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y +#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) +#define MEMP_STATS_INC_USED(x, i) do { ++lwip_stats.memp[i].used; \ +                                    if (lwip_stats.memp[i].max < lwip_stats.memp[i].used) { \ +                                        lwip_stats.memp[i].max = lwip_stats.memp[i].used; \ +                                    } \ +                                 } while(0) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) +#else +#define MEMP_STATS_AVAIL(x, i, y) +#define MEMP_STATS_INC(x, i) +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_INC_USED(x, i) +#define MEMP_STATS_DISPLAY(i) +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_DISPLAY() +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void); +void stats_display_proto(struct stats_proto *proto, char *name); +void stats_display_igmp(struct stats_igmp *igmp); +void stats_display_mem(struct stats_mem *mem, char *name); +void stats_display_memp(struct stats_mem *mem, int index); +void stats_display_sys(struct stats_sys *sys); +#else +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_STATS_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sys.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sys.h new file mode 100644 index 000000000..0cc84ddf1 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/sys.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_SYS_H__ +#define __LWIP_SYS_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null +   definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mbox_t; +struct sys_timeo {u8_t dummy;}; + +#define sys_init() +#define sys_timeout(m,h,a) +#define sys_untimeout(m,a) +#define sys_sem_new(c) c +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_sem_wait_timeout(s,t) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_mbox_new(s) 0 +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) + +#define sys_thread_new(n,t,a,s,p) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/* sys_mbox_tryfetch returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT  + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { +  struct sys_timeo *next; +  u32_t time; +  sys_timeout_handler h; +  void *arg; +}; + +struct sys_timeouts { +  struct sys_timeo *next; +}; + +/* sys_init() must be called before anthing else. */ +void sys_init(void); + +/* + * sys_timeout(): + * + * Schedule a timeout a specified amount of milliseconds in the + * future. When the timeout occurs, the specified timeout handler will + * be called. The handler will be passed the "arg" argument when + * called. + * + */ +void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +void sys_untimeout(sys_timeout_handler h, void *arg); +struct sys_timeouts *sys_arch_timeouts(void); + +/* Semaphore functions. */ +sys_sem_t sys_sem_new(u8_t count); +void sys_sem_signal(sys_sem_t sem); +u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout); +void sys_sem_free(sys_sem_t sem); +void sys_sem_wait(sys_sem_t sem); +int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout); + +/* Time functions. */ +#ifndef sys_msleep +void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ +#endif +#ifndef sys_jiffies +u32_t sys_jiffies(void); /* since power up. */ +#endif + +/* Mailbox functions. */ +sys_mbox_t sys_mbox_new(int size); +void sys_mbox_post(sys_mbox_t mbox, void *msg); +err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg); +u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout); +#ifndef sys_arch_mbox_tryfetch /* Allow port to override with a macro */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg); +#endif +/* For now, we map straight to sys_arch implementation. */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +void sys_mbox_free(sys_mbox_t mbox); +void sys_mbox_fetch(sys_mbox_t mbox, void **msg); + +/* Thread functions. */ +sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/** Returns the current time in milliseconds. */ +u32_t sys_now(void); + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. +   In some implementations they can provide a more light-weight protection +   mechanism than using semaphores. Otherwise semaphores can be used for +   implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex.  This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void); +void sys_arch_unprotect(sys_prot_t pval); + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) +#define SYS_ARCH_UNPROTECT(lev) + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                var += val; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                var -= val; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                ret = var; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                var = val; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_SET */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SYS_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/tcp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/tcp.h new file mode 100644 index 000000000..8f6b9d3c1 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/tcp.h @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_TCP_H__ +#define __LWIP_TCP_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +#define tcp_init() /* Compatibility define, not init needed. */ +void             tcp_tmr     (void);  /* Must be called every +                                         TCP_TMR_INTERVAL +                                         ms. (Typically 250 ms). */ +/* Application program's interface: */ +struct tcp_pcb * tcp_new     (void); +struct tcp_pcb * tcp_alloc   (u8_t prio); + +void             tcp_arg     (struct tcp_pcb *pcb, void *arg); +void             tcp_accept  (struct tcp_pcb *pcb, +                              err_t (* accept)(void *arg, struct tcp_pcb *newpcb, +                 err_t err)); +void             tcp_recv    (struct tcp_pcb *pcb, +                              err_t (* recv)(void *arg, struct tcp_pcb *tpcb, +                              struct pbuf *p, err_t err)); +void             tcp_sent    (struct tcp_pcb *pcb, +                              err_t (* sent)(void *arg, struct tcp_pcb *tpcb, +                              u16_t len)); +void             tcp_poll    (struct tcp_pcb *pcb, +                              err_t (* poll)(void *arg, struct tcp_pcb *tpcb), +                              u8_t interval); +void             tcp_err     (struct tcp_pcb *pcb, +                              void (* err)(void *arg, err_t err)); + +#define          tcp_mss(pcb)      ((pcb)->mss) +#define          tcp_sndbuf(pcb)   ((pcb)->snd_buf) + +#if TCP_LISTEN_BACKLOG +#define          tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--) +#else  /* TCP_LISTEN_BACKLOG */ +#define          tcp_accepted(pcb) +#endif /* TCP_LISTEN_BACKLOG */ + +void             tcp_recved  (struct tcp_pcb *pcb, u16_t len); +err_t            tcp_bind    (struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                              u16_t port); +err_t            tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                              u16_t port, err_t (* connected)(void *arg, +                              struct tcp_pcb *tpcb, +                              err_t err)); + +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +#define          tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void             tcp_abandon (struct tcp_pcb *pcb, int reset); +#define          tcp_abort(pcb) tcp_abandon((pcb), 1) +err_t            tcp_close   (struct tcp_pcb *pcb); + +/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len, +                              u8_t apiflags); + +void             tcp_setprio (struct tcp_pcb *pcb, u8_t prio); + +#define TCP_PRIO_MIN    1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX    127 + +/* It is also possible to call these two functions at the right +   intervals (instead of calling tcp_tmr()). */ +void             tcp_slowtmr (void); +void             tcp_fasttmr (void); + + +/* Only used by IP to pass a TCP segment to TCP: */ +void             tcp_input   (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +err_t            tcp_output  (struct tcp_pcb *pcb); +void             tcp_rexmit  (struct tcp_pcb *pcb); +void             tcp_rexmit_rto  (struct tcp_pcb *pcb); +u32_t            tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + *   than one unsent segment - with lwIP, this can happen although unsent->len < mss) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ +                            ((tpcb)->flags & TF_NODELAY) || \ +                            (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ +                              ((tpcb)->unsent->len >= (tpcb)->mss))) \ +                            ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b)     ((s32_t)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b)    ((s32_t)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b)     ((s32_t)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b)    ((s32_t)((a)-(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL       250  /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL      TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL      (2*TCP_TMR_INTERVAL)  /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT        6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef  TCP_KEEPIDLE_DEFAULT +#define  TCP_KEEPIDLE_DEFAULT     7200000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef  TCP_KEEPINTVL_DEFAULT +#define  TCP_KEEPINTVL_DEFAULT    75000UL   /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef  TCP_KEEPCNT_DEFAULT +#define  TCP_KEEPCNT_DEFAULT      9U        /* Default Counter for KEEPALIVE probes */ +#endif + +#define  TCP_MAXIDLE              TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT  /* Maximum KEEPALIVE probe time */ + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { +  PACK_STRUCT_FIELD(u16_t src); +  PACK_STRUCT_FIELD(u16_t dest); +  PACK_STRUCT_FIELD(u32_t seqno); +  PACK_STRUCT_FIELD(u32_t ackno); +  PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); +  PACK_STRUCT_FIELD(u16_t wnd); +  PACK_STRUCT_FIELD(u16_t chksum); +  PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr)  (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags)) +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) + +#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \ +          TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0)) + +enum tcp_state { +  CLOSED      = 0, +  LISTEN      = 1, +  SYN_SENT    = 2, +  SYN_RCVD    = 3, +  ESTABLISHED = 4, +  FIN_WAIT_1  = 5, +  FIN_WAIT_2  = 6, +  CLOSE_WAIT  = 7, +  CLOSING     = 8, +  LAST_ACK    = 9, +  TIME_WAIT   = 10 +}; + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET     (u8_t)0x08U   /* Connection was reset. */ +#define TF_CLOSED    (u8_t)0x10U   /* Connection was sucessfully closed. */ +#define TF_GOT_FIN   (u8_t)0x20U   /* Connection was closed by the remote end. */ + + +#if LWIP_CALLBACK_API +  /* Function to call when a listener has been connected. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb a new tcp_pcb that now is connected +   * @param err an error argument (TODO: that is current always ERR_OK?) +   * @return ERR_OK: accept the new connection, +   *                 any other err_t abortsthe new connection +   */ +#define DEF_ACCEPT_CALLBACK  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err) +#else /* LWIP_CALLBACK_API */ +#define DEF_ACCEPT_CALLBACK +#endif /* LWIP_CALLBACK_API */ + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ +  type *next; /* for the linked list */ \ +  enum tcp_state state; /* TCP state */ \ +  u8_t prio; \ +  void *callback_arg; \ +  /* ports are in host byte order */ \ +  u16_t local_port; \ +  /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ +  DEF_ACCEPT_CALLBACK + + +/* the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ +  IP_PCB; +/** protocol specific PCB members */ +  TCP_PCB_COMMON(struct tcp_pcb); + +  /* ports are in host byte order */ +  u16_t remote_port; +   +  u8_t flags; +#define TF_ACK_DELAY   ((u8_t)0x01U)   /* Delayed ACK. */ +#define TF_ACK_NOW     ((u8_t)0x02U)   /* Immediate ACK. */ +#define TF_INFR        ((u8_t)0x04U)   /* In fast recovery. */ +#define TF_TIMESTAMP   ((u8_t)0x08U)   /* Timestamp option enabled */ +#define TF_FIN         ((u8_t)0x20U)   /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY     ((u8_t)0x40U)   /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR ((u8_t)0x80U)   /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ + +  /* the rest of the fields are in host byte order +     as we have to do some math with them */ +  /* receiver variables */ +  u32_t rcv_nxt;   /* next seqno expected */ +  u16_t rcv_wnd;   /* receiver window available */ +  u16_t rcv_ann_wnd; /* receiver window to announce */ +  u32_t rcv_ann_right_edge; /* announced right edge of window */ + +  /* Timers */ +  u32_t tmr; +  u8_t polltmr, pollinterval; +   +  /* Retransmission timer. */ +  s16_t rtime; +   +  u16_t mss;   /* maximum segment size */ +   +  /* RTT (round trip time) estimation variables */ +  u32_t rttest; /* RTT estimate in 500ms ticks */ +  u32_t rtseq;  /* sequence number being timed */ +  s16_t sa, sv; /* @todo document this */ + +  s16_t rto;    /* retransmission time-out */ +  u8_t nrtx;    /* number of retransmissions */ + +  /* fast retransmit/recovery */ +  u32_t lastack; /* Highest acknowledged seqno. */ +  u8_t dupacks; +   +  /* congestion avoidance/control variables */ +  u16_t cwnd;   +  u16_t ssthresh; + +  /* sender variables */ +  u32_t snd_nxt;   /* next new seqno to be sent */ +  u16_t snd_wnd;   /* sender window */ +  u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last +                             window update. */ +  u32_t snd_lbb;       /* Sequence number of next byte to be buffered. */ + +  u16_t acked; +   +  u16_t snd_buf;   /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3) +  u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ +   +   +  /* These are ordered by sequence number: */ +  struct tcp_seg *unsent;   /* Unsent (queued) segments. */ +  struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ   +  struct tcp_seg *ooseq;    /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + +  struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API +  /* Function to be called when more send buffer space is available. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb which has send buffer space available +   * @param space the amount of bytes available +   * @return ERR_OK: try to send some data by calling tcp_output +   */ +  err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space); +   +  /* Function to be called when (in-sequence) data has arrived. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb for which data has arrived +   * @param p the packet buffer which arrived +   * @param err an error argument (TODO: that is current always ERR_OK?) +   * @return ERR_OK: try to send some data by calling tcp_output +   */ +  err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); + +  /* Function to be called when a connection has been set up. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb that now is connected +   * @param err an error argument (TODO: that is current always ERR_OK?) +   * @return value is currently ignored +   */ +  err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err); + +  /* Function which is called periodically. +   * The period can be adjusted in multiples of the TCP slow timer interval +   * by changing tcp_pcb.polltmr. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb to poll for +   * @return ERR_OK: try to send some data by calling tcp_output +   */ +  err_t (* poll)(void *arg, struct tcp_pcb *pcb); + +  /* Function to be called whenever a fatal error occurs. +   * There is no pcb parameter since most of the times, the pcb is +   * already deallocated (or there is no pcb) when this function is called. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param err an indication why the error callback is called: +   *            ERR_ABRT: aborted through tcp_abort or by a TCP timer +   *            ERR_RST: the connection was reset by the remote host +   */ +  void (* errf)(void *arg, err_t err); +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS +  u32_t ts_lastacksent; +  u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + +  /* idle time before KEEPALIVE is sent */ +  u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE +  u32_t keep_intvl; +  u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ +   +  /* Persist timer counter */ +  u32_t persist_cnt; +  /* Persist timer back-off */ +  u8_t persist_backoff; + +  /* KEEPALIVE counter */ +  u8_t keep_cnt_sent; +}; + +struct tcp_pcb_listen {   +/* Common members of all PCB types */ +  IP_PCB; +/* Protocol specific PCB members */ +  TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if TCP_LISTEN_BACKLOG +  u8_t backlog; +  u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + +#if LWIP_EVENT_API + +enum lwip_event { +  LWIP_EVENT_ACCEPT, +  LWIP_EVENT_SENT, +  LWIP_EVENT_RECV, +  LWIP_EVENT_CONNECTED, +  LWIP_EVENT_POLL, +  LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, +         enum lwip_event, +         struct pbuf *p, +         u16_t size, +         err_t err); + +#define TCP_EVENT_ACCEPT(pcb,err,ret)    ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                   LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret)       ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_POLL, NULL, 0, ERR_OK) +#define TCP_EVENT_ERR(errf,arg,err)  lwip_tcp_event((arg), NULL, \ +                LWIP_EVENT_ERR, NULL, 0, (err)) +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(pcb,err,ret)                          \ +  do {                                                         \ +    if((pcb)->accept != NULL)                                  \ +      (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err));  \ +    else (ret) = ERR_OK;                                       \ +  } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret)                          \ +  do {                                                         \ +    if((pcb)->sent != NULL)                                    \ +      (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space));  \ +    else (ret) = ERR_OK;                                       \ +  } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret)                           \ +  do {                                                          \ +    if((pcb)->recv != NULL) {                                   \ +      (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \ +    } else {                                                    \ +      (ret) = ERR_OK;                                           \ +      if (p != NULL)                                            \ +        pbuf_free(p);                                           \ +    }                                                           \ +  } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret)                         \ +  do {                                                           \ +    if((pcb)->connected != NULL)                                 \ +      (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ +    else (ret) = ERR_OK;                                         \ +  } while (0) + +#define TCP_EVENT_POLL(pcb,ret)                                \ +  do {                                                         \ +    if((pcb)->poll != NULL)                                    \ +      (ret) = (pcb)->poll((pcb)->callback_arg,(pcb));          \ +    else (ret) = ERR_OK;                                       \ +  } while (0) + +#define TCP_EVENT_ERR(errf,arg,err)                            \ +  do {                                                         \ +    if((errf) != NULL)                                         \ +      (errf)((arg),(err));                                     \ +  } while (0) + +#endif /* LWIP_EVENT_API */ + +/* This structure represents a TCP segment on the unsent and unacked queues */ +struct tcp_seg { +  struct tcp_seg *next;    /* used when putting segements on a queue */ +  struct pbuf *p;          /* buffer containing data + TCP header */ +  void *dataptr;           /* pointer to the TCP data in the pbuf */ +  u16_t len;               /* the TCP length of this segment */ +  u8_t  flags; +#define TF_SEG_OPTS_MSS   (u8_t)0x01U   /* Include MSS option. */ +#define TF_SEG_OPTS_TS    (u8_t)0x02U   /* Include timestamp option. */ +  struct tcp_hdr *tcphdr;  /* the TCP header */ +}; + +#define LWIP_TCP_OPT_LENGTH(flags)              \ +  (flags & TF_SEG_OPTS_MSS ? 4  : 0) +          \ +  (flags & TF_SEG_OPTS_TS  ? 12 : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(x) (x) = htonl(((u32_t)2 << 24) |          \ +                                            ((u32_t)4 << 16) |          \ +                                            (((u32_t)TCP_MSS / 256) << 8) | \ +                                            (TCP_MSS & 255)) + +/* Internal functions and global variables: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); +void tcp_pcb_purge(struct tcp_pcb *pcb); +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); + +u8_t tcp_segs_free(struct tcp_seg *seg); +u8_t tcp_seg_free(struct tcp_seg *seg); +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); + +#define tcp_ack(pcb)                               \ +  do {                                             \ +    if((pcb)->flags & TF_ACK_DELAY) {              \ +      (pcb)->flags &= ~TF_ACK_DELAY;               \ +      (pcb)->flags |= TF_ACK_NOW;                  \ +      tcp_output(pcb);                             \ +    }                                              \ +    else {                                         \ +      (pcb)->flags |= TF_ACK_DELAY;                \ +    }                                              \ +  } while (0) + +#define tcp_ack_now(pcb)                           \ +  do {                                             \ +    (pcb)->flags |= TF_ACK_NOW;                    \ +    tcp_output(pcb);                               \ +  } while (0) + +err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags); +err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len, +                  u8_t flags, u8_t apiflags, u8_t optflags); + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); + +void tcp_rst(u32_t seqno, u32_t ackno, +       struct ip_addr *local_ip, struct ip_addr *remote_ip, +       u16_t local_port, u16_t remote_port); + +u32_t tcp_next_iss(void); + +void tcp_keepalive(struct tcp_pcb *pcb); +void tcp_zero_window_probe(struct tcp_pcb *pcb); + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr); +void tcp_debug_print_flags(u8_t flags); +void tcp_debug_print_state(enum tcp_state s); +void tcp_debug_print_pcbs(void); +s16_t tcp_pcbs_sane(void); +#else +#  define tcp_debug_print(tcphdr) +#  define tcp_debug_print_flags(flags) +#  define tcp_debug_print_state(s) +#  define tcp_debug_print_pcbs() +#  define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +#if NO_SYS +#define tcp_timer_needed() +#else +void tcp_timer_needed(void); +#endif + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ +  struct tcp_pcb_listen *listen_pcbs;  +  struct tcp_pcb *pcbs; +}; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a +              state in which they accept or send +              data. */ +extern struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */ + +extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */ + +/* Axioms about the above lists:    +   1) Every TCP PCB that is not CLOSED is in one of the lists. +   2) A PCB is only in one of the lists. +   3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. +   4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ + +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB +   with a PCB list or removes a PCB from a list, respectively. */ +#if 0 +#define TCP_REG(pcbs, npcb) do {\ +                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \ +                            for(tcp_tmp_pcb = *pcbs; \ +          tcp_tmp_pcb != NULL; \ +        tcp_tmp_pcb = tcp_tmp_pcb->next) { \ +                                LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \ +                            } \ +                            LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \ +                            npcb->next = *pcbs; \ +                            LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \ +                            *(pcbs) = npcb; \ +                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ +              tcp_timer_needed(); \ +                            } while(0) +#define TCP_RMV(pcbs, npcb) do { \ +                            LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \ +                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \ +                            if(*pcbs == npcb) { \ +                               *pcbs = (*pcbs)->next; \ +                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ +                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \ +                                  tcp_tmp_pcb->next = npcb->next; \ +                                  break; \ +                               } \ +                            } \ +                            npcb->next = NULL; \ +                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ +                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \ +                            } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb)                        \ +  do {                                             \ +    npcb->next = *pcbs;                            \ +    *(pcbs) = npcb;                                \ +    tcp_timer_needed();                            \ +  } while (0) + +#define TCP_RMV(pcbs, npcb)                        \ +  do {                                             \ +    if(*(pcbs) == npcb) {                          \ +      (*(pcbs)) = (*pcbs)->next;                   \ +    }                                              \ +    else {                                         \ +      for(tcp_tmp_pcb = *pcbs;                                         \ +          tcp_tmp_pcb != NULL;                                         \ +          tcp_tmp_pcb = tcp_tmp_pcb->next) {                           \ +        if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) {   \ +          tcp_tmp_pcb->next = npcb->next;          \ +          break;                                   \ +        }                                          \ +      }                                            \ +    }                                              \ +    npcb->next = NULL;                             \ +  } while(0) + +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/tcpip.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/tcpip.h new file mode 100644 index 000000000..75393ee91 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/tcpip.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_TCPIP_H__ +#define __LWIP_TCPIP_H__ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" +#include "lwip/netifapi.h" +#include "lwip/pbuf.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_sem_t lock_tcpip_core; +#define LOCK_TCPIP_CORE()     sys_sem_wait(lock_tcpip_core) +#define UNLOCK_TCPIP_CORE()   sys_sem_signal(lock_tcpip_core) +#define TCPIP_APIMSG(m)       tcpip_apimsg_lock(m) +#define TCPIP_APIMSG_ACK(m) +#define TCPIP_NETIFAPI(m)     tcpip_netifapi_lock(m) +#define TCPIP_NETIFAPI_ACK(m) +#else +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#define TCPIP_APIMSG(m)       tcpip_apimsg(m) +#define TCPIP_APIMSG_ACK(m)   sys_sem_signal(m->conn->op_completed) +#define TCPIP_NETIFAPI(m)     tcpip_netifapi(m) +#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(m->sem) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +void tcpip_init(void (* tcpip_init_done)(void *), void *arg); + +#if LWIP_NETCONN +err_t tcpip_apimsg(struct api_msg *apimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_apimsg_lock(struct api_msg *apimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +#if LWIP_NETIF_API +err_t tcpip_netifapi(struct netifapi_msg *netifapimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block); +#define tcpip_callback(f, ctx)              tcpip_callback_with_block(f, ctx, 1) + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); + +enum tcpip_msg_type { +#if LWIP_NETCONN +  TCPIP_MSG_API, +#endif /* LWIP_NETCONN */ +  TCPIP_MSG_INPKT, +#if LWIP_NETIF_API +  TCPIP_MSG_NETIFAPI, +#endif /* LWIP_NETIF_API */ +  TCPIP_MSG_CALLBACK, +  TCPIP_MSG_TIMEOUT, +  TCPIP_MSG_UNTIMEOUT +}; + +struct tcpip_msg { +  enum tcpip_msg_type type; +  sys_sem_t *sem; +  union { +#if LWIP_NETCONN +    struct api_msg *apimsg; +#endif /* LWIP_NETCONN */ +#if LWIP_NETIF_API +    struct netifapi_msg *netifapimsg; +#endif /* LWIP_NETIF_API */ +    struct { +      struct pbuf *p; +      struct netif *netif; +    } inp; +    struct { +      void (*f)(void *ctx); +      void *ctx; +    } cb; +    struct { +      u32_t msecs; +      sys_timeout_handler h; +      void *arg; +    } tmo; +  } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* __LWIP_TCPIP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/udp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/udp.h new file mode 100644 index 000000000..d7b2a3820 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/lwip/udp.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_UDP_H__ +#define __LWIP_UDP_H__ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { +  PACK_STRUCT_FIELD(u16_t src); +  PACK_STRUCT_FIELD(u16_t dest);  /* src/dest UDP ports */ +  PACK_STRUCT_FIELD(u16_t len); +  PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE  0x02U +#define UDP_FLAGS_CONNECTED  0x04U + +struct udp_pcb { +/* Common members of all PCB types */ +  IP_PCB; + +/* Protocol specific PCB members */ + +  struct udp_pcb *next; + +  u8_t flags; +  /* ports are in host byte order */ +  u16_t local_port, remote_port; + +#if LWIP_IGMP +  /* outgoing network interface for multicast packets */ +  struct ip_addr multicast_ip; +#endif /* LWIP_IGMP */ + +#if LWIP_UDPLITE +  /* used for UDP_LITE only */ +  u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + +  /* receive callback function +   * addr and port are in same byte order as in the pcb +   * The callback is responsible for freeing the pbuf +   * if it's not used any more. +   * +   * @param arg user supplied argument (udp_pcb.recv_arg) +   * @param pcb the udp_pcb which received data +   * @param p the packet buffer that was received +   * @param addr the remote IP address from which the packet was received +   * @param port the remote port from which the packet was received +   */ +  void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p, +    struct ip_addr *addr, u16_t port); +  /* user-supplied argument for the recv callback */ +  void *recv_arg;   +}; +/* udp_pcbs export for exernal reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the +   UDP code. */ +struct udp_pcb * udp_new        (void); +void             udp_remove     (struct udp_pcb *pcb); +err_t            udp_bind       (struct udp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port); +err_t            udp_connect    (struct udp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port); +void             udp_disconnect    (struct udp_pcb *pcb); +void             udp_recv       (struct udp_pcb *pcb, +         void (* recv)(void *arg, struct udp_pcb *upcb, +                 struct pbuf *p, +                 struct ip_addr *addr, +                 u16_t port), +         void *recv_arg); +err_t            udp_sendto_if  (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif); +err_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port); +err_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p); + +#define          udp_flags(pcb)  ((pcb)->flags) +#define          udp_setflags(pcb, f)  ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void             udp_input      (struct pbuf *p, struct netif *inp); + +#define udp_init() /* Compatibility define, not init needed. */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr); +#else +#define udp_debug_print(udphdr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* __LWIP_UDP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/etharp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/etharp.h new file mode 100644 index 000000000..db691d91d --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/etharp.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv> + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#ifndef __NETIF_ETHARP_H__ +#define __NETIF_ETHARP_H__ + +#include "lwip/opt.h" + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE          0 +#endif + +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN     6 +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { +  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_hdr { +#if ETH_PAD_SIZE +  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif +  PACK_STRUCT_FIELD(struct eth_addr dest); +  PACK_STRUCT_FIELD(struct eth_addr src); +  PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message */ +struct etharp_hdr { +  PACK_STRUCT_FIELD(struct eth_hdr ethhdr); +  PACK_STRUCT_FIELD(u16_t hwtype); +  PACK_STRUCT_FIELD(u16_t proto); +  PACK_STRUCT_FIELD(u16_t _hwlen_protolen); +  PACK_STRUCT_FIELD(u16_t opcode); +  PACK_STRUCT_FIELD(struct eth_addr shwaddr); +  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); +  PACK_STRUCT_FIELD(struct eth_addr dhwaddr); +  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ethip_hdr { +  PACK_STRUCT_FIELD(struct eth_hdr eth); +  PACK_STRUCT_FIELD(struct ip_hdr ip); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/** 5 seconds period */ +#define ARP_TMR_INTERVAL 5000 + +#define ETHTYPE_ARP       0x0806 +#define ETHTYPE_IP        0x0800 +#define ETHTYPE_PPPOEDISC 0x8863  /* PPP Over Ethernet Discovery Stage */ +#define ETHTYPE_PPPOE     0x8864  /* PPP Over Ethernet Session Stage */ + +/** ARP message types (opcodes) */ +#define ARP_REQUEST 1 +#define ARP_REPLY   2 + +#if ARP_QUEUEING +/** struct for queueing outgoing packets for unknown address +  * defined here to be accessed by memp.h +  */ +struct etharp_q_entry { +  struct etharp_q_entry *next; +  struct pbuf *p; +}; +#endif /* ARP_QUEUEING */ + +#define etharp_init() /* Compatibility define, not init needed. */ +void etharp_tmr(void); +s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, +         struct eth_addr **eth_ret, struct ip_addr **ip_ret); +void etharp_ip_input(struct netif *netif, struct pbuf *p); +void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, +         struct pbuf *p); +err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr); +err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr); +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + *  this is an ARP packet sent by a node in order to spontaneously cause other + *  nodes to update an entry in their ARP cache. + *  From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) + +err_t ethernet_input(struct pbuf *p, struct netif *netif); + +#if LWIP_AUTOIP +err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, +                 const struct eth_addr *ethdst_addr, +                 const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr, +                 const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr, +                 const u16_t opcode); +#endif /* LWIP_AUTOIP */ + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) + +extern const struct eth_addr ethbroadcast, ethzero; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ARP */ + +#endif /* __NETIF_ARP_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/loopif.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/loopif.h new file mode 100644 index 000000000..304af4b39 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/loopif.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __NETIF_LOOPIF_H__ +#define __NETIF_LOOPIF_H__ + +#include "lwip/opt.h" +#include "lwip/netif.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +#define loopif_poll netif_poll +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ + +err_t loopif_init(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* __NETIF_LOOPIF_H__ */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/ppp_oe.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/ppp_oe.h new file mode 100644 index 000000000..3aa55aec7 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/ppp_oe.h @@ -0,0 +1,161 @@ +/***************************************************************************** +* ppp_oe.h - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann <martin@NetBSD.org>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *        This product includes software developed by the NetBSD + *        Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + *    contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef PPP_OE_H +#define PPP_OE_H + +#include "lwip/opt.h" + +#if PPPOE_SUPPORT > 0 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoehdr { +	PACK_STRUCT_FIELD(u8_t vertype); +	PACK_STRUCT_FIELD(u8_t code); +	PACK_STRUCT_FIELD(u16_t session); +	PACK_STRUCT_FIELD(u16_t plen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoetag { +	PACK_STRUCT_FIELD(u16_t tag); +	PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + + +#define PPPOE_STATE_INITIAL	0 +#define PPPOE_STATE_PADI_SENT	1 +#define	PPPOE_STATE_PADR_SENT	2 +#define	PPPOE_STATE_SESSION	3 +#define	PPPOE_STATE_CLOSING	4 +/* passive */ +#define	PPPOE_STATE_PADO_SENT	1 + +#define PPPOE_HEADERLEN	sizeof(struct pppoehdr) +#define	PPPOE_VERTYPE	0x11	/* VER=1, TYPE = 1 */ + +#define	PPPOE_TAG_EOL		0x0000		/* end of list */ +#define	PPPOE_TAG_SNAME		0x0101		/* service name */ +#define	PPPOE_TAG_ACNAME	0x0102		/* access concentrator name */ +#define	PPPOE_TAG_HUNIQUE	0x0103		/* host unique */ +#define	PPPOE_TAG_ACCOOKIE	0x0104		/* AC cookie */ +#define	PPPOE_TAG_VENDOR	0x0105		/* vendor specific */ +#define	PPPOE_TAG_RELAYSID	0x0110		/* relay session id */ +#define	PPPOE_TAG_SNAME_ERR	0x0201		/* service name error */ +#define	PPPOE_TAG_ACSYS_ERR	0x0202		/* AC system error */ +#define	PPPOE_TAG_GENERIC_ERR	0x0203		/* gerneric error */ + +#define PPPOE_CODE_PADI		0x09		/* Active Discovery Initiation */ +#define	PPPOE_CODE_PADO		0x07		/* Active Discovery Offer */ +#define	PPPOE_CODE_PADR		0x19		/* Active Discovery Request */ +#define	PPPOE_CODE_PADS		0x65		/* Active Discovery Session confirmation */ +#define	PPPOE_CODE_PADT		0xA7		/* Active Discovery Terminate */ + +#ifndef ETHERMTU +#define ETHERMTU 1500 +#endif + +/* two byte PPP protocol discriminator, then IP data */ +#define	PPPOE_MAXMTU	(ETHERMTU-PPPOE_HEADERLEN-2) + +struct pppoe_softc; + + +void pppoe_init(void); + +err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr); +err_t pppoe_destroy(struct netif *ifp); + +int pppoe_connect(struct pppoe_softc *sc); +void pppoe_disconnect(struct pppoe_softc *sc); + +void pppoe_disc_input(struct netif *netif, struct pbuf *p); +void pppoe_data_input(struct netif *netif, struct pbuf *p); + +err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); + +extern int pppoe_hdrlen; + +#endif /* PPPOE_SUPPORT */ + +#endif /* PPP_OE_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/slipif.h b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/slipif.h new file mode 100644 index 000000000..aa08ada4a --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/include/netif/slipif.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved.  + * + * Redistribution and use in source and binary forms, with or without  + * modification, are permitted provided that the following conditions  + * are met:  + * 1. Redistributions of source code must retain the above copyright  + *    notice, this list of conditions and the following disclaimer.  + * 2. Redistributions in binary form must reproduce the above copyright  + *    notice, this list of conditions and the following disclaimer in the  + *    documentation and/or other materials provided with the distribution.  + * 3. Neither the name of the Institute nor the names of its contributors  + *    may be used to endorse or promote products derived from this software  + *    without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND  + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  + * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE  + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  + * SUCH DAMAGE.  + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __NETIF_SLIPIF_H__ +#define __NETIF_SLIPIF_H__ + +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +err_t slipif_init(struct netif * netif); + +#ifdef __cplusplus +} +#endif +  +#endif  + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/FILES b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/FILES new file mode 100644 index 000000000..1c4f5928d --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/FILES @@ -0,0 +1,25 @@ +This directory contains generic network interface device drivers that +do not contain any hardware or architecture specific code. The files +are: + +etharp.c +          Implements the ARP (Address Resolution Protocol) over +          Ethernet. The code in this file should be used together with +          Ethernet device drivers. Note that this module has been +          largely made Ethernet independent so you should be able to +          adapt this for other link layers (such as Firewire). + +ethernetif.c +          An example of how an Ethernet device driver could look. This +          file can be used as a "skeleton" for developing new Ethernet +          network device drivers. It uses the etharp.c ARP code. + +loopif.c +          A "loopback" network interface driver. It requires configuration +          through the define LWIP_LOOPIF_MULTITHREADING (see opt.h). + +slipif.c +          A generic implementation of the SLIP (Serial Line IP) +          protocol. It requires a sio (serial I/O) module to work. + +ppp/      Point-to-Point Protocol stack diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/etharp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/etharp.c new file mode 100644 index 000000000..73ea21173 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/etharp.c @@ -0,0 +1,1185 @@ +/** + * @file + * Address Resolution Protocol module for IP over Ethernet + * + * Functionally, ARP is divided into two parts. The first maps an IP address + * to a physical address when sending a packet, and the second part answers + * requests from other machines for our physical address. + * + * This implementation complies with RFC 826 (Ethernet ARP). It supports + * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 + * if an interface calls etharp_gratuitous(our_netif) upon address change. + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv> + * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ +  +#include "lwip/opt.h" + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/inet.h" +#include "lwip/ip.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "netif/etharp.h" + +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#endif /* PPPOE_SUPPORT */ + +#include <string.h> + +/** the time an ARP entry stays valid after its last update, + *  for ARP_TMR_INTERVAL = 5000, this is + *  (240 * 5) seconds = 20 minutes. + */ +#define ARP_MAXAGE 240 +/** the time an ARP entry stays pending after first request, + *  for ARP_TMR_INTERVAL = 5000, this is + *  (2 * 5) seconds = 10 seconds. + *  + *  @internal Keep this number at least 2, otherwise it might + *  run out instantly if the timeout occurs directly after a request. + */ +#define ARP_MAXPENDING 2 + +#define HWTYPE_ETHERNET 1 + +#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8) +#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff) + +#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8)) +#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8)) + +enum etharp_state { +  ETHARP_STATE_EMPTY = 0, +  ETHARP_STATE_PENDING, +  ETHARP_STATE_STABLE +}; + +struct etharp_entry { +#if ARP_QUEUEING +  /**  +   * Pointer to queue of pending outgoing packets on this ARP entry. +   */ +  struct etharp_q_entry *q; +#endif +  struct ip_addr ipaddr; +  struct eth_addr ethaddr; +  enum etharp_state state; +  u8_t ctime; +  struct netif *netif; +}; + +const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +const struct eth_addr ethzero = {{0,0,0,0,0,0}}; +static struct etharp_entry arp_table[ARP_TABLE_SIZE]; +#if !LWIP_NETIF_HWADDRHINT +static u8_t etharp_cached_entry; +#endif + +/** + * Try hard to create a new entry - we want the IP address to appear in + * the cache (even if this means removing an active entry or so). */ +#define ETHARP_TRY_HARD 1 +#define ETHARP_FIND_ONLY  2 + +#if LWIP_NETIF_HWADDRHINT +#define NETIF_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \ +                                      *((netif)->addr_hint) = (hint); +static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif); +#else /* LWIP_NETIF_HWADDRHINT */ +static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags); +#endif /* LWIP_NETIF_HWADDRHINT */ + +static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); + + +/* Some checks, instead of etharp_init(): */ +#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) +  #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h" +#endif + + +#if ARP_QUEUEING +/** + * Free a complete queue of etharp entries + * + * @param q a qeueue of etharp_q_entry's to free + */ +static void +free_etharp_q(struct etharp_q_entry *q) +{ +  struct etharp_q_entry *r; +  LWIP_ASSERT("q != NULL", q != NULL); +  LWIP_ASSERT("q->p != NULL", q->p != NULL); +  while (q) { +    r = q; +    q = q->next; +    LWIP_ASSERT("r->p != NULL", (r->p != NULL)); +    pbuf_free(r->p); +    memp_free(MEMP_ARP_QUEUE, r); +  } +} +#endif + +/** + * Clears expired entries in the ARP table. + * + * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds), + * in order to expire entries in the ARP table. + */ +void +etharp_tmr(void) +{ +  u8_t i; + +  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); +  /* remove expired entries from the ARP table */ +  for (i = 0; i < ARP_TABLE_SIZE; ++i) { +    arp_table[i].ctime++; +    if (((arp_table[i].state == ETHARP_STATE_STABLE) && +         (arp_table[i].ctime >= ARP_MAXAGE)) || +        ((arp_table[i].state == ETHARP_STATE_PENDING)  && +         (arp_table[i].ctime >= ARP_MAXPENDING))) { +         /* pending or stable entry has become old! */ +      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", +           arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); +      /* clean up entries that have just been expired */ +      /* remove from SNMP ARP index tree */ +      snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); +#if ARP_QUEUEING +      /* and empty packet queue */ +      if (arp_table[i].q != NULL) { +        /* remove all queued packets */ +        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); +        free_etharp_q(arp_table[i].q); +        arp_table[i].q = NULL; +      } +#endif +      /* recycle entry for re-use */       +      arp_table[i].state = ETHARP_STATE_EMPTY; +    } +#if ARP_QUEUEING +    /* still pending entry? (not expired) */ +    if (arp_table[i].state == ETHARP_STATE_PENDING) { +        /* resend an ARP query here? */ +    } +#endif +  } +} + +/** + * Search the ARP table for a matching or new entry. + *  + * If an IP address is given, return a pending or stable ARP entry that matches + * the address. If no match is found, create a new entry with this address set, + * but in state ETHARP_EMPTY. The caller must check and possibly change the + * state of the returned entry. + *  + * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. + *  + * In all cases, attempt to create new entries from an empty entry. If no + * empty entries are available and ETHARP_TRY_HARD flag is set, recycle + * old entries. Heuristic choose the least important entry for recycling. + * + * @param ipaddr IP address to find in ARP cache, or to add if not found. + * @param flags + * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of + * active (stable or pending) entries. + *   + * @return The ARP entry index that matched or is created, ERR_MEM if no + * entry is found or could be recycled. + */ +static s8_t +#if LWIP_NETIF_HWADDRHINT +find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif) +#else /* LWIP_NETIF_HWADDRHINT */ +find_entry(struct ip_addr *ipaddr, u8_t flags) +#endif /* LWIP_NETIF_HWADDRHINT */ +{ +  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; +  s8_t empty = ARP_TABLE_SIZE; +  u8_t i = 0, age_pending = 0, age_stable = 0; +#if ARP_QUEUEING +  /* oldest entry with packets on queue */ +  s8_t old_queue = ARP_TABLE_SIZE; +  /* its age */ +  u8_t age_queue = 0; +#endif + +  /* First, test if the last call to this function asked for the +   * same address. If so, we're really fast! */ +  if (ipaddr) { +    /* ipaddr to search for was given */ +#if LWIP_NETIF_HWADDRHINT +    if ((netif != NULL) && (netif->addr_hint != NULL)) { +      /* per-pcb cached entry was given */ +      u8_t per_pcb_cache = *(netif->addr_hint); +      if ((per_pcb_cache < ARP_TABLE_SIZE) && arp_table[per_pcb_cache].state == ETHARP_STATE_STABLE) { +        /* the per-pcb-cached entry is stable */ +        if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) { +          /* per-pcb cached entry was the right one! */ +          ETHARP_STATS_INC(etharp.cachehit); +          return per_pcb_cache; +        } +      } +    } +#else /* #if LWIP_NETIF_HWADDRHINT */ +    if (arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) { +      /* the cached entry is stable */ +      if (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr)) { +        /* cached entry was the right one! */ +        ETHARP_STATS_INC(etharp.cachehit); +        return etharp_cached_entry; +      } +    } +#endif /* #if LWIP_NETIF_HWADDRHINT */ +  } + +  /** +   * a) do a search through the cache, remember candidates +   * b) select candidate entry +   * c) create new entry +   */ + +  /* a) in a single search sweep, do all of this +   * 1) remember the first empty entry (if any) +   * 2) remember the oldest stable entry (if any) +   * 3) remember the oldest pending entry without queued packets (if any) +   * 4) remember the oldest pending entry with queued packets (if any) +   * 5) search for a matching IP entry, either pending or stable +   *    until 5 matches, or all entries are searched for. +   */ + +  for (i = 0; i < ARP_TABLE_SIZE; ++i) { +    /* no empty entry found yet and now we do find one? */ +    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) { +      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); +      /* remember first empty entry */ +      empty = i; +    } +    /* pending entry? */ +    else if (arp_table[i].state == ETHARP_STATE_PENDING) { +      /* if given, does IP address match IP address in ARP entry? */ +      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { +        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i)); +        /* found exact IP address match, simply bail out */ +#if LWIP_NETIF_HWADDRHINT +        NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ +        etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ +        return i; +#if ARP_QUEUEING +      /* pending with queued packets? */ +      } else if (arp_table[i].q != NULL) { +        if (arp_table[i].ctime >= age_queue) { +          old_queue = i; +          age_queue = arp_table[i].ctime; +        } +#endif +      /* pending without queued packets? */ +      } else { +        if (arp_table[i].ctime >= age_pending) { +          old_pending = i; +          age_pending = arp_table[i].ctime; +        } +      }         +    } +    /* stable entry? */ +    else if (arp_table[i].state == ETHARP_STATE_STABLE) { +      /* if given, does IP address match IP address in ARP entry? */ +      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { +        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i)); +        /* found exact IP address match, simply bail out */ +#if LWIP_NETIF_HWADDRHINT +        NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ +        etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ +        return i; +      /* remember entry with oldest stable entry in oldest, its age in maxtime */ +      } else if (arp_table[i].ctime >= age_stable) { +        old_stable = i; +        age_stable = arp_table[i].ctime; +      } +    } +  } +  /* { we have no match } => try to create a new entry */ +    +  /* no empty entry found and not allowed to recycle? */ +  if (((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0)) +      /* or don't create new entry, only search? */ +      || ((flags & ETHARP_FIND_ONLY) != 0)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); +    return (s8_t)ERR_MEM; +  } +   +  /* b) choose the least destructive entry to recycle: +   * 1) empty entry +   * 2) oldest stable entry +   * 3) oldest pending entry without queued packets +   * 4) oldest pending entry with queued packets +   *  +   * { ETHARP_TRY_HARD is set at this point } +   */  + +  /* 1) empty entry available? */ +  if (empty < ARP_TABLE_SIZE) { +    i = empty; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); +  } +  /* 2) found recyclable stable entry? */ +  else if (old_stable < ARP_TABLE_SIZE) { +    /* recycle oldest stable*/ +    i = old_stable; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); +#if ARP_QUEUEING +    /* no queued packets should exist on stable entries */ +    LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); +#endif +  /* 3) found recyclable pending entry without queued packets? */ +  } else if (old_pending < ARP_TABLE_SIZE) { +    /* recycle oldest pending */ +    i = old_pending; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); +#if ARP_QUEUEING +  /* 4) found recyclable pending entry with queued packets? */ +  } else if (old_queue < ARP_TABLE_SIZE) { +    /* recycle oldest pending */ +    i = old_queue; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); +    free_etharp_q(arp_table[i].q); +    arp_table[i].q = NULL; +#endif +    /* no empty or recyclable entries found */ +  } else { +    return (s8_t)ERR_MEM; +  } + +  /* { empty or recyclable entry found } */ +  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + +  if (arp_table[i].state != ETHARP_STATE_EMPTY) +  { +    snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); +  } +  /* recycle entry (no-op for an already empty entry) */ +  arp_table[i].state = ETHARP_STATE_EMPTY; + +  /* IP address given? */ +  if (ipaddr != NULL) { +    /* set IP address */ +    ip_addr_set(&arp_table[i].ipaddr, ipaddr); +  } +  arp_table[i].ctime = 0; +#if LWIP_NETIF_HWADDRHINT +  NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ +  etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ +  return (err_t)i; +} + +/** + * Send an IP packet on the network using netif->linkoutput + * The ethernet header is filled in before sending. + * + * @params netif the lwIP network interface on which to send the packet + * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header + * @params src the source MAC address to be copied into the ethernet header + * @params dst the destination MAC address to be copied into the ethernet header + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +static err_t +etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) +{ +  struct eth_hdr *ethhdr = p->payload; +  u8_t k; + +  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", +              (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +  k = ETHARP_HWADDR_LEN; +  while(k > 0) { +    k--; +    ethhdr->dest.addr[k] = dst->addr[k]; +    ethhdr->src.addr[k]  = src->addr[k]; +  } +  ethhdr->type = htons(ETHTYPE_IP); +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); +  /* send the packet */ +  return netif->linkoutput(netif, p); +} + +/** + * Update (or insert) a IP/MAC address pair in the ARP cache. + * + * If a pending entry is resolved, any queued packets will be sent + * at this point. + *  + * @param ipaddr IP address of the inserted ARP entry. + * @param ethaddr Ethernet address of the inserted ARP entry. + * @param flags Defines behaviour: + * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified, + * only existing ARP entries will be updated. + * + * @return + * - ERR_OK Succesfully updated ARP cache. + * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set. + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + * @see pbuf_free() + */ +static err_t +update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) +{ +  s8_t i; +  u8_t k; +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 3, ("update_arp_entry()\n")); +  LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", +                                        ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),  +                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], +                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); +  /* non-unicast address? */ +  if (ip_addr_isany(ipaddr) || +      ip_addr_isbroadcast(ipaddr, netif) || +      ip_addr_ismulticast(ipaddr)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); +    return ERR_ARG; +  } +  /* find or create ARP entry */ +#if LWIP_NETIF_HWADDRHINT +  i = find_entry(ipaddr, flags, netif); +#else /* LWIP_NETIF_HWADDRHINT */ +  i = find_entry(ipaddr, flags); +#endif /* LWIP_NETIF_HWADDRHINT */ +  /* bail out if no entry could be found */ +  if (i < 0) +    return (err_t)i; +   +  /* mark it stable */ +  arp_table[i].state = ETHARP_STATE_STABLE; +  /* record network interface */ +  arp_table[i].netif = netif; + +  /* insert in SNMP ARP index tree */ +  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); + +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); +  /* update address */ +  k = ETHARP_HWADDR_LEN; +  while (k > 0) { +    k--; +    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; +  } +  /* reset time stamp */ +  arp_table[i].ctime = 0; +#if ARP_QUEUEING +  /* this is where we will send out queued packets! */ +  while (arp_table[i].q != NULL) { +    struct pbuf *p; +    /* remember remainder of queue */ +    struct etharp_q_entry *q = arp_table[i].q; +    /* pop first item off the queue */ +    arp_table[i].q = q->next; +    /* get the packet pointer */ +    p = q->p; +    /* now queue entry can be freed */ +    memp_free(MEMP_ARP_QUEUE, q); +    /* send the queued IP packet */ +    etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); +    /* free the queued IP packet */ +    pbuf_free(p); +  } +#endif +  return ERR_OK; +} + +/** + * Finds (stable) ethernet/IP address pair from ARP table + * using interface and IP address index. + * @note the addresses in the ARP table are in network order! + * + * @param netif points to interface index + * @param ipaddr points to the (network order) IP address index + * @param eth_ret points to return pointer + * @param ip_ret points to return pointer + * @return table index if found, -1 otherwise + */ +s8_t +etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, +         struct eth_addr **eth_ret, struct ip_addr **ip_ret) +{ +  s8_t i; + +  LWIP_UNUSED_ARG(netif); + +#if LWIP_NETIF_HWADDRHINT +  i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL); +#else /* LWIP_NETIF_HWADDRHINT */ +  i = find_entry(ipaddr, ETHARP_FIND_ONLY); +#endif /* LWIP_NETIF_HWADDRHINT */ +  if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) { +      *eth_ret = &arp_table[i].ethaddr; +      *ip_ret = &arp_table[i].ipaddr; +      return i; +  } +  return -1; +} + +/** + * Updates the ARP table using the given IP packet. + * + * Uses the incoming IP packet's source address to update the + * ARP cache for the local network. The function does not alter + * or free the packet. This function must be called before the + * packet p is passed to the IP layer. + * + * @param netif The lwIP network interface on which the IP packet pbuf arrived. + * @param p The IP packet that arrived on netif. + * + * @return NULL + * + * @see pbuf_free() + */ +void +etharp_ip_input(struct netif *netif, struct pbuf *p) +{ +  struct ethip_hdr *hdr; +  LWIP_ERROR("netif != NULL", (netif != NULL), return;); +  /* Only insert an entry if the source IP address of the +     incoming IP packet comes from a host on the local network. */ +  hdr = p->payload; +  /* source is not on the local network? */ +  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { +    /* do nothing */ +    return; +  } + +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); +  /* update ARP table */ +  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk +   * back soon (for example, if the destination IP address is ours. */ +  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0); +} + + +/** + * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache   + * send out queued IP packets. Updates cache with snooped address pairs. + * + * Should be called for incoming ARP packets. The pbuf in the argument + * is freed by this function. + * + * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * @param ethaddr Ethernet address of netif. + * @param p The ARP packet that arrived on netif. Is freed by this function. + * + * @return NULL + * + * @see pbuf_free() + */ +void +etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) +{ +  struct etharp_hdr *hdr; +  /* these are aligned properly, whereas the ARP header fields might not be */ +  struct ip_addr sipaddr, dipaddr; +  u8_t i; +  u8_t for_us; +#if LWIP_AUTOIP +  const u8_t * ethdst_hwaddr; +#endif /* LWIP_AUTOIP */ + +  LWIP_ERROR("netif != NULL", (netif != NULL), return;); +   +  /* drop short ARP packets: we have to check for p->len instead of p->tot_len here +     since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ +  if (p->len < sizeof(struct etharp_hdr)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr))); +    ETHARP_STATS_INC(etharp.lenerr); +    ETHARP_STATS_INC(etharp.drop); +    pbuf_free(p); +    return; +  } + +  hdr = p->payload; + +  /* RFC 826 "Packet Reception": */ +  if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) || +      (hdr->_hwlen_protolen != htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr))) || +      (hdr->proto != htons(ETHTYPE_IP)) || +      (hdr->ethhdr.type != htons(ETHTYPE_ARP)))  { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1, +      ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", +      hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), hdr->ethhdr.type)); +    ETHARP_STATS_INC(etharp.proterr); +    ETHARP_STATS_INC(etharp.drop); +    pbuf_free(p); +    return; +  } +  ETHARP_STATS_INC(etharp.recv); + +#if LWIP_AUTOIP +  /* We have to check if a host already has configured our random +   * created link local address and continously check if there is +   * a host with this IP-address so we can detect collisions */ +  autoip_arp_reply(netif, hdr); +#endif /* LWIP_AUTOIP */ + +  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without +   * structure packing (not using structure copy which breaks strict-aliasing rules). */ +  SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); +  SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); + +  /* this interface is not configured? */ +  if (netif->ip_addr.addr == 0) { +    for_us = 0; +  } else { +    /* ARP packet directed to us? */ +    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr)); +  } + +  /* ARP message directed to us? */ +  if (for_us) { +    /* add IP address in ARP cache; assume requester wants to talk to us. +     * can result in directly sending the queued packets for this host. */ +    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD); +  /* ARP message not directed to us? */ +  } else { +    /* update the source IP address in the cache, if present */ +    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0); +  } + +  /* now act on the message itself */ +  switch (htons(hdr->opcode)) { +  /* ARP request? */ +  case ARP_REQUEST: +    /* ARP request. If it asked for our address, we send out a +     * reply. In any case, we time-stamp any existing ARP entry, +     * and possiby send out an IP packet that was queued on it. */ + +    LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); +    /* ARP request for our address? */ +    if (for_us) { + +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); +      /* Re-use pbuf to send ARP reply. +         Since we are re-using an existing pbuf, we can't call etharp_raw since +         that would allocate a new pbuf. */ +      hdr->opcode = htons(ARP_REPLY); + +      hdr->dipaddr = hdr->sipaddr; +      SMEMCPY(&hdr->sipaddr, &netif->ip_addr, sizeof(hdr->sipaddr)); + +      LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", +                  (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +      i = ETHARP_HWADDR_LEN; +#if LWIP_AUTOIP +      /* If we are using Link-Local, ARP packets must be broadcast on the +       * link layer. (See RFC3927 Section 2.5) */ +      ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; +#endif /* LWIP_AUTOIP */ + +      while(i > 0) { +        i--; +        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; +#if LWIP_AUTOIP +        hdr->ethhdr.dest.addr[i] = ethdst_hwaddr[i]; +#else  /* LWIP_AUTOIP */ +        hdr->ethhdr.dest.addr[i] = hdr->shwaddr.addr[i]; +#endif /* LWIP_AUTOIP */ +        hdr->shwaddr.addr[i] = ethaddr->addr[i]; +        hdr->ethhdr.src.addr[i] = ethaddr->addr[i]; +      } + +      /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header +         are already correct, we tested that before */ + +      /* return ARP reply */ +      netif->linkoutput(netif, p); +    /* we are not configured? */ +    } else if (netif->ip_addr.addr == 0) { +      /* { for_us == 0 and netif->ip_addr.addr == 0 } */ +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); +    /* request was not directed to us */ +    } else { +      /* { for_us == 0 and netif->ip_addr.addr != 0 } */ +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); +    } +    break; +  case ARP_REPLY: +    /* ARP reply. We already updated the ARP cache earlier. */ +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) +    /* DHCP wants to know about ARP replies from any host with an +     * IP address also offered to us by the DHCP server. We do not +     * want to take a duplicate IP address on a single network. +     * @todo How should we handle redundant (fail-over) interfaces? */ +    dhcp_arp_reply(netif, &sipaddr); +#endif +    break; +  default: +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); +    ETHARP_STATS_INC(etharp.err); +    break; +  } +  /* free ARP packet */ +  pbuf_free(p); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing IP packet. + * + * For IP multicast and broadcast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, the packet is submitted to etharp_query(). In + * case the IP address is outside the local network, the IP address of + * the gateway is used. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ipaddr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or etharp_send_ip(). + */ +err_t +etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr) +{ +  struct eth_addr *dest, mcastaddr; + +  /* make room for Ethernet header - should not fail */ +  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { +    /* bail out */ +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n")); +    LINK_STATS_INC(link.lenerr); +    return ERR_BUF; +  } + +  /* assume unresolved Ethernet address */ +  dest = NULL; +  /* Determine on destination hardware address. Broadcasts and multicasts +   * are special, other IP addresses are looked up in the ARP table. */ + +  /* broadcast destination IP address? */ +  if (ip_addr_isbroadcast(ipaddr, netif)) { +    /* broadcast on Ethernet also */ +    dest = (struct eth_addr *)ðbroadcast; +  /* multicast destination IP address? */ +  } else if (ip_addr_ismulticast(ipaddr)) { +    /* Hash IP multicast address to MAC address.*/ +    mcastaddr.addr[0] = 0x01; +    mcastaddr.addr[1] = 0x00; +    mcastaddr.addr[2] = 0x5e; +    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; +    mcastaddr.addr[4] = ip4_addr3(ipaddr); +    mcastaddr.addr[5] = ip4_addr4(ipaddr); +    /* destination Ethernet address is multicast */ +    dest = &mcastaddr; +  /* unicast destination IP address? */ +  } else { +    /* outside local network? */ +    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { +      /* interface has default gateway? */ +      if (netif->gw.addr != 0) { +        /* send to hardware address of default gateway IP address */ +        ipaddr = &(netif->gw); +      /* no default gateway available */ +      } else { +        /* no route to destination error (default gateway missing) */ +        return ERR_RTE; +      } +    } +    /* queue on destination Ethernet address belonging to ipaddr */ +    return etharp_query(netif, ipaddr, q); +  } + +  /* continuation for multicast/broadcast destinations */ +  /* obtain source Ethernet address of the given interface */ +  /* send packet directly on the link */ +  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); +} + +/** + * Send an ARP request for the given IP address and/or queue a packet. + * + * If the IP address was not yet in the cache, a pending ARP cache entry + * is added and an ARP request is sent for the given address. The packet + * is queued on this entry. + * + * If the IP address was already pending in the cache, a new ARP request + * is sent for the given address. The packet is queued on this entry. + * + * If the IP address was already stable in the cache, and a packet is + * given, it is directly sent and no ARP request is sent out.  + *  + * If the IP address was already stable in the cache, and no packet is + * given, an ARP request is sent out. + *  + * @param netif The lwIP network interface on which ipaddr + * must be queried for. + * @param ipaddr The IP address to be resolved. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. + * q is not freed by this function. + * + * @note q must only be ONE packet, not a packet queue! + * + * @return + * - ERR_BUF Could not make room for Ethernet header. + * - ERR_MEM Hardware address unknown, and no more ARP entries available + *   to query for address or queue the packet. + * - ERR_MEM Could not queue packet due to memory shortage. + * - ERR_RTE No route to destination (no gateway to external networks). + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + */ +err_t +etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) +{ +  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; +  err_t result = ERR_MEM; +  s8_t i; /* ARP entry index */ + +  /* non-unicast address? */ +  if (ip_addr_isbroadcast(ipaddr, netif) || +      ip_addr_ismulticast(ipaddr) || +      ip_addr_isany(ipaddr)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); +    return ERR_ARG; +  } + +  /* find entry in ARP cache, ask to create entry if queueing packet */ +#if LWIP_NETIF_HWADDRHINT +  i = find_entry(ipaddr, ETHARP_TRY_HARD, netif); +#else /* LWIP_NETIF_HWADDRHINT */ +  i = find_entry(ipaddr, ETHARP_TRY_HARD); +#endif /* LWIP_NETIF_HWADDRHINT */ + +  /* could not find or create entry? */ +  if (i < 0) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); +    if (q) { +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); +      ETHARP_STATS_INC(etharp.memerr); +    } +    return (err_t)i; +  } + +  /* mark a fresh entry as pending (we just sent a request) */ +  if (arp_table[i].state == ETHARP_STATE_EMPTY) { +    arp_table[i].state = ETHARP_STATE_PENDING; +  } + +  /* { i is either a STABLE or (new or existing) PENDING entry } */ +  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", +  ((arp_table[i].state == ETHARP_STATE_PENDING) || +   (arp_table[i].state == ETHARP_STATE_STABLE))); + +  /* do we have a pending entry? or an implicit query request? */ +  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { +    /* try to resolve it; send out ARP request */ +    result = etharp_request(netif, ipaddr); +    if (result != ERR_OK) { +      /* ARP request couldn't be sent */ +      /* We don't re-send arp request in etharp_tmr, but we still queue packets, +         since this failure could be temporary, and the next packet calling +         etharp_query again could lead to sending the queued packets. */ +    } +  } +   +  /* packet given? */ +  if (q != NULL) { +    /* stable entry? */ +    if (arp_table[i].state == ETHARP_STATE_STABLE) { +      /* we have a valid IP->Ethernet address mapping */ +      /* send the packet */ +      result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); +    /* pending entry? (either just created or already pending */ +    } else if (arp_table[i].state == ETHARP_STATE_PENDING) { +#if ARP_QUEUEING /* queue the given q packet */ +      struct pbuf *p; +      int copy_needed = 0; +      /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but +       * to copy the whole queue into a new PBUF_RAM (see bug #11400)  +       * PBUF_ROMs can be left as they are, since ROM must not get changed. */ +      p = q; +      while (p) { +        LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); +        if(p->type != PBUF_ROM) { +          copy_needed = 1; +          break; +        } +        p = p->next; +      } +      if(copy_needed) { +        /* copy the whole packet into new pbufs */ +        p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); +        if(p != NULL) { +          if (pbuf_copy(p, q) != ERR_OK) { +            pbuf_free(p); +            p = NULL; +          } +        } +      } else { +        /* referencing the old pbuf is enough */ +        p = q; +        pbuf_ref(p); +      } +      /* packet could be taken over? */ +      if (p != NULL) { +        /* queue packet ... */ +        struct etharp_q_entry *new_entry; +        /* allocate a new arp queue entry */ +        new_entry = memp_malloc(MEMP_ARP_QUEUE); +        if (new_entry != NULL) { +          new_entry->next = 0; +          new_entry->p = p; +          if(arp_table[i].q != NULL) { +            /* queue was already existent, append the new entry to the end */ +            struct etharp_q_entry *r; +            r = arp_table[i].q; +            while (r->next != NULL) { +              r = r->next; +            } +            r->next = new_entry; +          } else { +            /* queue did not exist, first item in queue */ +            arp_table[i].q = new_entry; +          } +          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); +          result = ERR_OK; +        } else { +          /* the pool MEMP_ARP_QUEUE is empty */ +          pbuf_free(p); +          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); +          /* { result == ERR_MEM } through initialization */ +        } +      } else { +        ETHARP_STATS_INC(etharp.memerr); +        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); +        /* { result == ERR_MEM } through initialization */ +      } +#else /* ARP_QUEUEING == 0 */ +      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */ +      /* { result == ERR_MEM } through initialization */ +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q)); +#endif +    } +  } +  return result; +} + +/** + * Send a raw ARP packet (opcode and all addresses can be modified) + * + * @param netif the lwip network interface on which to send the ARP packet + * @param ethsrc_addr the source MAC address for the ethernet header + * @param ethdst_addr the destination MAC address for the ethernet header + * @param hwsrc_addr the source MAC address for the ARP protocol header + * @param ipsrc_addr the source IP address for the ARP protocol header + * @param hwdst_addr the destination MAC address for the ARP protocol header + * @param ipdst_addr the destination IP address for the ARP protocol header + * @param opcode the type of the ARP packet + * @return ERR_OK if the ARP packet has been sent + *         ERR_MEM if the ARP packet couldn't be allocated + *         any other err_t on failure + */ +#if !LWIP_AUTOIP +static +#endif /* LWIP_AUTOIP */ +err_t +etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, +           const struct eth_addr *ethdst_addr, +           const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr, +           const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr, +           const u16_t opcode) +{ +  struct pbuf *p; +  err_t result = ERR_OK; +  u8_t k; /* ARP entry index */ +  struct etharp_hdr *hdr; +#if LWIP_AUTOIP +  const u8_t * ethdst_hwaddr; +#endif /* LWIP_AUTOIP */ + +  /* allocate a pbuf for the outgoing ARP request packet */ +  p = pbuf_alloc(PBUF_RAW, sizeof(struct etharp_hdr), PBUF_RAM); +  /* could allocate a pbuf for an ARP request? */ +  if (p == NULL) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n")); +    ETHARP_STATS_INC(etharp.memerr); +    return ERR_MEM; +  } +  LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", +              (p->len >= sizeof(struct etharp_hdr))); + +  hdr = p->payload; +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); +  hdr->opcode = htons(opcode); + +  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", +              (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +  k = ETHARP_HWADDR_LEN; +#if LWIP_AUTOIP +  /* If we are using Link-Local, ARP packets must be broadcast on the +   * link layer. (See RFC3927 Section 2.5) */ +  ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; +#endif /* LWIP_AUTOIP */ +  /* Write MAC-Addresses (combined loop for both headers) */ +  while(k > 0) { +    k--; +    /* Write the ARP MAC-Addresses */ +    hdr->shwaddr.addr[k] = hwsrc_addr->addr[k]; +    hdr->dhwaddr.addr[k] = hwdst_addr->addr[k]; +    /* Write the Ethernet MAC-Addresses */ +#if LWIP_AUTOIP +    hdr->ethhdr.dest.addr[k] = ethdst_hwaddr[k]; +#else  /* LWIP_AUTOIP */ +    hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k]; +#endif /* LWIP_AUTOIP */ +    hdr->ethhdr.src.addr[k]  = ethsrc_addr->addr[k]; +  } +  hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr; +  hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr; + +  hdr->hwtype = htons(HWTYPE_ETHERNET); +  hdr->proto = htons(ETHTYPE_IP); +  /* set hwlen and protolen together */ +  hdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr)); + +  hdr->ethhdr.type = htons(ETHTYPE_ARP); +  /* send ARP query */ +  result = netif->linkoutput(netif, p); +  ETHARP_STATS_INC(etharp.xmit); +  /* free ARP query packet */ +  pbuf_free(p); +  p = NULL; +  /* could not allocate pbuf for ARP request */ + +  return result; +} + +/** + * Send an ARP request packet asking for ipaddr. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @return ERR_OK if the request has been sent + *         ERR_MEM if the ARP packet couldn't be allocated + *         any other err_t on failure + */ +err_t +etharp_request(struct netif *netif, struct ip_addr *ipaddr) +{ +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); +  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, +                    (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, +                    ipaddr, ARP_REQUEST); +} + +/** + * Process received ethernet frames. Using this function instead of directly + * calling ip_input and passing ARP frames through etharp in ethernetif_input, + * the ARP cache is protected from concurrent access. + * + * @param p the recevied packet, p->payload pointing to the ethernet header + * @param netif the network interface on which the packet was received + */ +err_t +ethernet_input(struct pbuf *p, struct netif *netif) +{ +  struct eth_hdr* ethhdr; + +  /* points to packet payload, which starts with an Ethernet header */ +  ethhdr = p->payload; +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, +    ("ethernet_input: dest:%02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, type:%2hx\n", +     (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], +     (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], +     (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], +     (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], +     (unsigned)htons(ethhdr->type))); + +  switch (htons(ethhdr->type)) { +    /* IP packet? */ +    case ETHTYPE_IP: +#if ETHARP_TRUST_IP_MAC +      /* update ARP table */ +      etharp_ip_input(netif, p); +#endif /* ETHARP_TRUST_IP_MAC */ +      /* skip Ethernet header */ +      if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) { +        LWIP_ASSERT("Can't move over header in packet", 0); +        pbuf_free(p); +        p = NULL; +      } else { +        /* pass to IP layer */ +        ip_input(p, netif); +      } +      break; +       +    case ETHTYPE_ARP: +      /* pass p to ARP module */ +      etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); +      break; + +#if PPPOE_SUPPORT +    case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */ +      pppoe_disc_input(netif, p); +      break; + +    case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */ +      pppoe_data_input(netif, p); +      break; +#endif /* PPPOE_SUPPORT */ + +    default: +      ETHARP_STATS_INC(etharp.proterr); +      ETHARP_STATS_INC(etharp.drop); +      pbuf_free(p); +      p = NULL; +      break; +  } + +  /* This means the pbuf is freed or consumed, +     so the caller doesn't have to free it again */ +  return ERR_OK; +} +#endif /* LWIP_ARP */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ethernetif.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ethernetif.c new file mode 100644 index 000000000..ccd7bd67f --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ethernetif.c @@ -0,0 +1,313 @@ +/** + * @file + * Ethernet Interface Skeleton + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/opt.h" + +#if 0 /* don't build, this is only a skeleton, see previous comment */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include <lwip/stats.h> +#include <lwip/snmp.h> +#include "netif/etharp.h" +#include "netif/ppp_oe.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * Helper struct to hold private data used to operate your ethernet interface. + * Keeping the ethernet address of the MAC in this struct is not necessary + * as it is already kept in the struct netif. + * But this is only an example, anyway... + */ +struct ethernetif { +  struct eth_addr *ethaddr; +  /* Add whatever per-interface state that is needed here. */ +}; + +/* Forward declarations. */ +static void  ethernetif_input(struct netif *netif); + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + *        for this ethernetif + */ +static void +low_level_init(struct netif *netif) +{ +  struct ethernetif *ethernetif = netif->state; +   +  /* set MAC hardware address length */ +  netif->hwaddr_len = ETHARP_HWADDR_LEN; + +  /* set MAC hardware address */ +  netif->hwaddr[0] = ; +  ... +  netif->hwaddr[5] = ; + +  /* maximum transfer unit */ +  netif->mtu = 1500; +   +  /* device capabilities */ +  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ +  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; +  +  /* Do whatever else is needed to initialize interface. */   +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + *         an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + *       strange results. You might consider waiting for space in the DMA queue + *       to become availale since the stack doesn't retry to send a packet + *       dropped because of memory failure (except for the TCP timers). + */ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ +  struct ethernetif *ethernetif = netif->state; +  struct pbuf *q; + +  initiate transfer(); +   +#if ETH_PAD_SIZE +  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +  for(q = p; q != NULL; q = q->next) { +    /* Send the data from the pbuf to the interface, one pbuf at a +       time. The size of the data in each pbuf is kept in the ->len +       variable. */ +    send data from(q->payload, q->len); +  } + +  signal that packet should be sent(); + +#if ETH_PAD_SIZE +  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif +   +  LINK_STATS_INC(link.xmit); + +  return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + *         NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif) +{ +  struct ethernetif *ethernetif = netif->state; +  struct pbuf *p, *q; +  u16_t len; + +  /* Obtain the size of the packet and put it into the "len" +     variable. */ +  len = ; + +#if ETH_PAD_SIZE +  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + +  /* We allocate a pbuf chain of pbufs from the pool. */ +  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); +   +  if (p != NULL) { + +#if ETH_PAD_SIZE +    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +    /* We iterate over the pbuf chain until we have read the entire +     * packet into the pbuf. */ +    for(q = p; q != NULL; q = q->next) { +      /* Read enough bytes to fill this pbuf in the chain. The +       * available data in the pbuf is given by the q->len +       * variable. */ +      read data into(q->payload, q->len); +    } +    acknowledge that packet has been read(); + +#if ETH_PAD_SIZE +    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + +    LINK_STATS_INC(link.recv); +  } else { +    drop packet(); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +  } + +  return p;   +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +static void +ethernetif_input(struct netif *netif) +{ +  struct ethernetif *ethernetif; +  struct eth_hdr *ethhdr; +  struct pbuf *p; + +  ethernetif = netif->state; + +  /* move received packet into a new pbuf */ +  p = low_level_input(netif); +  /* no packet could be read, silently ignore this */ +  if (p == NULL) return; +  /* points to packet payload, which starts with an Ethernet header */ +  ethhdr = p->payload; + +  switch (htons(ethhdr->type)) { +  /* IP or ARP packet? */ +  case ETHTYPE_IP: +  case ETHTYPE_ARP: +#if PPPOE_SUPPORT +  /* PPPoE packet? */ +  case ETHTYPE_PPPOEDISC: +  case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ +    /* full packet send to tcpip_thread to process */ +    if (netif->input(p, netif)!=ERR_OK) +     { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); +       pbuf_free(p); +       p = NULL; +     } +    break; + +  default: +    pbuf_free(p); +    p = NULL; +    break; +  } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + *         ERR_MEM if private data couldn't be allocated + *         any other err_t on error + */ +err_t +ethernetif_init(struct netif *netif) +{ +  struct ethernetif *ethernetif; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +     +  ethernetif = mem_malloc(sizeof(struct ethernetif)); +  if (ethernetif == NULL) { +    LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); +    return ERR_MEM; +  } + +#if LWIP_NETIF_HOSTNAME +  /* Initialize interface hostname */ +  netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + +  /* +   * Initialize the snmp variables and counters inside the struct netif. +   * The last argument should be replaced with your link speed, in units +   * of bits per second. +   */ +  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + +  netif->state = ethernetif; +  netif->name[0] = IFNAME0; +  netif->name[1] = IFNAME1; +  /* We directly use etharp_output() here to save a function call. +   * You can instead declare your own function an call etharp_output() +   * from it if you have to do some checks before sending (e.g. if link +   * is available...) */ +  netif->output = etharp_output; +  netif->linkoutput = low_level_output; +   +  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); +   +  /* initialize the hardware */ +  low_level_init(netif); + +  return ERR_OK; +} + +#endif /* 0 */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/loopif.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/loopif.c new file mode 100644 index 000000000..1e1f28cf1 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/loopif.c @@ -0,0 +1,66 @@ +/** + * @file + * Loop Interface + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#include "lwip/opt.h" + +#if LWIP_HAVE_LOOPIF + +#include "netif/loopif.h" +#include "lwip/snmp.h" + +/** + * Initialize a lwip network interface structure for a loopback interface + * + * @param netif the lwip network interface structure for this loopif + * @return ERR_OK if the loopif is initialized + *         ERR_MEM if private data couldn't be allocated + */ +err_t +loopif_init(struct netif *netif) +{ +  /* initialize the snmp variables and counters inside the struct netif +   * ifSpeed: no assumption can be made! +   */ +  NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); + +  netif->name[0] = 'l'; +  netif->name[1] = 'o'; +  netif->output = netif_loop_output; +  return ERR_OK; +} + +#endif /* LWIP_HAVE_LOOPIF */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/auth.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/auth.c new file mode 100644 index 000000000..4c0ee6a8e --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/auth.c @@ -0,0 +1,988 @@ +/***************************************************************************** +* auth.c - Network Authentication and Phase Control program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Ported from public pppd code. +*****************************************************************************/ +/* + * auth.c - PPP authentication and phase control. + * + * Copyright (c) 1993 The Australian National University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Australian National University.  The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "fsm.h" +#include "lcp.h" +#include "pap.h" +#include "chap.h" +#include "auth.h" +#include "ipcp.h" + +#if CBCP_SUPPORT +#include "cbcp.h" +#endif /* CBCP_SUPPORT */ + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +/* Bits in auth_pending[] */ +#define PAP_WITHPEER    1 +#define PAP_PEER        2 +#define CHAP_WITHPEER   4 +#define CHAP_PEER       8 + + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ +/* Used for storing a sequence of words.  Usually malloced. */ +struct wordlist { +  struct wordlist *next; +  char        word[1]; +}; + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +extern char *crypt (const char *, const char *); + +/* Prototypes for procedures local to this file. */ + +static void network_phase (int); +static void check_idle (void *); +static void connect_time_expired (void *); +#if 0 +static int  login (char *, char *, char **, int *); +#endif +static void logout (void); +static int  null_login (int); +static int  get_pap_passwd (int, char *, char *); +static int  have_pap_secret (void); +static int  have_chap_secret (char *, char *, u32_t); +static int  ip_addr_check (u32_t, struct wordlist *); +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +static void set_allowed_addrs(int unit, struct wordlist *addrs); +static void free_wordlist (struct wordlist *); +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ +#if CBCP_SUPPORT +static void callback_phase (int); +#endif /* CBCP_SUPPORT */ + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +#if PAP_SUPPORT || CHAP_SUPPORT +/* The name by which the peer authenticated itself to us. */ +static char peer_authname[MAXNAMELEN]; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +/* Records which authentication operations haven't completed yet. */ +static int auth_pending[NUM_PPP]; + +/* Set if we have successfully called login() */ +static int logged_in; + +/* Set if we have run the /etc/ppp/auth-up script. */ +static int did_authup; + +/* List of addresses which the peer may use. */ +static struct wordlist *addresses[NUM_PPP]; + +/* Number of network protocols which we have opened. */ +static int num_np_open; + +/* Number of network protocols which have come up. */ +static int num_np_up; + +#if PAP_SUPPORT || CHAP_SUPPORT +/* Set if we got the contents of passwd[] from the pap-secrets file. */ +static int passwd_from_file; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * An Open on LCP has requested a change from Dead to Establish phase. + * Do what's necessary to bring the physical layer up. + */ +void +link_required(int unit) +{ +  LWIP_UNUSED_ARG(unit); + +  AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit)); +} + +/* + * LCP has terminated the link; go to the Dead phase and take the + * physical layer down. + */ +void +link_terminated(int unit) +{ +  AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit)); +  if (lcp_phase[unit] == PHASE_DEAD) { +    return; +  } +  if (logged_in) { +    logout(); +  } +  lcp_phase[unit] = PHASE_DEAD; +  AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n")); +  pppLinkTerminated(unit); +} + +/* + * LCP has gone down; it will either die or try to re-establish. + */ +void +link_down(int unit) +{ +  int i; +  struct protent *protp; +   +  AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit)); +  if (did_authup) { +    /* XXX Do link down processing. */ +    did_authup = 0; +  } +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (!protp->enabled_flag) { +      continue; +    } +    if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) { +      (*protp->lowerdown)(unit); +    } +    if (protp->protocol < 0xC000 && protp->close != NULL) { +      (*protp->close)(unit, "LCP down"); +    } +  } +  num_np_open = 0; +  num_np_up = 0; +  if (lcp_phase[unit] != PHASE_DEAD) { +    lcp_phase[unit] = PHASE_TERMINATE; +  } +  pppLinkDown(unit); +} + +/* + * The link is established. + * Proceed to the Dead, Authenticate or Network phase as appropriate. + */ +void +link_established(int unit) +{ +  int auth; +  int i; +  struct protent *protp; +  lcp_options *wo = &lcp_wantoptions[unit]; +  lcp_options *go = &lcp_gotoptions[unit]; +#if PAP_SUPPORT || CHAP_SUPPORT +  lcp_options *ho = &lcp_hisoptions[unit]; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +  AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit)); +  /* +   * Tell higher-level protocols that LCP is up. +   */ +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) { +      (*protp->lowerup)(unit); +    } +  } +  if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) { +    /* +     * We wanted the peer to authenticate itself, and it refused: +     * treat it as though it authenticated with PAP using a username +     * of "" and a password of "".  If that's not OK, boot it out. +     */ +    if (!wo->neg_upap || !null_login(unit)) { +      AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n")); +      lcp_close(unit, "peer refused to authenticate"); +      return; +    } +  } +     +  lcp_phase[unit] = PHASE_AUTHENTICATE; +  auth = 0; +#if CHAP_SUPPORT +  if (go->neg_chap) { +    ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype); +    auth |= CHAP_PEER; +  }  +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT && CHAP_SUPPORT +  else +#endif /* PAP_SUPPORT && CHAP_SUPPORT */ +#if PAP_SUPPORT +  if (go->neg_upap) { +    upap_authpeer(unit); +    auth |= PAP_PEER; +  } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +  if (ho->neg_chap) { +    ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype); +    auth |= CHAP_WITHPEER; +  } +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT && CHAP_SUPPORT +  else +#endif /* PAP_SUPPORT && CHAP_SUPPORT */ +#if PAP_SUPPORT +  if (ho->neg_upap) { +    if (ppp_settings.passwd[0] == 0) { +      passwd_from_file = 1; +      if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) { +        AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n")); +      } +    } +    upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd); +    auth |= PAP_WITHPEER; +  } +#endif /* PAP_SUPPORT */ +  auth_pending[unit] = auth; + +  if (!auth) { +    network_phase(unit); +  } +} + +/* + * The peer has failed to authenticate himself using `protocol'. + */ +void +auth_peer_fail(int unit, u16_t protocol) +{ +  LWIP_UNUSED_ARG(protocol); + +  AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol)); +  /* +   * Authentication failure: take the link down +   */ +  lcp_close(unit, "Authentication failed"); +} + + +#if PAP_SUPPORT || CHAP_SUPPORT +/* + * The peer has been successfully authenticated using `protocol'. + */ +void +auth_peer_success(int unit, u16_t protocol, char *name, int namelen) +{ +  int pbit; +   +  AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol)); +  switch (protocol) { +    case PPP_CHAP: +      pbit = CHAP_PEER; +      break; +    case PPP_PAP: +      pbit = PAP_PEER; +      break; +    default: +      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol)); +      return; +  } +   +  /* +   * Save the authenticated name of the peer for later. +   */ +  if (namelen > sizeof(peer_authname) - 1) { +    namelen = sizeof(peer_authname) - 1; +  } +  BCOPY(name, peer_authname, namelen); +  peer_authname[namelen] = 0; +   +  /* +   * If there is no more authentication still to be done, +   * proceed to the network (or callback) phase. +   */ +  if ((auth_pending[unit] &= ~pbit) == 0) { +    network_phase(unit); +  } +} + +/* + * We have failed to authenticate ourselves to the peer using `protocol'. + */ +void +auth_withpeer_fail(int unit, u16_t protocol) +{ +  int errCode = PPPERR_AUTHFAIL; +   +  LWIP_UNUSED_ARG(protocol); + +  AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol)); +  if (passwd_from_file) { +    BZERO(ppp_settings.passwd, MAXSECRETLEN); +  } +  /*  +   * XXX Warning: the unit number indicates the interface which is +   * not necessarily the PPP connection.  It works here as long +   * as we are only supporting PPP interfaces. +   */ +  pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode); + +  /* +   * We've failed to authenticate ourselves to our peer. +   * He'll probably take the link down, and there's not much +   * we can do except wait for that. +   */ +} + +/* + * We have successfully authenticated ourselves with the peer using `protocol'. + */ +void +auth_withpeer_success(int unit, u16_t protocol) +{ +  int pbit; +   +  AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol)); +  switch (protocol) { +    case PPP_CHAP: +      pbit = CHAP_WITHPEER; +      break; +    case PPP_PAP: +      if (passwd_from_file) { +        BZERO(ppp_settings.passwd, MAXSECRETLEN); +      } +      pbit = PAP_WITHPEER; +      break; +    default: +      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol)); +      pbit = 0; +  } +   +  /* +   * If there is no more authentication still being done, +   * proceed to the network (or callback) phase. +   */ +  if ((auth_pending[unit] &= ~pbit) == 0) { +    network_phase(unit); +  } +} +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + + +/* + * np_up - a network protocol has come up. + */ +void +np_up(int unit, u16_t proto) +{ +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(proto); + +  AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto)); +  if (num_np_up == 0) { +    AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit)); +    /* +     * At this point we consider that the link has come up successfully. +     */ +    if (ppp_settings.idle_time_limit > 0) { +      TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit); +    } +     +    /* +     * Set a timeout to close the connection once the maximum +     * connect time has expired. +     */ +    if (ppp_settings.maxconnect > 0) { +      TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect); +    } +  } +  ++num_np_up; +} + +/* + * np_down - a network protocol has gone down. + */ +void +np_down(int unit, u16_t proto) +{ +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(proto); + +  AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto)); +  if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) { +    UNTIMEOUT(check_idle, NULL); +  } +} + +/* + * np_finished - a network protocol has finished using the link. + */ +void +np_finished(int unit, u16_t proto) +{ +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(proto); + +  AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto)); +  if (--num_np_open <= 0) { +    /* no further use for the link: shut up shop. */ +    lcp_close(0, "No network protocols running"); +  } +} + +/* + * auth_reset - called when LCP is starting negotiations to recheck + * authentication options, i.e. whether we have appropriate secrets + * to use for authenticating ourselves and/or the peer. + */ +void +auth_reset(int unit) +{ +  lcp_options *go = &lcp_gotoptions[unit]; +  lcp_options *ao = &lcp_allowoptions[0]; +  ipcp_options *ipwo = &ipcp_wantoptions[0]; +  u32_t remote; + +  AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit)); +  ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL)); +  ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/; + +  if (go->neg_upap && !have_pap_secret()) { +    go->neg_upap = 0; +  } +  if (go->neg_chap) { +    remote = ipwo->accept_remote? 0: ipwo->hisaddr; +    if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote)) { +      go->neg_chap = 0; +    } +  } +} + +#if PAP_SUPPORT +/* + * check_passwd - Check the user name and passwd against the PAP secrets + * file.  If requested, also check against the system password database, + * and login the user if OK. + * + * returns: + *  UPAP_AUTHNAK: Authentication failed. + *  UPAP_AUTHACK: Authentication succeeded. + * In either case, msg points to an appropriate message. + */ +int +check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen) +{ +#if 1 +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(auser); +  LWIP_UNUSED_ARG(userlen); +  LWIP_UNUSED_ARG(apasswd); +  LWIP_UNUSED_ARG(passwdlen); +  LWIP_UNUSED_ARG(msglen); +  *msg = (char *) 0; +  return UPAP_AUTHACK;     /* XXX Assume all entries OK. */ +#else +  int ret = 0; +  struct wordlist *addrs = NULL; +  char passwd[256], user[256]; +  char secret[MAXWORDLEN]; +  static u_short attempts = 0; +   +  /* +   * Make copies of apasswd and auser, then null-terminate them. +   */ +  BCOPY(apasswd, passwd, passwdlen); +  passwd[passwdlen] = '\0'; +  BCOPY(auser, user, userlen); +  user[userlen] = '\0'; +  *msg = (char *) 0; + +  /* XXX Validate user name and password. */ +  ret = UPAP_AUTHACK;     /* XXX Assume all entries OK. */ +       +  if (ret == UPAP_AUTHNAK) { +    if (*msg == (char *) 0) { +      *msg = "Login incorrect"; +    } +    *msglen = strlen(*msg); +    /* +     * Frustrate passwd stealer programs. +     * Allow 10 tries, but start backing off after 3 (stolen from login). +     * On 10'th, drop the connection. +     */ +    if (attempts++ >= 10) { +      AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user)); +      /*ppp_panic("Excess Bad Logins");*/ +    } +    if (attempts > 3) { +      sys_msleep((attempts - 3) * 5); +    } +    if (addrs != NULL) { +      free_wordlist(addrs); +    } +  } else { +    attempts = 0; /* Reset count */ +    if (*msg == (char *) 0) { +      *msg = "Login ok"; +    } +    *msglen = strlen(*msg); +    set_allowed_addrs(unit, addrs); +  } + +  BZERO(passwd, sizeof(passwd)); +  BZERO(secret, sizeof(secret)); + +  return ret; +#endif +} +#endif /* PAP_SUPPORT */ + + +/* + * auth_ip_addr - check whether the peer is authorized to use + * a given IP address.  Returns 1 if authorized, 0 otherwise. + */ +int +auth_ip_addr(int unit, u32_t addr) +{ +  return ip_addr_check(addr, addresses[unit]); +} + +/* + * bad_ip_adrs - return 1 if the IP address is one we don't want + * to use, such as an address in the loopback net or a multicast address. + * addr is in network byte order. + */ +int +bad_ip_adrs(u32_t addr) +{ +  addr = ntohl(addr); +  return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET +      || IN_MULTICAST(addr) || IN_BADCLASS(addr); +} + + +#if CHAP_SUPPORT +/* + * get_secret - open the CHAP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int get_secret( int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs) +{ +#if 1 +  int len; +  struct wordlist *addrs; + +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(server); +  LWIP_UNUSED_ARG(save_addrs); + +  addrs = NULL; + +  if(!client || !client[0] || strcmp(client, ppp_settings.user)) { +    return 0; +  } + +  len = strlen(ppp_settings.passwd); +  if (len > MAXSECRETLEN) { +    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server)); +    len = MAXSECRETLEN; +  } + +  BCOPY(ppp_settings.passwd, secret, len); +  *secret_len = len; + +  return 1; +#else +  int ret = 0, len; +  struct wordlist *addrs; +  char secbuf[MAXWORDLEN]; +   +  addrs = NULL; +  secbuf[0] = 0; + +  /* XXX Find secret. */ +  if (ret < 0) { +    return 0; +  } + +  if (save_addrs) { +    set_allowed_addrs(unit, addrs); +  } + +  len = strlen(secbuf); +  if (len > MAXSECRETLEN) { +    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server)); +    len = MAXSECRETLEN; +  } + +  BCOPY(secbuf, secret, len); +  BZERO(secbuf, sizeof(secbuf)); +  *secret_len = len; + +  return 1; +#endif +} +#endif /* CHAP_SUPPORT */ + + +#if 0 /* UNUSED */ +/* + * auth_check_options - called to check authentication options. + */ +void +auth_check_options(void) +{ +  lcp_options *wo = &lcp_wantoptions[0]; +  int can_auth; +  ipcp_options *ipwo = &ipcp_wantoptions[0]; +  u32_t remote; + +  /* Default our_name to hostname, and user to our_name */ +  if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) { +      strcpy(ppp_settings.our_name, ppp_settings.hostname); +  } + +  if (ppp_settings.user[0] == 0) { +    strcpy(ppp_settings.user, ppp_settings.our_name); +  } + +  /* If authentication is required, ask peer for CHAP or PAP. */ +  if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) { +    wo->neg_chap = 1; +    wo->neg_upap = 1; +  } +   +  /* +   * Check whether we have appropriate secrets to use +   * to authenticate the peer. +   */ +  can_auth = wo->neg_upap && have_pap_secret(); +  if (!can_auth && wo->neg_chap) { +    remote = ipwo->accept_remote? 0: ipwo->hisaddr; +    can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote); +  } + +  if (ppp_settings.auth_required && !can_auth) { +    ppp_panic("No auth secret"); +  } +} +#endif + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * Proceed to the network phase. + */ +static void +network_phase(int unit) +{ +  int i; +  struct protent *protp; +  lcp_options *go = &lcp_gotoptions[unit]; +   +  /* +   * If the peer had to authenticate, run the auth-up script now. +   */ +  if ((go->neg_chap || go->neg_upap) && !did_authup) { +    /* XXX Do setup for peer authentication. */ +    did_authup = 1; +  } + +#if CBCP_SUPPORT +  /* +   * If we negotiated callback, do it now. +   */ +  if (go->neg_cbcp) { +    lcp_phase[unit] = PHASE_CALLBACK; +    (*cbcp_protent.open)(unit); +    return; +  } +#endif /* CBCP_SUPPORT */ + +  lcp_phase[unit] = PHASE_NETWORK; +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { +      (*protp->open)(unit); +      if (protp->protocol != PPP_CCP) { +        ++num_np_open; +      } +    } +  } + +  if (num_np_open == 0) { +    /* nothing to do */ +    lcp_close(0, "No network protocols running"); +  } +} + +/* + * check_idle - check whether the link has been idle for long + * enough that we can shut it down. + */ +static void +check_idle(void *arg) +{ +  struct ppp_idle idle; +  u_short itime; +   +  LWIP_UNUSED_ARG(arg); +  if (!get_idle_time(0, &idle)) { +    return; +  } +  itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); +  if (itime >= ppp_settings.idle_time_limit) { +    /* link is idle: shut it down. */ +    AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n")); +    lcp_close(0, "Link inactive"); +  } else { +    TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime); +  } +} + +/* + * connect_time_expired - log a message and close the connection. + */ +static void +connect_time_expired(void *arg) +{ +  LWIP_UNUSED_ARG(arg); + +  AUTHDEBUG((LOG_INFO, "Connect time expired\n")); +  lcp_close(0, "Connect time expired");   /* Close connection */ +} + +#if 0 +/* + * login - Check the user name and password against the system + * password database, and login the user if OK. + * + * returns: + *  UPAP_AUTHNAK: Login failed. + *  UPAP_AUTHACK: Login succeeded. + * In either case, msg points to an appropriate message. + */ +static int +login(char *user, char *passwd, char **msg, int *msglen) +{ +  /* XXX Fail until we decide that we want to support logins. */ +  return (UPAP_AUTHNAK); +} +#endif + +/* + * logout - Logout the user. + */ +static void +logout(void) +{ +  logged_in = 0; +} + +/* + * null_login - Check if a username of "" and a password of "" are + * acceptable, and iff so, set the list of acceptable IP addresses + * and return 1. + */ +static int +null_login(int unit) +{ +  LWIP_UNUSED_ARG(unit); +  /* XXX Fail until we decide that we want to support logins. */ +  return 0; +} + +/* + * get_pap_passwd - get a password for authenticating ourselves with + * our peer using PAP.  Returns 1 on success, 0 if no suitable password + * could be found. + */ +static int +get_pap_passwd(int unit, char *user, char *passwd) +{ +  LWIP_UNUSED_ARG(unit); +/* normally we would reject PAP if no password is provided, +   but this causes problems with some providers (like CHT in Taiwan) +   who incorrectly request PAP and expect a bogus/empty password, so +   always provide a default user/passwd of "none"/"none" +*/ +  if(user) { +    strcpy(user, "none"); +  } +  if(passwd) { +    strcpy(passwd, "none"); +  } +  return 1; +} + +/* + * have_pap_secret - check whether we have a PAP file with any + * secrets that we could possibly use for authenticating the peer. + */ +static int +have_pap_secret(void) +{ +  /* XXX Fail until we set up our passwords. */ +  return 0; +} + +/* + * have_chap_secret - check whether we have a CHAP file with a + * secret that we could possibly use for authenticating `client' + * on `server'.  Either can be the null string, meaning we don't + * know the identity yet. + */ +static int +have_chap_secret(char *client, char *server, u32_t remote) +{ +  LWIP_UNUSED_ARG(client); +  LWIP_UNUSED_ARG(server); +  LWIP_UNUSED_ARG(remote); +  /* XXX Fail until we set up our passwords. */ +  return 0; +} + +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * set_allowed_addrs() - set the list of allowed addresses. + */ +static void +set_allowed_addrs(int unit, struct wordlist *addrs) +{ +  if (addresses[unit] != NULL) { +    free_wordlist(addresses[unit]); +  } +  addresses[unit] = addrs; + +#if 0 +  /* +   * If there's only one authorized address we might as well +   * ask our peer for that one right away +   */ +  if (addrs != NULL && addrs->next == NULL) { +    char *p = addrs->word; +    struct ipcp_options *wo = &ipcp_wantoptions[unit]; +    u32_t a; +    struct hostent *hp; +     +    if (wo->hisaddr == 0 && *p != '!' && *p != '-' && strchr(p, '/') == NULL) { +      hp = gethostbyname(p); +      if (hp != NULL && hp->h_addrtype == AF_INET) { +        a = *(u32_t *)hp->h_addr; +      } else { +        a = inet_addr(p); +      } +      if (a != (u32_t) -1) { +        wo->hisaddr = a; +      } +    } +  } +#endif +} +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ + +static int +ip_addr_check(u32_t addr, struct wordlist *addrs) +{ +  /* don't allow loopback or multicast address */ +  if (bad_ip_adrs(addr)) { +    return 0; +  } + +  if (addrs == NULL) { +    return !ppp_settings.auth_required; /* no addresses authorized */ +  } + +  /* XXX All other addresses allowed. */ +  return 1; +} + +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * free_wordlist - release memory allocated for a wordlist. + */ +static void +free_wordlist(struct wordlist *wp) +{ +  struct wordlist *next; +   +  while (wp != NULL) { +    next = wp->next; +    free(wp); +    wp = next; +  } +} +#endif  /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/auth.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/auth.h new file mode 100644 index 000000000..86ff04945 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/auth.h @@ -0,0 +1,111 @@ +/***************************************************************************** +* auth.h -  PPP Authentication and phase control header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original derived from BSD pppd.h. +*****************************************************************************/ +/* + * pppd.h - PPP daemon global declarations. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef AUTH_H +#define AUTH_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* we are starting to use the link */ +void link_required (int); + +/* we are finished with the link */ +void link_terminated (int); + +/* the LCP layer has left the Opened state */ +void link_down (int); + +/* the link is up; authenticate now */ +void link_established (int); + +/* a network protocol has come up */ +void np_up (int, u16_t); + +/* a network protocol has gone down */ +void np_down (int, u16_t); + +/* a network protocol no longer needs link */ +void np_finished (int, u16_t); + +/* peer failed to authenticate itself */ +void auth_peer_fail (int, u16_t); + +/* peer successfully authenticated itself */ +void auth_peer_success (int, u16_t, char *, int); + +/* we failed to authenticate ourselves */ +void auth_withpeer_fail (int, u16_t); + +/* we successfully authenticated ourselves */ +void auth_withpeer_success (int, u16_t); + +/* check authentication options supplied */ +void auth_check_options (void); + +/* check what secrets we have */ +void auth_reset (int); + +/* Check peer-supplied username/password */ +int  check_passwd (int, char *, int, char *, int, char **, int *); + +/* get "secret" for chap */ +int  get_secret (int, char *, char *, char *, int *, int); + +/* check if IP address is authorized */ +int  auth_ip_addr (int, u32_t); + +/* check if IP address is unreasonable */ +int  bad_ip_adrs (u32_t); + +#endif /* AUTH_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chap.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chap.c new file mode 100644 index 000000000..6d9c3c3ce --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chap.c @@ -0,0 +1,902 @@ +/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/ +/***************************************************************************** +* chap.c - Network Challenge Handshake Authentication Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD chap.c. +*****************************************************************************/ +/* + * chap.c - Challenge Handshake Authentication Protocol. + * + * Copyright (c) 1993 The Australian National University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Australian National University.  The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1991 Gregory M. Christy. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Gregory M. Christy.  The name of the author may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT  /* don't build if not configured for use in lwipopts.h */ + +#if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "magic.h" +#include "randm.h" +#include "auth.h" +#include "md5.h" +#include "chap.h" +#include "chpms.h" + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Protocol entry points. + */ +static void ChapInit (int); +static void ChapLowerUp (int); +static void ChapLowerDown (int); +static void ChapInput (int, u_char *, int); +static void ChapProtocolReject (int); +#if 0 +static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *); +#endif + +static void ChapChallengeTimeout (void *); +static void ChapResponseTimeout (void *); +static void ChapReceiveChallenge (chap_state *, u_char *, int, int); +static void ChapRechallenge (void *); +static void ChapReceiveResponse (chap_state *, u_char *, int, int); +static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapSendStatus (chap_state *, int); +static void ChapSendChallenge (chap_state *); +static void ChapSendResponse (chap_state *); +static void ChapGenChallenge (chap_state *); + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ + +struct protent chap_protent = { +  PPP_CHAP, +  ChapInit, +  ChapInput, +  ChapProtocolReject, +  ChapLowerUp, +  ChapLowerDown, +  NULL, +  NULL, +#if 0 +  ChapPrintPkt, +  NULL, +#endif +  1, +  "CHAP", +#if 0 +  NULL, +  NULL, +  NULL +#endif +}; + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * ChapAuthWithPeer - Authenticate us with our peer (start client). + * + */ +void +ChapAuthWithPeer(int unit, char *our_name, int digest) +{ +  chap_state *cstate = &chap[unit]; + +  cstate->resp_name = our_name; +  cstate->resp_type = digest; + +  if (cstate->clientstate == CHAPCS_INITIAL || +      cstate->clientstate == CHAPCS_PENDING) { +    /* lower layer isn't up - wait until later */ +    cstate->clientstate = CHAPCS_PENDING; +    return; +  } + +  /* +   * We get here as a result of LCP coming up. +   * So even if CHAP was open before, we will  +   * have to re-authenticate ourselves. +   */ +  cstate->clientstate = CHAPCS_LISTEN; +} + + +/* + * ChapAuthPeer - Authenticate our peer (start server). + */ +void +ChapAuthPeer(int unit, char *our_name, int digest) +{ +  chap_state *cstate = &chap[unit]; + +  cstate->chal_name = our_name; +  cstate->chal_type = digest; +   +  if (cstate->serverstate == CHAPSS_INITIAL || +      cstate->serverstate == CHAPSS_PENDING) { +    /* lower layer isn't up - wait until later */ +    cstate->serverstate = CHAPSS_PENDING; +    return; +  } + +  ChapGenChallenge(cstate); +  ChapSendChallenge(cstate);    /* crank it up dude! */ +  cstate->serverstate = CHAPSS_INITIAL_CHAL; +} + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * ChapInit - Initialize a CHAP unit. + */ +static void +ChapInit(int unit) +{ +  chap_state *cstate = &chap[unit]; + +  BZERO(cstate, sizeof(*cstate)); +  cstate->unit = unit; +  cstate->clientstate = CHAPCS_INITIAL; +  cstate->serverstate = CHAPSS_INITIAL; +  cstate->timeouttime = CHAP_DEFTIMEOUT; +  cstate->max_transmits = CHAP_DEFTRANSMITS; +  /* random number generator is initialized in magic_init */ +} + + +/* + * ChapChallengeTimeout - Timeout expired on sending challenge. + */ +static void +ChapChallengeTimeout(void *arg) +{ +  chap_state *cstate = (chap_state *) arg; + +  /* if we aren't sending challenges, don't worry.  then again we */ +  /* probably shouldn't be here either */ +  if (cstate->serverstate != CHAPSS_INITIAL_CHAL && +      cstate->serverstate != CHAPSS_RECHALLENGE) { +    return; +  } + +  if (cstate->chal_transmits >= cstate->max_transmits) { +    /* give up on peer */ +    CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n")); +    cstate->serverstate = CHAPSS_BADAUTH; +    auth_peer_fail(cstate->unit, PPP_CHAP); +    return; +  } + +  ChapSendChallenge(cstate); /* Re-send challenge */ +} + + +/* + * ChapResponseTimeout - Timeout expired on sending response. + */ +static void +ChapResponseTimeout(void *arg) +{ +  chap_state *cstate = (chap_state *) arg; + +  /* if we aren't sending a response, don't worry. */ +  if (cstate->clientstate != CHAPCS_RESPONSE) { +    return; +  } + +  ChapSendResponse(cstate);    /* re-send response */ +} + + +/* + * ChapRechallenge - Time to challenge the peer again. + */ +static void +ChapRechallenge(void *arg) +{ +  chap_state *cstate = (chap_state *) arg; +   +  /* if we aren't sending a response, don't worry. */ +  if (cstate->serverstate != CHAPSS_OPEN) { +    return; +  } + +  ChapGenChallenge(cstate); +  ChapSendChallenge(cstate); +  cstate->serverstate = CHAPSS_RECHALLENGE; +} + + +/* + * ChapLowerUp - The lower layer is up. + * + * Start up if we have pending requests. + */ +static void +ChapLowerUp(int unit) +{ +  chap_state *cstate = &chap[unit]; + +  if (cstate->clientstate == CHAPCS_INITIAL) { +    cstate->clientstate = CHAPCS_CLOSED; +  } else if (cstate->clientstate == CHAPCS_PENDING) { +    cstate->clientstate = CHAPCS_LISTEN; +  } + +  if (cstate->serverstate == CHAPSS_INITIAL) { +    cstate->serverstate = CHAPSS_CLOSED; +  } else if (cstate->serverstate == CHAPSS_PENDING) { +    ChapGenChallenge(cstate); +    ChapSendChallenge(cstate); +    cstate->serverstate = CHAPSS_INITIAL_CHAL; +  } +} + + +/* + * ChapLowerDown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void +ChapLowerDown(int unit) +{ +  chap_state *cstate = &chap[unit]; + +  /* Timeout(s) pending?  Cancel if so. */ +  if (cstate->serverstate == CHAPSS_INITIAL_CHAL || +      cstate->serverstate == CHAPSS_RECHALLENGE) { +    UNTIMEOUT(ChapChallengeTimeout, cstate); +  } else if (cstate->serverstate == CHAPSS_OPEN +      && cstate->chal_interval != 0) { +    UNTIMEOUT(ChapRechallenge, cstate); +  } +  if (cstate->clientstate == CHAPCS_RESPONSE) { +    UNTIMEOUT(ChapResponseTimeout, cstate); +  } +  cstate->clientstate = CHAPCS_INITIAL; +  cstate->serverstate = CHAPSS_INITIAL; +} + + +/* + * ChapProtocolReject - Peer doesn't grok CHAP. + */ +static void +ChapProtocolReject(int unit) +{ +  chap_state *cstate = &chap[unit]; +   +  if (cstate->serverstate != CHAPSS_INITIAL && +      cstate->serverstate != CHAPSS_CLOSED) { +    auth_peer_fail(unit, PPP_CHAP); +  } +  if (cstate->clientstate != CHAPCS_INITIAL && +      cstate->clientstate != CHAPCS_CLOSED) { +    auth_withpeer_fail(unit, PPP_CHAP); +  } +  ChapLowerDown(unit); /* shutdown chap */ +} + + +/* + * ChapInput - Input CHAP packet. + */ +static void +ChapInput(int unit, u_char *inpacket, int packet_len) +{ +  chap_state *cstate = &chap[unit]; +  u_char *inp; +  u_char code, id; +  int len; +   +  /* +   * Parse header (code, id and length). +   * If packet too short, drop it. +   */ +  inp = inpacket; +  if (packet_len < CHAP_HEADERLEN) { +    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n")); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  GETSHORT(len, inp); +  if (len < CHAP_HEADERLEN) { +    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n")); +    return; +  } +  if (len > packet_len) { +    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n")); +    return; +  } +  len -= CHAP_HEADERLEN; +   +  /* +   * Action depends on code (as in fact it usually does :-). +   */ +  switch (code) { +    case CHAP_CHALLENGE: +      ChapReceiveChallenge(cstate, inp, id, len); +      break; +     +    case CHAP_RESPONSE: +      ChapReceiveResponse(cstate, inp, id, len); +      break; +     +    case CHAP_FAILURE: +      ChapReceiveFailure(cstate, inp, id, len); +      break; +     +    case CHAP_SUCCESS: +      ChapReceiveSuccess(cstate, inp, id, len); +      break; +     +    default:        /* Need code reject? */ +      CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code)); +      break; +  } +} + + +/* + * ChapReceiveChallenge - Receive Challenge and send Response. + */ +static void +ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len) +{ +  int rchallenge_len; +  u_char *rchallenge; +  int secret_len; +  char secret[MAXSECRETLEN]; +  char rhostname[256]; +  MD5_CTX mdContext; +  u_char hash[MD5_SIGNATURE_SIZE]; +   +  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id)); +  if (cstate->clientstate == CHAPCS_CLOSED || +    cstate->clientstate == CHAPCS_PENDING) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n", +         cstate->clientstate)); +    return; +  } + +  if (len < 2) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n")); +    return; +  } + +  GETCHAR(rchallenge_len, inp); +  len -= sizeof (u_char) + rchallenge_len;  /* now name field length */ +  if (len < 0) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n")); +    return; +  } +  rchallenge = inp; +  INCPTR(rchallenge_len, inp); + +  if (len >= sizeof(rhostname)) { +    len = sizeof(rhostname) - 1; +  } +  BCOPY(inp, rhostname, len); +  rhostname[len] = '\000'; + +  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname)); + +  /* Microsoft doesn't send their name back in the PPP packet */ +  if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) { +    strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname)); +    rhostname[sizeof(rhostname) - 1] = 0; +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname)); +  } + +  /* get secret for authenticating ourselves with the specified host */ +  if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) { +    secret_len = 0;    /* assume null secret if can't find one */ +    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname)); +  } + +  /* cancel response send timeout if necessary */ +  if (cstate->clientstate == CHAPCS_RESPONSE) { +    UNTIMEOUT(ChapResponseTimeout, cstate); +  } + +  cstate->resp_id = id; +  cstate->resp_transmits = 0; + +  /*  generate MD based on negotiated type */ +  switch (cstate->resp_type) {  + +  case CHAP_DIGEST_MD5: +    MD5Init(&mdContext); +    MD5Update(&mdContext, &cstate->resp_id, 1); +    MD5Update(&mdContext, (u_char*)secret, secret_len); +    MD5Update(&mdContext, rchallenge, rchallenge_len); +    MD5Final(hash, &mdContext); +    BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE); +    cstate->resp_length = MD5_SIGNATURE_SIZE; +    break; +   +#ifdef CHAPMS +  case CHAP_MICROSOFT: +    ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len); +    break; +#endif + +  default: +    CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type)); +    return; +  } + +  BZERO(secret, sizeof(secret)); +  ChapSendResponse(cstate); +} + + +/* + * ChapReceiveResponse - Receive and process response. + */ +static void +ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) +{ +  u_char *remmd, remmd_len; +  int secret_len, old_state; +  int code; +  char rhostname[256]; +  MD5_CTX mdContext; +  char secret[MAXSECRETLEN]; +  u_char hash[MD5_SIGNATURE_SIZE]; +   +  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id)); +   +  if (cstate->serverstate == CHAPSS_CLOSED || +      cstate->serverstate == CHAPSS_PENDING) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n", +    cstate->serverstate)); +    return; +  } + +  if (id != cstate->chal_id) { +    return;      /* doesn't match ID of last challenge */ +  } + +  /* +  * If we have received a duplicate or bogus Response, +  * we have to send the same answer (Success/Failure) +  * as we did for the first Response we saw. +  */ +  if (cstate->serverstate == CHAPSS_OPEN) { +    ChapSendStatus(cstate, CHAP_SUCCESS); +    return; +  } +  if (cstate->serverstate == CHAPSS_BADAUTH) { +    ChapSendStatus(cstate, CHAP_FAILURE); +    return; +  } +   +  if (len < 2) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n")); +    return; +  } +  GETCHAR(remmd_len, inp); /* get length of MD */ +  remmd = inp;             /* get pointer to MD */ +  INCPTR(remmd_len, inp); +   +  len -= sizeof (u_char) + remmd_len; +  if (len < 0) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n")); +    return; +  } + +  UNTIMEOUT(ChapChallengeTimeout, cstate); +   +  if (len >= sizeof(rhostname)) { +    len = sizeof(rhostname) - 1; +  } +  BCOPY(inp, rhostname, len); +  rhostname[len] = '\000'; + +  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", rhostname)); + +  /* +  * Get secret for authenticating them with us, +  * do the hash ourselves, and compare the result. +  */ +  code = CHAP_FAILURE; +  if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) { +    /* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */ +    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n", +    rhostname)); +  } else { +    /*  generate MD based on negotiated type */ +    switch (cstate->chal_type) { + +      case CHAP_DIGEST_MD5:    /* only MD5 is defined for now */ +        if (remmd_len != MD5_SIGNATURE_SIZE) { +          break;      /* it's not even the right length */ +        } +        MD5Init(&mdContext); +        MD5Update(&mdContext, &cstate->chal_id, 1); +        MD5Update(&mdContext, (u_char*)secret, secret_len); +        MD5Update(&mdContext, cstate->challenge, cstate->chal_len); +        MD5Final(hash, &mdContext);  +         +        /* compare local and remote MDs and send the appropriate status */ +        if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) { +          code = CHAP_SUCCESS;  /* they are the same! */ +        } +        break; +       +      default: +        CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type)); +    } +  } +   +  BZERO(secret, sizeof(secret)); +  ChapSendStatus(cstate, code); + +  if (code == CHAP_SUCCESS) { +    old_state = cstate->serverstate; +    cstate->serverstate = CHAPSS_OPEN; +    if (old_state == CHAPSS_INITIAL_CHAL) { +      auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len); +    } +    if (cstate->chal_interval != 0) { +      TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval); +    } +  } else { +    CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n")); +    cstate->serverstate = CHAPSS_BADAUTH; +    auth_peer_fail(cstate->unit, PPP_CHAP); +  } +} + +/* + * ChapReceiveSuccess - Receive Success + */ +static void +ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len) +{ +  LWIP_UNUSED_ARG(id); +  LWIP_UNUSED_ARG(inp); + +  CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id)); + +  if (cstate->clientstate == CHAPCS_OPEN) { +    /* presumably an answer to a duplicate response */ +    return; +  } + +  if (cstate->clientstate != CHAPCS_RESPONSE) { +    /* don't know what this is */ +    CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate)); +    return; +  } +   +  UNTIMEOUT(ChapResponseTimeout, cstate); +   +  /* +   * Print message. +   */ +  if (len > 0) { +    PRINTMSG(inp, len); +  } + +  cstate->clientstate = CHAPCS_OPEN; + +  auth_withpeer_success(cstate->unit, PPP_CHAP); +} + + +/* + * ChapReceiveFailure - Receive failure. + */ +static void +ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len) +{ +  LWIP_UNUSED_ARG(id); +  LWIP_UNUSED_ARG(inp); + +  CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id)); + +  if (cstate->clientstate != CHAPCS_RESPONSE) { +    /* don't know what this is */ +    CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate)); +    return; +  } + +  UNTIMEOUT(ChapResponseTimeout, cstate); + +  /* +   * Print message. +   */ +  if (len > 0) { +    PRINTMSG(inp, len); +  } + +  CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n")); +  auth_withpeer_fail(cstate->unit, PPP_CHAP); +} + + +/* + * ChapSendChallenge - Send an Authenticate challenge. + */ +static void +ChapSendChallenge(chap_state *cstate) +{ +  u_char *outp; +  int chal_len, name_len; +  int outlen; +   +  chal_len = cstate->chal_len; +  name_len = strlen(cstate->chal_name); +  outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; +  outp = outpacket_buf[cstate->unit]; +   +  MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */ +   +  PUTCHAR(CHAP_CHALLENGE, outp); +  PUTCHAR(cstate->chal_id, outp); +  PUTSHORT(outlen, outp); +   +  PUTCHAR(chal_len, outp);    /* put length of challenge */ +  BCOPY(cstate->challenge, outp, chal_len); +  INCPTR(chal_len, outp); +   +  BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */ +   +  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); +   +  CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id)); +   +  TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime); +  ++cstate->chal_transmits; +} + + +/* + * ChapSendStatus - Send a status response (ack or nak). + */ +static void +ChapSendStatus(chap_state *cstate, int code) +{ +  u_char *outp; +  int outlen, msglen; +  char msg[256]; +   +  if (code == CHAP_SUCCESS) { +    strcpy(msg, "Welcome!"); +  } else { +    strcpy(msg, "I don't like you.  Go 'way."); +  } +  msglen = strlen(msg); +   +  outlen = CHAP_HEADERLEN + msglen; +  outp = outpacket_buf[cstate->unit]; +   +  MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */ +   +  PUTCHAR(code, outp); +  PUTCHAR(cstate->chal_id, outp); +  PUTSHORT(outlen, outp); +  BCOPY(msg, outp, msglen); +  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); +   +  CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id)); +} + +/* + * ChapGenChallenge is used to generate a pseudo-random challenge string of + * a pseudo-random length between min_len and max_len.  The challenge + * string and its length are stored in *cstate, and various other fields of + * *cstate are initialized. + */ + +static void +ChapGenChallenge(chap_state *cstate) +{ +  int chal_len; +  u_char *ptr = cstate->challenge; +  int i; +   +  /* pick a random challenge length between MIN_CHALLENGE_LENGTH and  +     MAX_CHALLENGE_LENGTH */   +  chal_len = (unsigned) +        ((((magic() >> 16) * +              (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16) +           + MIN_CHALLENGE_LENGTH); +  cstate->chal_len = chal_len; +  cstate->chal_id = ++cstate->id; +  cstate->chal_transmits = 0; +   +  /* generate a random string */ +  for (i = 0; i < chal_len; i++ ) { +    *ptr++ = (char) (magic() & 0xff); +  } +} + +/* + * ChapSendResponse - send a response packet with values as specified + * in *cstate. + */ +/* ARGSUSED */ +static void +ChapSendResponse(chap_state *cstate) +{ +  u_char *outp; +  int outlen, md_len, name_len; +   +  md_len = cstate->resp_length; +  name_len = strlen(cstate->resp_name); +  outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; +  outp = outpacket_buf[cstate->unit]; +   +  MAKEHEADER(outp, PPP_CHAP); +   +  PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */ +  PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */ +  PUTSHORT(outlen, outp);      /* packet length */ +   +  PUTCHAR(md_len, outp);      /* length of MD */ +  BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */ +  INCPTR(md_len, outp); +   +  BCOPY(cstate->resp_name, outp, name_len);  /* append our name */ +   +  /* send the packet */ +  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); +   +  cstate->clientstate = CHAPCS_RESPONSE; +  TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime); +  ++cstate->resp_transmits; +} + +#if 0 +static char *ChapCodenames[] = { +  "Challenge", "Response", "Success", "Failure" +}; +/* + * ChapPrintPkt - print the contents of a CHAP packet. + */ +static int +ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ +  int code, id, len; +  int clen, nlen; +  u_char x; +   +  if (plen < CHAP_HEADERLEN) { +    return 0; +  } +  GETCHAR(code, p); +  GETCHAR(id, p); +  GETSHORT(len, p); +  if (len < CHAP_HEADERLEN || len > plen) { +    return 0; +  } +  if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) { +    printer(arg, " %s", ChapCodenames[code-1]); +  } else { +    printer(arg, " code=0x%x", code); +  } +  printer(arg, " id=0x%x", id); +  len -= CHAP_HEADERLEN; +  switch (code) { +    case CHAP_CHALLENGE: +    case CHAP_RESPONSE: +      if (len < 1) { +        break; +      } +      clen = p[0]; +      if (len < clen + 1) { +        break; +      } +      ++p; +      nlen = len - clen - 1; +      printer(arg, " <"); +      for (; clen > 0; --clen) { +        GETCHAR(x, p); +        printer(arg, "%.2x", x); +      } +      printer(arg, ">, name = %.*Z", nlen, p); +      break; +    case CHAP_FAILURE: +    case CHAP_SUCCESS: +      printer(arg, " %.*Z", len, p); +      break; +    default: +      for (clen = len; clen > 0; --clen) { +        GETCHAR(x, p); +        printer(arg, " %.2x", x); +      } +  } + +  return len + CHAP_HEADERLEN; +} +#endif + +#endif /* CHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chap.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chap.h new file mode 100644 index 000000000..83dafd734 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chap.h @@ -0,0 +1,166 @@ +/***************************************************************************** +* chap.h - Network Challenge Handshake Authentication Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original built from BSD network code. +******************************************************************************/ +/* + * chap.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1993 The Australian National University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Australian National University.  The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1991 Gregory M. Christy + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: chap.h,v 1.4 2007/12/19 20:47:22 fbernon Exp $ + */ + +#ifndef CHAP_H +#define CHAP_H + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* Code + ID + length */ +#define CHAP_HEADERLEN 4 + +/* + * CHAP codes. + */ + +#define CHAP_DIGEST_MD5      5    /* use MD5 algorithm */ +#define MD5_SIGNATURE_SIZE   16   /* 16 bytes in a MD5 message digest */ +#define CHAP_MICROSOFT       0x80 /* use Microsoft-compatible alg. */ +#define MS_CHAP_RESPONSE_LEN 49   /* Response length for MS-CHAP */ + +#define CHAP_CHALLENGE       1 +#define CHAP_RESPONSE        2 +#define CHAP_SUCCESS         3 +#define CHAP_FAILURE         4 + +/* + *  Challenge lengths (for challenges we send) and other limits. + */ +#define MIN_CHALLENGE_LENGTH 32 +#define MAX_CHALLENGE_LENGTH 64 +#define MAX_RESPONSE_LENGTH  64 /* sufficient for MD5 or MS-CHAP */ + +/* + * Client (peer) states. + */ +#define CHAPCS_INITIAL       0 /* Lower layer down, not opened */ +#define CHAPCS_CLOSED        1 /* Lower layer up, not opened */ +#define CHAPCS_PENDING       2 /* Auth us to peer when lower up */ +#define CHAPCS_LISTEN        3 /* Listening for a challenge */ +#define CHAPCS_RESPONSE      4 /* Sent response, waiting for status */ +#define CHAPCS_OPEN          5 /* We've received Success */ + +/* + * Server (authenticator) states. + */ +#define CHAPSS_INITIAL       0 /* Lower layer down, not opened */ +#define CHAPSS_CLOSED        1 /* Lower layer up, not opened */ +#define CHAPSS_PENDING       2 /* Auth peer when lower up */ +#define CHAPSS_INITIAL_CHAL  3 /* We've sent the first challenge */ +#define CHAPSS_OPEN          4 /* We've sent a Success msg */ +#define CHAPSS_RECHALLENGE   5 /* We've sent another challenge */ +#define CHAPSS_BADAUTH       6 /* We've sent a Failure msg */ + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * Each interface is described by a chap structure. + */ + +typedef struct chap_state { +  int unit;                               /* Interface unit number */ +  int clientstate;                        /* Client state */ +  int serverstate;                        /* Server state */ +  u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */ +  u_char chal_len;                        /* challenge length */ +  u_char chal_id;                         /* ID of last challenge */ +  u_char chal_type;                       /* hash algorithm for challenges */ +  u_char id;                              /* Current id */ +  char *chal_name;                        /* Our name to use with challenge */ +  int chal_interval;                      /* Time until we challenge peer again */ +  int timeouttime;                        /* Timeout time in seconds */ +  int max_transmits;                      /* Maximum # of challenge transmissions */ +  int chal_transmits;                     /* Number of transmissions of challenge */ +  int resp_transmits;                     /* Number of transmissions of response */ +  u_char response[MAX_RESPONSE_LENGTH];   /* Response to send */ +  u_char resp_length;                     /* length of response */ +  u_char resp_id;                         /* ID for response messages */ +  u_char resp_type;                       /* hash algorithm for responses */ +  char *resp_name;                        /* Our name to send with response */ +} chap_state; + + +/****************** +*** PUBLIC DATA *** +******************/ +extern chap_state chap[]; + +extern struct protent chap_protent; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +void ChapAuthWithPeer (int, char *, int); +void ChapAuthPeer (int, char *, int); + +#endif /* CHAP_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chpms.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chpms.c new file mode 100644 index 000000000..0c7521f20 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chpms.c @@ -0,0 +1,396 @@ +/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/ +/***************************************************************************** +* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD chap_ms.c. +*****************************************************************************/ +/* + * chap_ms.c - Microsoft MS-CHAP compatible implementation. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Eric Rosenquist.  The name of the author may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 + * + *   Implemented LANManager type password response to MS-CHAP challenges. + *   Now pppd provides both NT style and LANMan style blocks, and the + *   prefered is set by option "ms-lanman". Default is to use NT. + *   The hash text (StdText) was taken from Win95 RASAPI32.DLL. + * + *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 + */ + +#define USE_CRYPT + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "md4.h" +#ifndef USE_CRYPT +#include "des.h" +#endif +#include "chap.h" +#include "chpms.h" + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ +typedef struct { +    u_char LANManResp[24]; +    u_char NTResp[24]; +    u_char UseNT; /* If 1, ignore the LANMan response field */ +} MS_ChapResponse; +/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse), +   in case this struct gets padded. */ + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ + +/* XXX Don't know what to do with these. */ +extern void setkey(const char *); +extern void encrypt(char *, int); + +static void DesEncrypt (u_char *, u_char *, u_char *); +static void MakeKey (u_char *, u_char *); + +#ifdef USE_CRYPT +static void Expand (u_char *, u_char *); +static void Collapse (u_char *, u_char *); +#endif + +static void ChallengeResponse( +  u_char *challenge, /* IN   8 octets */ +  u_char *pwHash,    /* IN  16 octets */ +  u_char *response   /* OUT 24 octets */ +); +static void ChapMS_NT( +  char *rchallenge, +  int rchallenge_len, +  char *secret, +  int secret_len, +  MS_ChapResponse *response +); +static u_char Get7Bits( +  u_char *input, +  int startBit +); + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +void +ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len) +{ +  MS_ChapResponse response; +#ifdef MSLANMAN +  extern int ms_lanman; +#endif + +#if 0 +  CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret)); +#endif +  BZERO(&response, sizeof(response)); + +  /* Calculate both always */ +  ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response); + +#ifdef MSLANMAN +  ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response); + +  /* prefered method is set by option  */ +  response.UseNT = !ms_lanman; +#else +  response.UseNT = 1; +#endif + +  BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); +  cstate->resp_length = MS_CHAP_RESPONSE_LEN; +} + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +static void +ChallengeResponse( u_char *challenge, /* IN   8 octets */ +                   u_char *pwHash,    /* IN  16 octets */ +                   u_char *response   /* OUT 24 octets */) +{ +  char    ZPasswordHash[21]; + +  BZERO(ZPasswordHash, sizeof(ZPasswordHash)); +  BCOPY(pwHash, ZPasswordHash, 16); + +#if 0 +  log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG); +#endif + +  DesEncrypt(challenge, ZPasswordHash +  0, response + 0); +  DesEncrypt(challenge, ZPasswordHash +  7, response + 8); +  DesEncrypt(challenge, ZPasswordHash + 14, response + 16); + +#if 0 +  log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG); +#endif +} + + +#ifdef USE_CRYPT +static void +DesEncrypt( u_char *clear, /* IN  8 octets */ +            u_char *key,   /* IN  7 octets */ +            u_char *cipher /* OUT 8 octets */) +{ +  u_char des_key[8]; +  u_char crypt_key[66]; +  u_char des_input[66]; + +  MakeKey(key, des_key); + +  Expand(des_key, crypt_key); +  setkey(crypt_key); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", +             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); +#endif + +  Expand(clear, des_input); +  encrypt(des_input, 0); +  Collapse(des_input, cipher); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", +             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); +#endif +} + +#else /* USE_CRYPT */ + +static void +DesEncrypt( u_char *clear, /* IN  8 octets */ +            u_char *key,   /* IN  7 octets */ +            u_char *cipher /* OUT 8 octets */) +{ +  des_cblock    des_key; +  des_key_schedule  key_schedule; + +  MakeKey(key, des_key); + +  des_set_key(&des_key, key_schedule); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", +             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); +#endif + +  des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", +             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); +#endif +} + +#endif /* USE_CRYPT */ + + +static u_char +Get7Bits( u_char *input, int startBit) +{ +  register unsigned int  word; + +  word  = (unsigned)input[startBit / 8] << 8; +  word |= (unsigned)input[startBit / 8 + 1]; + +  word >>= 15 - (startBit % 8 + 7); + +  return word & 0xFE; +} + +#ifdef USE_CRYPT + +/* in == 8-byte string (expanded version of the 56-bit key) + * out == 64-byte string where each byte is either 1 or 0 + * Note that the low-order "bit" is always ignored by by setkey() + */ +static void +Expand(u_char *in, u_char *out) +{ +  int j, c; +  int i; + +  for(i = 0; i < 64; in++){ +    c = *in; +    for(j = 7; j >= 0; j--) { +      *out++ = (c >> j) & 01; +    } +    i += 8; +  } +} + +/* The inverse of Expand + */ +static void +Collapse(u_char *in, u_char *out) +{ +  int j; +  int i; +  unsigned int c; + +  for (i = 0; i < 64; i += 8, out++) { +    c = 0; +    for (j = 7; j >= 0; j--, in++) { +      c |= *in << j; +    } +    *out = c & 0xff; +  } +} +#endif + +static void +MakeKey( u_char *key,    /* IN  56 bit DES key missing parity bits */ +         u_char *des_key /* OUT 64 bit DES key with parity bits added */) +{ +  des_key[0] = Get7Bits(key,  0); +  des_key[1] = Get7Bits(key,  7); +  des_key[2] = Get7Bits(key, 14); +  des_key[3] = Get7Bits(key, 21); +  des_key[4] = Get7Bits(key, 28); +  des_key[5] = Get7Bits(key, 35); +  des_key[6] = Get7Bits(key, 42); +  des_key[7] = Get7Bits(key, 49); +   +#ifndef USE_CRYPT +  des_set_odd_parity((des_cblock *)des_key); +#endif +   +#if 0 +  CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n", +             key[0], key[1], key[2], key[3], key[4], key[5], key[6])); +  CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n", +             des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7])); +#endif +} + +static void +ChapMS_NT( char *rchallenge, +           int rchallenge_len, +           char *secret, +           int secret_len, +           MS_ChapResponse *response) +{ +  int      i; +  MDstruct  md4Context; +  u_char    unicodePassword[MAX_NT_PASSWORD * 2]; +  static int  low_byte_first = -1; + +  /* Initialize the Unicode version of the secret (== password). */ +  /* This implicitly supports 8-bit ISO8859/1 characters. */ +  BZERO(unicodePassword, sizeof(unicodePassword)); +  for (i = 0; i < secret_len; i++) { +    unicodePassword[i * 2] = (u_char)secret[i]; +  } +  MDbegin(&md4Context); +  MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);  /* Unicode is 2 bytes/char, *8 for bit count */ + +  if (low_byte_first == -1) { +    low_byte_first = (htons((unsigned short int)1) != 1); +  } +  if (low_byte_first == 0) { +    MDreverse((u_long *)&md4Context);  /*  sfb 961105 */ +  } + +  MDupdate(&md4Context, NULL, 0);  /* Tell MD4 we're done */ + +  ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp); +} + +#ifdef MSLANMAN +static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ + +static void +ChapMS_LANMan( char *rchallenge, +               int rchallenge_len, +               char *secret, +               int secret_len, +               MS_ChapResponse  *response) +{ +  int      i; +  u_char    UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ +  u_char    PasswordHash[16]; +   +  /* LANMan password is case insensitive */ +  BZERO(UcasePassword, sizeof(UcasePassword)); +  for (i = 0; i < secret_len; i++) { +    UcasePassword[i] = (u_char)toupper(secret[i]); +  } +  DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 ); +  DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 ); +  ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); +} +#endif + +#endif /* MSCHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chpms.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chpms.h new file mode 100644 index 000000000..df070fb35 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/chpms.h @@ -0,0 +1,64 @@ +/***************************************************************************** +* chpms.h - Network Microsoft Challenge Handshake Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original built from BSD network code. +******************************************************************************/ +/* + * chap.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Eric Rosenquist.  The name of the author may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: chpms.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef CHPMS_H +#define CHPMS_H + +#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */ + +void ChapMS (chap_state *, char *, int, char *, int); + +#endif /* CHPMS_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/fsm.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/fsm.c new file mode 100644 index 000000000..c073f1e36 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/fsm.c @@ -0,0 +1,906 @@ +/***************************************************************************** +* fsm.c - Network Control Protocol Finite State Machine program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD fsm.c. +*****************************************************************************/ +/* + * fsm.c - {Link, IP} Control Protocol Finite State Machine. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * TODO: + * Randomize fsm id on link/init. + * Deal with variable outgoing MTU. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "fsm.h" + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +#if PPP_DEBUG + +static const char *ppperr_strerr[] = { +           "LS_INITIAL",  /* LS_INITIAL  0 */ +           "LS_STARTING", /* LS_STARTING 1 */ +           "LS_CLOSED",   /* LS_CLOSED   2 */ +           "LS_STOPPED",  /* LS_STOPPED  3 */ +           "LS_CLOSING",  /* LS_CLOSING  4 */ +           "LS_STOPPING", /* LS_STOPPING 5 */ +           "LS_REQSENT",  /* LS_REQSENT  6 */ +           "LS_ACKRCVD",  /* LS_ACKRCVD  7 */ +           "LS_ACKSENT",  /* LS_ACKSENT  8 */ +           "LS_OPENED"    /* LS_OPENED   9 */ +}; + +#endif /* PPP_DEBUG */ + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +static void fsm_timeout (void *); +static void fsm_rconfreq (fsm *, u_char, u_char *, int); +static void fsm_rconfack (fsm *, int, u_char *, int); +static void fsm_rconfnakrej (fsm *, int, int, u_char *, int); +static void fsm_rtermreq (fsm *, int, u_char *, int); +static void fsm_rtermack (fsm *); +static void fsm_rcoderej (fsm *, u_char *, int); +static void fsm_sconfreq (fsm *, int); + +#define PROTO_NAME(f) ((f)->callbacks->proto_name) + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +int peer_mru[NUM_PPP]; + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ + +/* + * fsm_init - Initialize fsm. + * + * Initialize fsm state. + */ +void +fsm_init(fsm *f) +{ +  f->state = LS_INITIAL; +  f->flags = 0; +  f->id = 0;        /* XXX Start with random id? */ +  f->timeouttime = FSM_DEFTIMEOUT; +  f->maxconfreqtransmits = FSM_DEFMAXCONFREQS; +  f->maxtermtransmits = FSM_DEFMAXTERMREQS; +  f->maxnakloops = FSM_DEFMAXNAKLOOPS; +  f->term_reason_len = 0; +} + + +/* + * fsm_lowerup - The lower layer is up. + */ +void +fsm_lowerup(fsm *f) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  switch( f->state ) { +    case LS_INITIAL: +      f->state = LS_CLOSED; +      break; + +    case LS_STARTING: +      if( f->flags & OPT_SILENT ) { +        f->state = LS_STOPPED; +      } else { +        /* Send an initial configure-request */ +        fsm_sconfreq(f, 0); +        f->state = LS_REQSENT; +      } +    break; + +    default: +      FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n", +          PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +  } +   +  FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_lowerdown - The lower layer is down. + * + * Cancel all timeouts and inform upper layers. + */ +void +fsm_lowerdown(fsm *f) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  switch( f->state ) { +    case LS_CLOSED: +      f->state = LS_INITIAL; +      break; + +    case LS_STOPPED: +      f->state = LS_STARTING; +      if( f->callbacks->starting ) { +        (*f->callbacks->starting)(f); +      } +      break; + +    case LS_CLOSING: +      f->state = LS_INITIAL; +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      break; + +    case LS_STOPPING: +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +      f->state = LS_STARTING; +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      break; + +    case LS_OPENED: +      if( f->callbacks->down ) { +        (*f->callbacks->down)(f); +      } +      f->state = LS_STARTING; +      break; + +    default: +      FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n", +          PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +  } + +  FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_open - Link is allowed to come up. + */ +void +fsm_open(fsm *f) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  switch( f->state ) { +    case LS_INITIAL: +      f->state = LS_STARTING; +      if( f->callbacks->starting ) { +        (*f->callbacks->starting)(f); +      } +      break; + +    case LS_CLOSED: +      if( f->flags & OPT_SILENT ) { +        f->state = LS_STOPPED; +      } else { +        /* Send an initial configure-request */ +        fsm_sconfreq(f, 0); +        f->state = LS_REQSENT; +      } +      break; +   +    case LS_CLOSING: +      f->state = LS_STOPPING; +      /* fall through */ +    case LS_STOPPED: +    case LS_OPENED: +      if( f->flags & OPT_RESTART ) { +        fsm_lowerdown(f); +        fsm_lowerup(f); +      } +      break; +  } + +  FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_close - Start closing connection. + * + * Cancel timeouts and either initiate close or possibly go directly to + * the LS_CLOSED state. + */ +void +fsm_close(fsm *f, char *reason) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  f->term_reason = reason; +  f->term_reason_len = (reason == NULL? 0: strlen(reason)); +  switch( f->state ) { +    case LS_STARTING: +      f->state = LS_INITIAL; +      break; +    case LS_STOPPED: +      f->state = LS_CLOSED; +      break; +    case LS_STOPPING: +      f->state = LS_CLOSING; +      break; + +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +    case LS_OPENED: +      if( f->state != LS_OPENED ) { +        UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      } else if( f->callbacks->down ) { +        (*f->callbacks->down)(f);  /* Inform upper layers we're down */ +      } +      /* Init restart counter, send Terminate-Request */ +      f->retransmits = f->maxtermtransmits; +      fsm_sdata(f, TERMREQ, f->reqid = ++f->id, +            (u_char *) f->term_reason, f->term_reason_len); +      TIMEOUT(fsm_timeout, f, f->timeouttime); +      --f->retransmits; + +      f->state = LS_CLOSING; +      break; +  } + +  FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_sdata - Send some data. + * + * Used for all packets sent to our peer by this module. + */ +void +fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen) +{ +  u_char *outp; +  int outlen; + +  /* Adjust length to be smaller than MTU */ +  outp = outpacket_buf[f->unit]; +  if (datalen > peer_mru[f->unit] - (int)HEADERLEN) { +    datalen = peer_mru[f->unit] - HEADERLEN; +  } +  if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) { +    BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); +  } +  outlen = datalen + HEADERLEN; +  MAKEHEADER(outp, f->protocol); +  PUTCHAR(code, outp); +  PUTCHAR(id, outp); +  PUTSHORT(outlen, outp); +  pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN); +  FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n", +        PROTO_NAME(f), code, id, outlen)); +} + + +/* + * fsm_input - Input packet. + */ +void +fsm_input(fsm *f, u_char *inpacket, int l) +{ +  u_char *inp = inpacket; +  u_char code, id; +  int len; + +  /* +  * Parse header (code, id and length). +  * If packet too short, drop it. +  */ +  if (l < HEADERLEN) { +    FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n", +          f->protocol)); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  GETSHORT(len, inp); +  if (len < HEADERLEN) { +    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n", +        f->protocol)); +    return; +  } +  if (len > l) { +    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n", +        f->protocol)); +    return; +  } +  len -= HEADERLEN;    /* subtract header length */ + +  if( f->state == LS_INITIAL || f->state == LS_STARTING ) { +    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n", +        f->protocol, f->state, ppperr_strerr[f->state])); +    return; +  } +  FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l)); +  /* +   * Action depends on code. +   */ +  switch (code) { +    case CONFREQ: +      fsm_rconfreq(f, id, inp, len); +      break; +     +    case CONFACK: +      fsm_rconfack(f, id, inp, len); +      break; +     +    case CONFNAK: +    case CONFREJ: +      fsm_rconfnakrej(f, code, id, inp, len); +      break; +     +    case TERMREQ: +      fsm_rtermreq(f, id, inp, len); +      break; +     +    case TERMACK: +      fsm_rtermack(f); +      break; +     +    case CODEREJ: +      fsm_rcoderej(f, inp, len); +      break; +     +    default: +      if( !f->callbacks->extcode || +          !(*f->callbacks->extcode)(f, code, id, inp, len) ) { +        fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); +      } +      break; +  } +} + + +/* + * fsm_protreject - Peer doesn't speak this protocol. + * + * Treat this as a catastrophic error (RXJ-). + */ +void +fsm_protreject(fsm *f) +{ +  switch( f->state ) { +    case LS_CLOSING: +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      /* fall through */ +    case LS_CLOSED: +      f->state = LS_CLOSED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; + +    case LS_STOPPING: +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      /* fall through */ +    case LS_STOPPED: +      f->state = LS_STOPPED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; +     +    case LS_OPENED: +      if( f->callbacks->down ) { +        (*f->callbacks->down)(f); +      } +      /* Init restart counter, send Terminate-Request */ +      f->retransmits = f->maxtermtransmits; +      fsm_sdata(f, TERMREQ, f->reqid = ++f->id, +            (u_char *) f->term_reason, f->term_reason_len); +      TIMEOUT(fsm_timeout, f, f->timeouttime); +      --f->retransmits; +       +      f->state = LS_STOPPING; +      break; +     +    default: +      FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n", +            PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +    } +} + + + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +/* + * fsm_timeout - Timeout expired. + */ +static void +fsm_timeout(void *arg) +{ +  fsm *f = (fsm *) arg; + +  switch (f->state) { +    case LS_CLOSING: +    case LS_STOPPING: +      if( f->retransmits <= 0 ) { +        FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n", +             PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        /* +         * We've waited for an ack long enough.  Peer probably heard us. +         */ +        f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED; +        if( f->callbacks->finished ) { +          (*f->callbacks->finished)(f); +        } +      } else { +        FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n", +             PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        /* Send Terminate-Request */ +        fsm_sdata(f, TERMREQ, f->reqid = ++f->id, +            (u_char *) f->term_reason, f->term_reason_len); +        TIMEOUT(fsm_timeout, f, f->timeouttime); +        --f->retransmits; +      } +      break; + +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +      if (f->retransmits <= 0) { +        FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n", +         PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        f->state = LS_STOPPED; +        if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) { +          (*f->callbacks->finished)(f); +        } +      } else { +        FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n", +         PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        /* Retransmit the configure-request */ +        if (f->callbacks->retransmit) { +          (*f->callbacks->retransmit)(f); +        } +        fsm_sconfreq(f, 1);    /* Re-send Configure-Request */ +        if( f->state == LS_ACKRCVD ) { +          f->state = LS_REQSENT; +        } +      } +      break; + +    default: +      FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d (%s)!\n", +          PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +  } +} + + +/* + * fsm_rconfreq - Receive Configure-Request. + */ +static void +fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) +{ +  int code, reject_if_disagree; + +  FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",  +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); +  switch( f->state ) { +    case LS_CLOSED: +      /* Go away, we're closed */ +      fsm_sdata(f, TERMACK, id, NULL, 0); +      return; +    case LS_CLOSING: +    case LS_STOPPING: +      return; + +    case LS_OPENED: +      /* Go down and restart negotiation */ +      if( f->callbacks->down ) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      break; + +    case LS_STOPPED: +      /* Negotiation started by our peer */ +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      f->state = LS_REQSENT; +      break; +  } +   +  /* +  * Pass the requested configuration options +  * to protocol-specific code for checking. +  */ +  if (f->callbacks->reqci) {    /* Check CI */ +    reject_if_disagree = (f->nakloops >= f->maxnakloops); +    code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); +  } else if (len) { +    code = CONFREJ;      /* Reject all CI */ +  } else { +    code = CONFACK; +  } +   +  /* send the Ack, Nak or Rej to the peer */ +  fsm_sdata(f, (u_char)code, id, inp, len); +   +  if (code == CONFACK) { +    if (f->state == LS_ACKRCVD) { +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      f->state = LS_OPENED; +      if (f->callbacks->up) { +        (*f->callbacks->up)(f);  /* Inform upper layers */ +      } +    } else { +      f->state = LS_ACKSENT; +    } +    f->nakloops = 0; +  } else { +    /* we sent CONFACK or CONFREJ */ +    if (f->state != LS_ACKRCVD) { +      f->state = LS_REQSENT; +    } +    if( code == CONFNAK ) { +      ++f->nakloops; +    } +  } +} + + +/* + * fsm_rconfack - Receive Configure-Ack. + */ +static void +fsm_rconfack(fsm *f, int id, u_char *inp, int len) +{ +  FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n", +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); +   +  if (id != f->reqid || f->seen_ack) {   /* Expected id? */ +    return; /* Nope, toss... */ +  } +  if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) { +    /* Ack is bad - ignore it */ +    FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n", +          PROTO_NAME(f), len)); +    return; +  } +  f->seen_ack = 1; +   +  switch (f->state) { +    case LS_CLOSED: +    case LS_STOPPED: +      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); +      break; +     +    case LS_REQSENT: +      f->state = LS_ACKRCVD; +      f->retransmits = f->maxconfreqtransmits; +      break; +     +    case LS_ACKRCVD: +      /* Huh? an extra valid Ack? oh well... */ +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      fsm_sconfreq(f, 0); +      f->state = LS_REQSENT; +      break; +     +    case LS_ACKSENT: +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      f->state = LS_OPENED; +      f->retransmits = f->maxconfreqtransmits; +      if (f->callbacks->up) { +        (*f->callbacks->up)(f);  /* Inform upper layers */ +      } +      break; +     +    case LS_OPENED: +      /* Go down and restart negotiation */ +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      f->state = LS_REQSENT; +      break; +  } +} + + +/* + * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. + */ +static void +fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) +{ +  int (*proc) (fsm *, u_char *, int); +  int ret; + +  FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n", +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + +  if (id != f->reqid || f->seen_ack) { /* Expected id? */ +    return;        /* Nope, toss... */ +  } +  proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; +  if (!proc || !((ret = proc(f, inp, len)))) { +    /* Nak/reject is bad - ignore it */ +    FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n", +          PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); +    return; +  } +  f->seen_ack = 1; + +  switch (f->state) { +    case LS_CLOSED: +    case LS_STOPPED: +      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); +      break; +     +    case LS_REQSENT: +    case LS_ACKSENT: +      /* They didn't agree to what we wanted - try another request */ +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      if (ret < 0) { +        f->state = LS_STOPPED;    /* kludge for stopping CCP */ +      } else { +        fsm_sconfreq(f, 0);    /* Send Configure-Request */ +      } +      break; +     +    case LS_ACKRCVD: +      /* Got a Nak/reject when we had already had an Ack?? oh well... */ +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      fsm_sconfreq(f, 0); +      f->state = LS_REQSENT; +      break; +     +    case LS_OPENED: +      /* Go down and restart negotiation */ +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      f->state = LS_REQSENT; +      break; +  } +} + + +/* + * fsm_rtermreq - Receive Terminate-Req. + */ +static void +fsm_rtermreq(fsm *f, int id, u_char *p, int len) +{ +  LWIP_UNUSED_ARG(p); + +  FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n", +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + +  switch (f->state) { +    case LS_ACKRCVD: +    case LS_ACKSENT: +      f->state = LS_REQSENT;    /* Start over but keep trying */ +      break; + +    case LS_OPENED: +      if (len > 0) { +        FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p)); +      } else { +        FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f))); +      } +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      f->retransmits = 0; +      f->state = LS_STOPPING; +      TIMEOUT(fsm_timeout, f, f->timeouttime); +      break; +  } + +  fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); +} + + +/* + * fsm_rtermack - Receive Terminate-Ack. + */ +static void +fsm_rtermack(fsm *f) +{ +  FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n",  +        PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +   +  switch (f->state) { +    case LS_CLOSING: +      UNTIMEOUT(fsm_timeout, f); +      f->state = LS_CLOSED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; + +    case LS_STOPPING: +      UNTIMEOUT(fsm_timeout, f); +      f->state = LS_STOPPED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; +     +    case LS_ACKRCVD: +      f->state = LS_REQSENT; +      break; +     +    case LS_OPENED: +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0); +      break; +  } +} + + +/* + * fsm_rcoderej - Receive an Code-Reject. + */ +static void +fsm_rcoderej(fsm *f, u_char *inp, int len) +{ +  u_char code, id; +   +  FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n",  +        PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +   +  if (len < HEADERLEN) { +    FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n")); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n", +        PROTO_NAME(f), code, id)); +   +  if( f->state == LS_ACKRCVD ) { +    f->state = LS_REQSENT; +  } +} + + +/* + * fsm_sconfreq - Send a Configure-Request. + */ +static void +fsm_sconfreq(fsm *f, int retransmit) +{ +  u_char *outp; +  int cilen; +   +  if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) { +    /* Not currently negotiating - reset options */ +    if( f->callbacks->resetci ) { +      (*f->callbacks->resetci)(f); +    } +    f->nakloops = 0; +  } +   +  if( !retransmit ) { +    /* New request - reset retransmission counter, use new ID */ +    f->retransmits = f->maxconfreqtransmits; +    f->reqid = ++f->id; +  } +   +  f->seen_ack = 0; +   +  /* +   * Make up the request packet +   */ +  outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN; +  if( f->callbacks->cilen && f->callbacks->addci ) { +    cilen = (*f->callbacks->cilen)(f); +    if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) { +      cilen = peer_mru[f->unit] - HEADERLEN; +    } +    if (f->callbacks->addci) { +      (*f->callbacks->addci)(f, outp, &cilen); +    } +  } else { +    cilen = 0; +  } + +  /* send the request to our peer */ +  fsm_sdata(f, CONFREQ, f->reqid, outp, cilen); +   +  /* start the retransmit timer */ +  --f->retransmits; +  TIMEOUT(fsm_timeout, f, f->timeouttime); +   +  FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n", +        PROTO_NAME(f), f->reqid)); +} + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/fsm.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/fsm.h new file mode 100644 index 000000000..14034ec7f --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/fsm.h @@ -0,0 +1,169 @@ +/***************************************************************************** +* fsm.h - Network Control Protocol Finite State Machine header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original based on BSD code. +*****************************************************************************/ +/* + * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: fsm.h,v 1.4 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef FSM_H +#define FSM_H + +/***************************************************************************** +************************* PUBLIC DEFINITIONS ********************************* +*****************************************************************************/ +/* + * LCP Packet header = Code, id, length. + */ +#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) + + +/* + *  CP (LCP, IPCP, etc.) codes. + */ +#define CONFREQ     1 /* Configuration Request */ +#define CONFACK     2 /* Configuration Ack */ +#define CONFNAK     3 /* Configuration Nak */ +#define CONFREJ     4 /* Configuration Reject */ +#define TERMREQ     5 /* Termination Request */ +#define TERMACK     6 /* Termination Ack */ +#define CODEREJ     7 /* Code Reject */ + +/* + * Link states. + */ +#define LS_INITIAL  0 /* Down, hasn't been opened */ +#define LS_STARTING 1 /* Down, been opened */ +#define LS_CLOSED   2 /* Up, hasn't been opened */ +#define LS_STOPPED  3 /* Open, waiting for down event */ +#define LS_CLOSING  4 /* Terminating the connection, not open */ +#define LS_STOPPING 5 /* Terminating, but open */ +#define LS_REQSENT  6 /* We've sent a Config Request */ +#define LS_ACKRCVD  7 /* We've received a Config Ack */ +#define LS_ACKSENT  8 /* We've sent a Config Ack */ +#define LS_OPENED   9 /* Connection available */ + +/* + * Flags - indicate options controlling FSM operation + */ +#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ +#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ +#define OPT_SILENT  4 /* Wait for peer to speak first */ + + +/***************************************************************************** +************************* PUBLIC DATA TYPES ********************************** +*****************************************************************************/ +/* + * Each FSM is described by an fsm structure and fsm callbacks. + */ +typedef struct fsm { +  int unit;                        /* Interface unit number */ +  u_short protocol;                /* Data Link Layer Protocol field value */ +  int state;                       /* State */ +  int flags;                       /* Contains option bits */ +  u_char id;                       /* Current id */ +  u_char reqid;                    /* Current request id */ +  u_char seen_ack;                 /* Have received valid Ack/Nak/Rej to Req */ +  int timeouttime;                 /* Timeout time in milliseconds */ +  int maxconfreqtransmits;         /* Maximum Configure-Request transmissions */ +  int retransmits;                 /* Number of retransmissions left */ +  int maxtermtransmits;            /* Maximum Terminate-Request transmissions */ +  int nakloops;                    /* Number of nak loops since last ack */ +  int maxnakloops;                 /* Maximum number of nak loops tolerated */ +  struct fsm_callbacks* callbacks; /* Callback routines */ +  char* term_reason;               /* Reason for closing protocol */ +  int term_reason_len;             /* Length of term_reason */ +} fsm; + + +typedef struct fsm_callbacks { +  void (*resetci)(fsm*);                            /* Reset our Configuration Information */ +  int  (*cilen)(fsm*);                              /* Length of our Configuration Information */ +  void (*addci)(fsm*, u_char*, int*);               /* Add our Configuration Information */ +  int  (*ackci)(fsm*, u_char*, int);                /* ACK our Configuration Information */ +  int  (*nakci)(fsm*, u_char*, int);                /* NAK our Configuration Information */ +  int  (*rejci)(fsm*, u_char*, int);                /* Reject our Configuration Information */ +  int  (*reqci)(fsm*, u_char*, int*, int);          /* Request peer's Configuration Information */ +  void (*up)(fsm*);                                 /* Called when fsm reaches LS_OPENED state */ +  void (*down)(fsm*);                               /* Called when fsm leaves LS_OPENED state */ +  void (*starting)(fsm*);                           /* Called when we want the lower layer */ +  void (*finished)(fsm*);                           /* Called when we don't want the lower layer */ +  void (*protreject)(int);                          /* Called when Protocol-Reject received */ +  void (*retransmit)(fsm*);                         /* Retransmission is necessary */ +  int  (*extcode)(fsm*, int, u_char, u_char*, int); /* Called when unknown code received */ +  char *proto_name;                                 /* String name for protocol (for messages) */ +} fsm_callbacks; + + +/***************************************************************************** +*********************** PUBLIC DATA STRUCTURES ******************************* +*****************************************************************************/ +/* + * Variables + */ +extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */ + + +/***************************************************************************** +************************** PUBLIC FUNCTIONS ********************************** +*****************************************************************************/ + +/* + * Prototypes + */ +void fsm_init (fsm*); +void fsm_lowerup (fsm*); +void fsm_lowerdown (fsm*); +void fsm_open (fsm*); +void fsm_close (fsm*, char*); +void fsm_input (fsm*, u_char*, int); +void fsm_protreject (fsm*); +void fsm_sdata (fsm*, u_char, u_char, u_char*, int); + +#endif /* FSM_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c new file mode 100644 index 000000000..3a403a0a6 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c @@ -0,0 +1,1440 @@ +/***************************************************************************** +* ipcp.c - Network PPP IP Control Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ +/* + * ipcp.c - PPP IP Control Protocol. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "auth.h" +#include "fsm.h" +#include "vj.h" +#include "ipcp.h" + +#include <string.h> + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ +/* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */ + +/* + * Lengths of configuration options. + */ +#define CILEN_VOID     2 +#define CILEN_COMPRESS 4  /* min length for compression protocol opt. */ +#define CILEN_VJ       6  /* length for RFC1332 Van-Jacobson opt. */ +#define CILEN_ADDR     6  /* new-style single address option */ +#define CILEN_ADDRS    10 /* old-style dual address option */ + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Callbacks for fsm code.  (CI = Configuration Information) + */ +static void ipcp_resetci (fsm *);                     /* Reset our CI */ +static int  ipcp_cilen (fsm *);                       /* Return length of our CI */ +static void ipcp_addci (fsm *, u_char *, int *);      /* Add our CI */ +static int  ipcp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */ +static int  ipcp_nakci (fsm *, u_char *, int);        /* Peer nak'd our CI */ +static int  ipcp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */ +static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */ +static void ipcp_up (fsm *);                          /* We're UP */ +static void ipcp_down (fsm *);                        /* We're DOWN */ +#if 0 +static void ipcp_script (fsm *, char *); /* Run an up/down script */ +#endif +static void ipcp_finished (fsm *);                    /* Don't need lower layer */ + +/* + * Protocol entry points from main code. + */ +static void ipcp_init (int); +static void ipcp_open (int); +static void ipcp_close (int, char *); +static void ipcp_lowerup (int); +static void ipcp_lowerdown (int); +static void ipcp_input (int, u_char *, int); +static void ipcp_protrej (int); + +static void ipcp_clear_addrs (int); + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ +                     (x) == CONFNAK ? "NAK" : "REJ") + + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +/* global vars */ +ipcp_options ipcp_wantoptions[NUM_PPP];  /* Options that we want to request */ +ipcp_options ipcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */ +ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +ipcp_options ipcp_hisoptions[NUM_PPP];   /* Options that we ack'd */ + +fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ + +struct protent ipcp_protent = { +  PPP_IPCP, +  ipcp_init, +  ipcp_input, +  ipcp_protrej, +  ipcp_lowerup, +  ipcp_lowerdown, +  ipcp_open, +  ipcp_close, +#if 0 +  ipcp_printpkt, +  NULL, +#endif +  1, +  "IPCP", +#if 0 +  ip_check_options, +  NULL, +  ip_active_pkt +#endif +}; + + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +/* local vars */ +static int cis_received[NUM_PPP];      /* # Conf-Reqs received */ +static int default_route_set[NUM_PPP]; /* Have set up a default route */ + +static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ +  ipcp_resetci,  /* Reset our Configuration Information */ +  ipcp_cilen,    /* Length of our Configuration Information */ +  ipcp_addci,    /* Add our Configuration Information */ +  ipcp_ackci,    /* ACK our Configuration Information */ +  ipcp_nakci,    /* NAK our Configuration Information */ +  ipcp_rejci,    /* Reject our Configuration Information */ +  ipcp_reqci,    /* Request peer's Configuration Information */ +  ipcp_up,       /* Called when fsm reaches LS_OPENED state */ +  ipcp_down,     /* Called when fsm leaves LS_OPENED state */ +  NULL,          /* Called when we want the lower layer up */ +  ipcp_finished, /* Called when we want the lower layer down */ +  NULL,          /* Called when Protocol-Reject received */ +  NULL,          /* Retransmission is necessary */ +  NULL,          /* Called to handle protocol-specific codes */ +  "IPCP"         /* String name of protocol */ +}; + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +/* + * Non-standard inet_ntoa left here for compat with original ppp + * sources. Assumes u32_t instead of struct in_addr. + */  + +char * +_inet_ntoa(u32_t n) +{ +  struct in_addr ia; +  ia.s_addr = n; +  return inet_ntoa(ia); +} + +#define inet_ntoa _inet_ntoa + +/* + * ipcp_init - Initialize IPCP. + */ +static void +ipcp_init(int unit) +{ +  fsm           *f = &ipcp_fsm[unit]; +  ipcp_options *wo = &ipcp_wantoptions[unit]; +  ipcp_options *ao = &ipcp_allowoptions[unit]; + +  f->unit      = unit; +  f->protocol  = PPP_IPCP; +  f->callbacks = &ipcp_callbacks; +  fsm_init(&ipcp_fsm[unit]); + +  memset(wo, 0, sizeof(*wo)); +  memset(ao, 0, sizeof(*ao)); + +  wo->neg_addr      = 1; +  wo->ouraddr       = 0; +#if VJ_SUPPORT +  wo->neg_vj        = 1; +#else  /* VJ_SUPPORT */ +  wo->neg_vj        = 0; +#endif /* VJ_SUPPORT */ +  wo->vj_protocol   = IPCP_VJ_COMP; +  wo->maxslotindex  = MAX_SLOTS - 1; +  wo->cflag         = 0; +  wo->default_route = 1; + +  ao->neg_addr      = 1; +#if VJ_SUPPORT +  ao->neg_vj        = 1; +#else  /* VJ_SUPPORT */ +  ao->neg_vj        = 0; +#endif /* VJ_SUPPORT */ +  ao->maxslotindex  = MAX_SLOTS - 1; +  ao->cflag         = 1; +  ao->default_route = 1; +} + + +/* + * ipcp_open - IPCP is allowed to come up. + */ +static void +ipcp_open(int unit) +{ +  fsm_open(&ipcp_fsm[unit]); +} + + +/* + * ipcp_close - Take IPCP down. + */ +static void +ipcp_close(int unit, char *reason) +{ +  fsm_close(&ipcp_fsm[unit], reason); +} + + +/* + * ipcp_lowerup - The lower layer is up. + */ +static void +ipcp_lowerup(int unit) +{ +  fsm_lowerup(&ipcp_fsm[unit]); +} + + +/* + * ipcp_lowerdown - The lower layer is down. + */ +static void +ipcp_lowerdown(int unit) +{ +  fsm_lowerdown(&ipcp_fsm[unit]); +} + + +/* + * ipcp_input - Input IPCP packet. + */ +static void +ipcp_input(int unit, u_char *p, int len) +{ +  fsm_input(&ipcp_fsm[unit], p, len); +} + + +/* + * ipcp_protrej - A Protocol-Reject was received for IPCP. + * + * Pretend the lower layer went down, so we shut up. + */ +static void +ipcp_protrej(int unit) +{ +  fsm_lowerdown(&ipcp_fsm[unit]); +} + + +/* + * ipcp_resetci - Reset our CI. + */ +static void +ipcp_resetci(fsm *f) +{ +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; +   +  wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; +  if (wo->ouraddr == 0) { +    wo->accept_local = 1; +  } +  if (wo->hisaddr == 0) { +    wo->accept_remote = 1; +  } +  /* Request DNS addresses from the peer */ +  wo->req_dns1 = ppp_settings.usepeerdns; +  wo->req_dns2 = ppp_settings.usepeerdns; +  ipcp_gotoptions[f->unit] = *wo; +  cis_received[f->unit] = 0; +} + + +/* + * ipcp_cilen - Return length of our CI. + */ +static int +ipcp_cilen(fsm *f) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; +  ipcp_options *ho = &ipcp_hisoptions[f->unit]; + +#define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) +#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0) +#define LENCIDNS(neg)       (neg ? (CILEN_ADDR) : 0) + +  /* +   * First see if we want to change our options to the old +   * forms because we have received old forms from the peer. +   */ +  if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { +    /* use the old style of address negotiation */ +    go->neg_addr = 1; +    go->old_addrs = 1; +  } +  if (wo->neg_vj && !go->neg_vj && !go->old_vj) { +    /* try an older style of VJ negotiation */ +    if (cis_received[f->unit] == 0) { +      /* keep trying the new style until we see some CI from the peer */ +      go->neg_vj = 1; +    } else { +      /* use the old style only if the peer did */ +      if (ho->neg_vj && ho->old_vj) { +        go->neg_vj = 1; +        go->old_vj = 1; +        go->vj_protocol = ho->vj_protocol; +      } +    } +  } + +  return (LENCIADDR(go->neg_addr, go->old_addrs) + +          LENCIVJ(go->neg_vj, go->old_vj) + +          LENCIDNS(go->req_dns1) + +          LENCIDNS(go->req_dns2)); +} + + +/* + * ipcp_addci - Add our desired CIs to a packet. + */ +static void +ipcp_addci(fsm *f, u_char *ucp, int *lenp) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  int len = *lenp; + +#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ +  if (neg) { \ +    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ +    if (len >= vjlen) { \ +      PUTCHAR(opt, ucp); \ +      PUTCHAR(vjlen, ucp); \ +      PUTSHORT(val, ucp); \ +      if (!old) { \ +        PUTCHAR(maxslotindex, ucp); \ +        PUTCHAR(cflag, ucp); \ +      } \ +      len -= vjlen; \ +    } else { \ +      neg = 0; \ +    } \ +  } + +#define ADDCIADDR(opt, neg, old, val1, val2) \ +  if (neg) { \ +    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ +    if (len >= addrlen) { \ +      u32_t l; \ +      PUTCHAR(opt, ucp); \ +      PUTCHAR(addrlen, ucp); \ +      l = ntohl(val1); \ +      PUTLONG(l, ucp); \ +      if (old) { \ +        l = ntohl(val2); \ +        PUTLONG(l, ucp); \ +      } \ +      len -= addrlen; \ +    } else { \ +      neg = 0; \ +    } \ +  } + +#define ADDCIDNS(opt, neg, addr) \ +  if (neg) { \ +    if (len >= CILEN_ADDR) { \ +      u32_t l; \ +      PUTCHAR(opt, ucp); \ +      PUTCHAR(CILEN_ADDR, ucp); \ +      l = ntohl(addr); \ +      PUTLONG(l, ucp); \ +      len -= CILEN_ADDR; \ +    } else { \ +      neg = 0; \ +    } \ +  } + +  ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, +      go->old_addrs, go->ouraddr, go->hisaddr); + +  ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, +      go->maxslotindex, go->cflag); + +  ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + +  ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); + +  *lenp -= len; +} + + +/* + * ipcp_ackci - Ack our CIs. + * + * Returns: + *  0 - Ack was bad. + *  1 - Ack was good. + */ +static int +ipcp_ackci(fsm *f, u_char *p, int len) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  u_short cilen, citype, cishort; +  u32_t cilong; +  u_char cimaxslotindex, cicflag; + +  /* +   * CIs must be in exactly the same order that we sent... +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ + +#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ +  if (neg) { \ +    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ +    if ((len -= vjlen) < 0) { \ +      goto bad; \ +    } \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != vjlen || \ +        citype != opt) { \ +      goto bad; \ +    } \ +    GETSHORT(cishort, p); \ +    if (cishort != val) { \ +      goto bad; \ +    } \ +    if (!old) { \ +      GETCHAR(cimaxslotindex, p); \ +      if (cimaxslotindex != maxslotindex) { \ +        goto bad; \ +      } \ +      GETCHAR(cicflag, p); \ +      if (cicflag != cflag) { \ +        goto bad; \ +      } \ +    } \ +  } +   +#define ACKCIADDR(opt, neg, old, val1, val2) \ +  if (neg) { \ +    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ +    u32_t l; \ +    if ((len -= addrlen) < 0) { \ +      goto bad; \ +    } \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != addrlen || \ +        citype != opt) { \ +      goto bad; \ +    } \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    if (val1 != cilong) { \ +      goto bad; \ +    } \ +    if (old) { \ +      GETLONG(l, p); \ +      cilong = htonl(l); \ +      if (val2 != cilong) { \ +        goto bad; \ +      } \ +    } \ +  } + +#define ACKCIDNS(opt, neg, addr) \ +  if (neg) { \ +    u32_t l; \ +    if ((len -= CILEN_ADDR) < 0) { \ +      goto bad; \ +    } \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_ADDR || \ +        citype != opt) { \ +      goto bad; \ +    } \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    if (addr != cilong) { \ +      goto bad; \ +    } \ +  } + +  ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, +        go->old_addrs, go->ouraddr, go->hisaddr); + +  ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, +      go->maxslotindex, go->cflag); + +  ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + +  ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); + +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  return (1); +   +bad: +  IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n")); +  return (0); +} + +/* + * ipcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if IPCP is in the LS_OPENED state. + * + * Returns: + *  0 - Nak was bad. + *  1 - Nak was good. + */ +static int +ipcp_nakci(fsm *f, u_char *p, int len) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  u_char cimaxslotindex, cicflag; +  u_char citype, cilen, *next; +  u_short cishort; +  u32_t ciaddr1, ciaddr2, l, cidnsaddr; +  ipcp_options no;    /* options we've seen Naks for */ +  ipcp_options try;    /* options to request next time */ + +  BZERO(&no, sizeof(no)); +  try = *go; + +  /* +   * Any Nak'd CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define NAKCIADDR(opt, neg, old, code) \ +  if (go->neg && \ +      len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \ +      p[1] == cilen && \ +      p[0] == opt) { \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    ciaddr1 = htonl(l); \ +    if (old) { \ +      GETLONG(l, p); \ +      ciaddr2 = htonl(l); \ +      no.old_addrs = 1; \ +    } else { \ +      ciaddr2 = 0; \ +    } \ +    no.neg = 1; \ +    code \ +  } + +#define NAKCIVJ(opt, neg, code) \ +  if (go->neg && \ +      ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ +      len >= cilen && \ +      p[0] == opt) { \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    no.neg = 1; \ +    code \ +  } +   +#define NAKCIDNS(opt, neg, code) \ +  if (go->neg && \ +      ((cilen = p[1]) == CILEN_ADDR) && \ +      len >= cilen && \ +      p[0] == opt) { \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    cidnsaddr = htonl(l); \ +    no.neg = 1; \ +    code \ +  } + +  /* +   * Accept the peer's idea of {our,his} address, if different +   * from our idea, only if the accept_{local,remote} flag is set. +   */ +  NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, +    if (go->accept_local && ciaddr1) { /* Do we know our address? */ +      try.ouraddr = ciaddr1; +      IPCPDEBUG((LOG_INFO, "local IP address %s\n", +           inet_ntoa(ciaddr1))); +    } +    if (go->accept_remote && ciaddr2) { /* Does he know his? */ +      try.hisaddr = ciaddr2; +      IPCPDEBUG((LOG_INFO, "remote IP address %s\n", +           inet_ntoa(ciaddr2))); +    } +  ); + +  /* +   * Accept the peer's value of maxslotindex provided that it +   * is less than what we asked for.  Turn off slot-ID compression +   * if the peer wants.  Send old-style compress-type option if +   * the peer wants. +   */ +  NAKCIVJ(CI_COMPRESSTYPE, neg_vj, +    if (cilen == CILEN_VJ) { +      GETCHAR(cimaxslotindex, p); +      GETCHAR(cicflag, p); +      if (cishort == IPCP_VJ_COMP) { +        try.old_vj = 0; +        if (cimaxslotindex < go->maxslotindex) { +          try.maxslotindex = cimaxslotindex; +        } +        if (!cicflag) { +          try.cflag = 0; +        } +      } else { +        try.neg_vj = 0; +      } +    } else { +      if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { +        try.old_vj = 1; +        try.vj_protocol = cishort; +      } else { +        try.neg_vj = 0; +      } +    } +  ); + +  NAKCIDNS(CI_MS_DNS1, req_dns1, +      try.dnsaddr[0] = cidnsaddr; +        IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr))); +      ); + +  NAKCIDNS(CI_MS_DNS2, req_dns2, +      try.dnsaddr[1] = cidnsaddr; +        IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr))); +      ); + +  /* +  * There may be remaining CIs, if the peer is requesting negotiation +  * on an option that we didn't include in our request packet. +  * If they want to negotiate about IP addresses, we comply. +  * If they want us to ask for compression, we refuse. +  */ +  while (len > CILEN_VOID) { +    GETCHAR(citype, p); +    GETCHAR(cilen, p); +    if( (len -= cilen) < 0 ) { +      goto bad; +    } +    next = p + cilen - 2; + +    switch (citype) { +      case CI_COMPRESSTYPE: +        if (go->neg_vj || no.neg_vj || +            (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { +          goto bad; +        } +        no.neg_vj = 1; +        break; +      case CI_ADDRS: +        if ((go->neg_addr && go->old_addrs) || no.old_addrs +            || cilen != CILEN_ADDRS) { +          goto bad; +        } +        try.neg_addr = 1; +        try.old_addrs = 1; +        GETLONG(l, p); +        ciaddr1 = htonl(l); +        if (ciaddr1 && go->accept_local) { +          try.ouraddr = ciaddr1; +        } +        GETLONG(l, p); +        ciaddr2 = htonl(l); +        if (ciaddr2 && go->accept_remote) { +          try.hisaddr = ciaddr2; +        } +        no.old_addrs = 1; +        break; +      case CI_ADDR: +        if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) { +          goto bad; +        } +        try.old_addrs = 0; +        GETLONG(l, p); +        ciaddr1 = htonl(l); +        if (ciaddr1 && go->accept_local) { +          try.ouraddr = ciaddr1; +        } +        if (try.ouraddr != 0) { +          try.neg_addr = 1; +        } +        no.neg_addr = 1; +        break; +    } +    p = next; +  } + +  /* If there is still anything left, this packet is bad. */ +  if (len != 0) { +    goto bad; +  } + +  /* +   * OK, the Nak is good.  Now we can update state. +   */ +  if (f->state != LS_OPENED) { +    *go = try; +  } + +  return 1; + +bad: +  IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n")); +  return 0; +} + + +/* + * ipcp_rejci - Reject some of our CIs. + */ +static int +ipcp_rejci(fsm *f, u_char *p, int len) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  u_char cimaxslotindex, ciflag, cilen; +  u_short cishort; +  u32_t cilong; +  ipcp_options try;    /* options to request next time */ + +  try = *go; +  /* +   * Any Rejected CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define REJCIADDR(opt, neg, old, val1, val2) \ +  if (go->neg && \ +      len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \ +      p[1] == cilen && \ +      p[0] == opt) { \ +    u32_t l; \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    /* Check rejected value. */ \ +    if (cilong != val1) { \ +      goto bad; \ +    } \ +    if (old) { \ +      GETLONG(l, p); \ +      cilong = htonl(l); \ +      /* Check rejected value. */ \ +      if (cilong != val2) { \ +        goto bad; \ +      } \ +    } \ +    try.neg = 0; \ +  } + +#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ +  if (go->neg && \ +      p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ +      len >= p[1] && \ +      p[0] == opt) { \ +    len -= p[1]; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    /* Check rejected value. */  \ +    if (cishort != val) { \ +      goto bad; \ +    } \ +    if (!old) { \ +      GETCHAR(cimaxslotindex, p); \ +      if (cimaxslotindex != maxslot) { \ +        goto bad; \ +      } \ +      GETCHAR(ciflag, p); \ +      if (ciflag != cflag) { \ +        goto bad; \ +      } \ +    } \ +    try.neg = 0; \ +  } + +#define REJCIDNS(opt, neg, dnsaddr) \ +  if (go->neg && \ +      ((cilen = p[1]) == CILEN_ADDR) && \ +      len >= cilen && \ +      p[0] == opt) { \ +    u32_t l; \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    /* Check rejected value. */ \ +    if (cilong != dnsaddr) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +  } + +  REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, +        go->old_addrs, go->ouraddr, go->hisaddr); + +  REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, +      go->maxslotindex, go->cflag); + +  REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); + +  REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); + +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  /* +   * Now we can update state. +   */ +  if (f->state != LS_OPENED) { +    *go = try; +  } +  return 1; + +bad: +  IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n")); +  return 0; +} + + +/* + * ipcp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately.  If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + */ +static int +ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree) +{ +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; +  ipcp_options *ho = &ipcp_hisoptions[f->unit]; +  ipcp_options *ao = &ipcp_allowoptions[f->unit]; +#ifdef OLD_CI_ADDRS +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +#endif +  u_char *cip, *next;     /* Pointer to current and next CIs */ +  u_short cilen, citype;  /* Parsed len, type */ +  u_short cishort;        /* Parsed short value */ +  u32_t tl, ciaddr1;      /* Parsed address values */ +#ifdef OLD_CI_ADDRS +  u32_t ciaddr2;          /* Parsed address values */ +#endif +  int rc = CONFACK;       /* Final packet return code */ +  int orc;                /* Individual option return code */ +  u_char *p;              /* Pointer to next char to parse */ +  u_char *ucp = inp;      /* Pointer to current output char */ +  int l = *len;           /* Length left */ +  u_char maxslotindex, cflag; +  int d; + +  cis_received[f->unit] = 1; + +  /* +   * Reset all his options. +   */ +  BZERO(ho, sizeof(*ho)); + +  /* +   * Process all his options. +   */ +  next = inp; +  while (l) { +    orc = CONFACK;       /* Assume success */ +    cip = p = next;      /* Remember begining of CI */ +    if (l < 2 ||         /* Not enough data for CI header or */ +        p[1] < 2 ||      /*  CI length too small or */ +        p[1] > l) {      /*  CI length too big? */ +      IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n")); +      orc = CONFREJ;     /* Reject bad CI */ +      cilen = l;         /* Reject till end of packet */ +      l = 0;             /* Don't loop again */ +      goto endswitch; +    } +    GETCHAR(citype, p);  /* Parse CI type */ +    GETCHAR(cilen, p);   /* Parse CI length */ +    l -= cilen;          /* Adjust remaining length */ +    next += cilen;       /* Step to next CI */ + +    switch (citype) {      /* Check CI type */ +#ifdef OLD_CI_ADDRS /* Need to save space... */ +      case CI_ADDRS: +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n")); +        if (!ao->neg_addr || +            cilen != CILEN_ADDRS) {  /* Check CI length */ +          orc = CONFREJ;    /* Reject CI */ +          break; +        } + +        /* +         * If he has no address, or if we both have his address but +         * disagree about it, then NAK it with our idea. +         * In particular, if we don't know his address, but he does, +         * then accept it. +         */ +        GETLONG(tl, p);    /* Parse source address (his) */ +        ciaddr1 = htonl(tl); +        IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1))); +        if (ciaddr1 != wo->hisaddr +            && (ciaddr1 == 0 || !wo->accept_remote)) { +          orc = CONFNAK; +          if (!reject_if_disagree) { +            DECPTR(sizeof(u32_t), p); +            tl = ntohl(wo->hisaddr); +            PUTLONG(tl, p); +          } +        } else if (ciaddr1 == 0 && wo->hisaddr == 0) { +          /* +           * If neither we nor he knows his address, reject the option. +           */ +          orc = CONFREJ; +          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */ +          break; +        } + +        /* +         * If he doesn't know our address, or if we both have our address +         * but disagree about it, then NAK it with our idea. +         */ +        GETLONG(tl, p);    /* Parse desination address (ours) */ +        ciaddr2 = htonl(tl); +        IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2))); +        if (ciaddr2 != wo->ouraddr) { +          if (ciaddr2 == 0 || !wo->accept_local) { +            orc = CONFNAK; +            if (!reject_if_disagree) { +              DECPTR(sizeof(u32_t), p); +              tl = ntohl(wo->ouraddr); +              PUTLONG(tl, p); +            } +          } else { +            go->ouraddr = ciaddr2;  /* accept peer's idea */ +          } +        } + +        ho->neg_addr = 1; +        ho->old_addrs = 1; +        ho->hisaddr = ciaddr1; +        ho->ouraddr = ciaddr2; +        break; +#endif + +      case CI_ADDR: +        if (!ao->neg_addr) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n")); +          orc = CONFREJ;        /* Reject CI */ +          break; +        } else if (cilen != CILEN_ADDR) {  /* Check CI length */ +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n")); +          orc = CONFREJ;        /* Reject CI */ +          break; +        } + +        /* +         * If he has no address, or if we both have his address but +         * disagree about it, then NAK it with our idea. +         * In particular, if we don't know his address, but he does, +         * then accept it. +         */ +        GETLONG(tl, p);  /* Parse source address (his) */ +        ciaddr1 = htonl(tl); +        if (ciaddr1 != wo->hisaddr +            && (ciaddr1 == 0 || !wo->accept_remote)) { +          orc = CONFNAK; +          if (!reject_if_disagree) { +            DECPTR(sizeof(u32_t), p); +            tl = ntohl(wo->hisaddr); +            PUTLONG(tl, p); +          } +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1))); +        } else if (ciaddr1 == 0 && wo->hisaddr == 0) { +          /* +           * Don't ACK an address of 0.0.0.0 - reject it instead. +           */ +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1))); +          orc = CONFREJ; +          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */ +          break; +        } + +        ho->neg_addr = 1; +        ho->hisaddr = ciaddr1; +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1))); +        break; + +      case CI_MS_DNS1: +      case CI_MS_DNS2: +        /* Microsoft primary or secondary DNS request */ +        d = citype == CI_MS_DNS2; + +        /* If we do not have a DNS address then we cannot send it */ +        if (ao->dnsaddr[d] == 0 || +            cilen != CILEN_ADDR) {  /* Check CI length */ +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1)); +          orc = CONFREJ;        /* Reject CI */ +          break; +        } +        GETLONG(tl, p); +        if (htonl(tl) != ao->dnsaddr[d]) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n", +                d+1, inet_ntoa(tl))); +          DECPTR(sizeof(u32_t), p); +          tl = ntohl(ao->dnsaddr[d]); +          PUTLONG(tl, p); +          orc = CONFNAK; +        } +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1)); +        break; + +      case CI_MS_WINS1: +      case CI_MS_WINS2: +        /* Microsoft primary or secondary WINS request */ +        d = citype == CI_MS_WINS2; +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1)); + +        /* If we do not have a DNS address then we cannot send it */ +        if (ao->winsaddr[d] == 0 || +          cilen != CILEN_ADDR) {  /* Check CI length */ +          orc = CONFREJ;      /* Reject CI */ +          break; +        } +        GETLONG(tl, p); +        if (htonl(tl) != ao->winsaddr[d]) { +          DECPTR(sizeof(u32_t), p); +          tl = ntohl(ao->winsaddr[d]); +          PUTLONG(tl, p); +          orc = CONFNAK; +        } +        break; + +      case CI_COMPRESSTYPE: +        if (!ao->neg_vj) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n")); +          orc = CONFREJ; +          break; +        } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen)); +          orc = CONFREJ; +          break; +        } +        GETSHORT(cishort, p); + +        if (!(cishort == IPCP_VJ_COMP || +            (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort)); +          orc = CONFREJ; +          break; +        } + +        ho->neg_vj = 1; +        ho->vj_protocol = cishort; +        if (cilen == CILEN_VJ) { +          GETCHAR(maxslotindex, p); +          if (maxslotindex > ao->maxslotindex) {  +            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex)); +            orc = CONFNAK; +            if (!reject_if_disagree) { +              DECPTR(1, p); +              PUTCHAR(ao->maxslotindex, p); +            } +          } +          GETCHAR(cflag, p); +          if (cflag && !ao->cflag) { +            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag)); +            orc = CONFNAK; +            if (!reject_if_disagree) { +              DECPTR(1, p); +              PUTCHAR(wo->cflag, p); +            } +          } +          ho->maxslotindex = maxslotindex; +          ho->cflag = cflag; +        } else { +          ho->old_vj = 1; +          ho->maxslotindex = MAX_SLOTS - 1; +          ho->cflag = 1; +        } +        IPCPDEBUG((LOG_INFO,  +              "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n", +              ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag)); +        break; + +      default: +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype)); +        orc = CONFREJ; +        break; +    } + +endswitch: +    if (orc == CONFACK &&    /* Good CI */ +        rc != CONFACK) {     /*  but prior CI wasnt? */ +      continue;              /* Don't send this one */ +    } + +    if (orc == CONFNAK) {    /* Nak this CI? */ +      if (reject_if_disagree) {  /* Getting fed up with sending NAKs? */ +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n")); +        orc = CONFREJ;       /* Get tough if so */ +      } else { +        if (rc == CONFREJ) { /* Rejecting prior CI? */ +          continue;          /* Don't send this one */ +        } +        if (rc == CONFACK) { /* Ack'd all prior CIs? */ +          rc = CONFNAK;      /* Not anymore... */ +          ucp = inp;         /* Backup */ +        } +      } +    } + +    if (orc == CONFREJ &&    /* Reject this CI */ +        rc != CONFREJ) {  /*  but no prior ones? */ +      rc = CONFREJ; +      ucp = inp;        /* Backup */ +    } +     +    /* Need to move CI? */ +    if (ucp != cip) { +      BCOPY(cip, ucp, cilen);  /* Move it */ +    } + +    /* Update output pointer */ +    INCPTR(cilen, ucp); +  } + +  /* +   * If we aren't rejecting this packet, and we want to negotiate +   * their address, and they didn't send their address, then we +   * send a NAK with a CI_ADDR option appended.  We assume the +   * input buffer is long enough that we can append the extra +   * option safely. +   */ +  if (rc != CONFREJ && !ho->neg_addr && +      wo->req_addr && !reject_if_disagree) { +    IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n")); +    if (rc == CONFACK) { +      rc = CONFNAK; +      ucp = inp;        /* reset pointer */ +      wo->req_addr = 0;    /* don't ask again */ +    } +    PUTCHAR(CI_ADDR, ucp); +    PUTCHAR(CILEN_ADDR, ucp); +    tl = ntohl(wo->hisaddr); +    PUTLONG(tl, ucp); +  } + +  *len = (int)(ucp - inp);    /* Compute output length */ +  IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc))); +  return (rc);      /* Return final code */ +} + + +#if 0 +/* + * ip_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void +ip_check_options(u_long localAddr) +{ +  ipcp_options *wo = &ipcp_wantoptions[0]; + +  /* +   * Load our default IP address but allow the remote host to give us +   * a new address. +   */ +  if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) { +    wo->accept_local = 1;  /* don't insist on this default value */ +    wo->ouraddr = htonl(localAddr); +  } +} +#endif + + +/* + * ipcp_up - IPCP has come UP. + * + * Configure the IP network interface appropriately and bring it up. + */ +static void +ipcp_up(fsm *f) +{ +  u32_t mask; +  ipcp_options *ho = &ipcp_hisoptions[f->unit]; +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; + +  np_up(f->unit, PPP_IP); +  IPCPDEBUG((LOG_INFO, "ipcp: up\n")); + +  /* +   * We must have a non-zero IP address for both ends of the link. +   */ +  if (!ho->neg_addr) { +    ho->hisaddr = wo->hisaddr; +  } + +  if (ho->hisaddr == 0) { +    IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n")); +    ipcp_close(f->unit, "Could not determine remote IP address"); +    return; +  } +  if (go->ouraddr == 0) { +    IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n")); +    ipcp_close(f->unit, "Could not determine local IP address"); +    return; +  } + +  if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { +    /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/ +  } + +  /* +   * Check that the peer is allowed to use the IP address it wants. +   */ +  if (!auth_ip_addr(f->unit, ho->hisaddr)) { +    IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n", +        inet_ntoa(ho->hisaddr))); +    ipcp_close(f->unit, "Unauthorized remote IP address"); +    return; +  } + +  /* set tcp compression */ +  sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); + +  /* +   * Set IP addresses and (if specified) netmask. +   */ +  mask = GetMask(go->ouraddr); + +  if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) { +    IPCPDEBUG((LOG_WARNING, "sifaddr failed\n")); +    ipcp_close(f->unit, "Interface configuration failed"); +    return; +  } + +  /* bring the interface up for IP */ +  if (!sifup(f->unit)) { +    IPCPDEBUG((LOG_WARNING, "sifup failed\n")); +    ipcp_close(f->unit, "Interface configuration failed"); +    return; +  } + +  sifnpmode(f->unit, PPP_IP, NPMODE_PASS); + +  /* assign a default route through the interface if required */ +  if (ipcp_wantoptions[f->unit].default_route) { +    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) { +      default_route_set[f->unit] = 1; +    } +  } + +  IPCPDEBUG((LOG_NOTICE, "local  IP address %s\n", inet_ntoa(go->ouraddr))); +  IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr))); +  if (go->dnsaddr[0]) { +    IPCPDEBUG((LOG_NOTICE, "primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0]))); +  } +  if (go->dnsaddr[1]) { +    IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1]))); +  } +} + + +/* + * ipcp_down - IPCP has gone DOWN. + * + * Take the IP network interface down, clear its addresses + * and delete routes through it. + */ +static void +ipcp_down(fsm *f) +{ +  IPCPDEBUG((LOG_INFO, "ipcp: down\n")); +  np_down(f->unit, PPP_IP); +  sifvjcomp(f->unit, 0, 0, 0); + +  sifdown(f->unit); +  ipcp_clear_addrs(f->unit); +} + + +/* + * ipcp_clear_addrs() - clear the interface addresses, routes, etc. + */ +static void +ipcp_clear_addrs(int unit) +{ +  u32_t ouraddr, hisaddr; + +  ouraddr = ipcp_gotoptions[unit].ouraddr; +  hisaddr = ipcp_hisoptions[unit].hisaddr; +  if (default_route_set[unit]) { +    cifdefaultroute(unit, ouraddr, hisaddr); +    default_route_set[unit] = 0; +  } +  cifaddr(unit, ouraddr, hisaddr); +} + + +/* + * ipcp_finished - possibly shut down the lower layers. + */ +static void +ipcp_finished(fsm *f) +{ +  np_finished(f->unit, PPP_IP); +} + +#if 0 +static int +ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ +  LWIP_UNUSED_ARG(p); +  LWIP_UNUSED_ARG(plen); +  LWIP_UNUSED_ARG(printer); +  LWIP_UNUSED_ARG(arg); +  return 0; +} + +/* + * ip_active_pkt - see if this IP packet is worth bringing the link up for. + * We don't bring the link up for IP fragments or for TCP FIN packets + * with no data. + */ +#define IP_HDRLEN   20  /* bytes */ +#define IP_OFFMASK  0x1fff +#define IPPROTO_TCP 6 +#define TCP_HDRLEN  20 +#define TH_FIN      0x01 + +/* + * We use these macros because the IP header may be at an odd address, + * and some compilers might use word loads to get th_off or ip_hl. + */ + +#define net_short(x)    (((x)[0] << 8) + (x)[1]) +#define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF) +#define get_ipoff(x)    net_short((unsigned char *)(x) + 6) +#define get_ipproto(x)  (((unsigned char *)(x))[9]) +#define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4) +#define get_tcpflags(x) (((unsigned char *)(x))[13]) + +static int +ip_active_pkt(u_char *pkt, int len) +{ +  u_char *tcp; +  int hlen; + +  len -= PPP_HDRLEN; +  pkt += PPP_HDRLEN; +  if (len < IP_HDRLEN) { +    return 0; +  } +  if ((get_ipoff(pkt) & IP_OFFMASK) != 0) { +    return 0; +  } +  if (get_ipproto(pkt) != IPPROTO_TCP) { +    return 1; +  } +  hlen = get_iphl(pkt) * 4; +  if (len < hlen + TCP_HDRLEN) { +    return 0; +  } +  tcp = pkt + hlen; +  if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) { +    return 0; +  } +  return 1; +} +#endif + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h new file mode 100644 index 000000000..dfcf4fba6 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h @@ -0,0 +1,124 @@ +/***************************************************************************** +* ipcp.h -  PPP IP NCP: Internet Protocol Network Control Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ipcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef IPCP_H +#define IPCP_H + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ +/* + * Options. + */ +#define CI_ADDRS            1      /* IP Addresses */ +#define CI_COMPRESSTYPE     2      /* Compression Type */ +#define CI_ADDR             3 + +#define CI_MS_WINS1         128    /* Primary WINS value */ +#define CI_MS_DNS1          129    /* Primary DNS value */ +#define CI_MS_WINS2         130    /* Secondary WINS value */ +#define CI_MS_DNS2          131    /* Secondary DNS value */ + +#define IPCP_VJMODE_OLD     1      /* "old" mode (option # = 0x0037) */ +#define IPCP_VJMODE_RFC1172 2      /* "old-rfc"mode (option # = 0x002d) */ +#define IPCP_VJMODE_RFC1332 3      /* "new-rfc"mode (option # = 0x002d, */ +                                   /*  maxslot and slot number compression) */ + +#define IPCP_VJ_COMP        0x002d /* current value for VJ compression option */ +#define IPCP_VJ_COMP_OLD    0x0037 /* "old" (i.e, broken) value for VJ */ +                                   /* compression option */  + + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +typedef struct ipcp_options { +  u_int   neg_addr      : 1; /* Negotiate IP Address? */ +  u_int   old_addrs     : 1; /* Use old (IP-Addresses) option? */ +  u_int   req_addr      : 1; /* Ask peer to send IP address? */ +  u_int   default_route : 1; /* Assign default route through interface? */ +  u_int   proxy_arp     : 1; /* Make proxy ARP entry for peer? */ +  u_int   neg_vj        : 1; /* Van Jacobson Compression? */ +  u_int   old_vj        : 1; /* use old (short) form of VJ option? */ +  u_int   accept_local  : 1; /* accept peer's value for ouraddr */ +  u_int   accept_remote : 1; /* accept peer's value for hisaddr */ +  u_int   req_dns1      : 1; /* Ask peer to send primary DNS address? */ +  u_int   req_dns2      : 1; /* Ask peer to send secondary DNS address? */ +  u_short vj_protocol;       /* protocol value to use in VJ option */ +  u_char  maxslotindex;      /* VJ slots - 1. */ +  u_char  cflag;             /* VJ slot compression flag. */ +  u32_t   ouraddr, hisaddr;  /* Addresses in NETWORK BYTE ORDER */ +  u32_t   dnsaddr[2];        /* Primary and secondary MS DNS entries */ +  u32_t   winsaddr[2];       /* Primary and secondary MS WINS entries */ +} ipcp_options; + + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +extern fsm ipcp_fsm[]; +extern ipcp_options ipcp_wantoptions[]; +extern ipcp_options ipcp_gotoptions[]; +extern ipcp_options ipcp_allowoptions[]; +extern ipcp_options ipcp_hisoptions[]; + +extern struct protent ipcp_protent; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +#endif /* IPCP_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/lcp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/lcp.c new file mode 100644 index 000000000..85a0add95 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/lcp.c @@ -0,0 +1,2035 @@ +/***************************************************************************** +* lcp.c - Network Link Control Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ + +/* + * lcp.c - PPP Link Control Protocol. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +  + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "fsm.h" +#include "chap.h" +#include "magic.h" +#include "auth.h" +#include "lcp.h" + +#include <string.h> + +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#else +#define PPPOE_MAXMTU PPP_MAXMRU +#endif + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ +/* + * Length of each type of configuration option (in octets) + */ +#define CILEN_VOID  2 +#define CILEN_CHAR  3 +#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ +#define CILEN_CHAP  5 /* CILEN_VOID + sizeof(short) + 1 */ +#define CILEN_LONG  6 /* CILEN_VOID + sizeof(long) */ +#define CILEN_LQR   8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ +#define CILEN_CBCP  3 + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Callbacks for fsm code.  (CI = Configuration Information) + */ +static void lcp_resetci (fsm*);                   /* Reset our CI */ +static int  lcp_cilen (fsm*);                     /* Return length of our CI */ +static void lcp_addci (fsm*, u_char*, int*);      /* Add our CI to pkt */ +static int  lcp_ackci (fsm*, u_char*, int);       /* Peer ack'd our CI */ +static int  lcp_nakci (fsm*, u_char*, int);       /* Peer nak'd our CI */ +static int  lcp_rejci (fsm*, u_char*, int);       /* Peer rej'd our CI */ +static int  lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */ +static void lcp_up (fsm*);                        /* We're UP */ +static void lcp_down (fsm*);                      /* We're DOWN */ +static void lcp_starting (fsm*);                  /* We need lower layer up */ +static void lcp_finished (fsm*);                  /* We need lower layer down */ +static int  lcp_extcode (fsm*, int, u_char, u_char*, int); + +static void lcp_rprotrej (fsm*, u_char*, int); + +/* + * routines to send LCP echos to peer + */ +static void lcp_echo_lowerup (int); +static void lcp_echo_lowerdown (int); +static void LcpEchoTimeout (void*); +static void lcp_received_echo_reply (fsm*, int, u_char*, int); +static void LcpSendEchoRequest (fsm*); +static void LcpLinkFailure (fsm*); +static void LcpEchoCheck (fsm*); + +/* + * Protocol entry points. + * Some of these are called directly. + */ +static void lcp_input (int, u_char *, int); +static void lcp_protrej (int); + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ") + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +/* global vars */ +LinkPhase lcp_phase[NUM_PPP];          /* Phase of link session (RFC 1661) */ +lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */ +lcp_options lcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */ +lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +lcp_options lcp_hisoptions[NUM_PPP];   /* Options that we ack'd */ +ext_accm xmit_accm[NUM_PPP];           /* extended transmit ACCM */ + + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static fsm lcp_fsm[NUM_PPP];                            /* LCP fsm structure (global)*/ +static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ +static u_int lcp_echo_fails         = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ +static u32_t lcp_echos_pending      = 0;                /* Number of outstanding echo msgs */ +static u32_t lcp_echo_number        = 0;                /* ID number of next echo frame */ +static u32_t lcp_echo_timer_running = 0;                /* TRUE if a timer is running */ + +static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ + +static fsm_callbacks lcp_callbacks = { /* LCP callback routines */ +  lcp_resetci,  /* Reset our Configuration Information */ +  lcp_cilen,    /* Length of our Configuration Information */ +  lcp_addci,    /* Add our Configuration Information */ +  lcp_ackci,    /* ACK our Configuration Information */ +  lcp_nakci,    /* NAK our Configuration Information */ +  lcp_rejci,    /* Reject our Configuration Information */ +  lcp_reqci,    /* Request peer's Configuration Information */ +  lcp_up,       /* Called when fsm reaches LS_OPENED state */ +  lcp_down,     /* Called when fsm leaves LS_OPENED state */ +  lcp_starting, /* Called when we want the lower layer up */ +  lcp_finished, /* Called when we want the lower layer down */ +  NULL,         /* Called when Protocol-Reject received */ +  NULL,         /* Retransmission is necessary */ +  lcp_extcode,  /* Called to handle LCP-specific codes */ +  "LCP"         /* String name of protocol */ +}; + +struct protent lcp_protent = { +    PPP_LCP, +    lcp_init, +    lcp_input, +    lcp_protrej, +    lcp_lowerup, +    lcp_lowerdown, +    lcp_open, +    lcp_close, +#if 0 +    lcp_printpkt, +    NULL, +#endif +    1, +    "LCP", +#if 0 +    NULL, +    NULL, +    NULL +#endif +}; + +int lcp_loopbackfail = DEFLOOPBACKFAIL; + + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * lcp_init - Initialize LCP. + */ +void +lcp_init(int unit) +{ +  fsm         *f  = &lcp_fsm[unit]; +  lcp_options *wo = &lcp_wantoptions[unit]; +  lcp_options *ao = &lcp_allowoptions[unit]; +   +  f->unit      = unit; +  f->protocol  = PPP_LCP; +  f->callbacks = &lcp_callbacks; +   +  fsm_init(f); +   +  wo->passive           = 0; +  wo->silent            = 0; +  wo->restart           = 0;               /* Set to 1 in kernels or multi-line implementations */ +  wo->neg_mru           = 1; +  wo->mru               = PPP_DEFMRU; +  wo->neg_asyncmap      = 1; +  wo->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */ +  wo->neg_chap          = 0;               /* Set to 1 on server */ +  wo->neg_upap          = 0;               /* Set to 1 on server */ +  wo->chap_mdtype       = CHAP_DIGEST_MD5; +  wo->neg_magicnumber   = 1; +  wo->neg_pcompression  = 1; +  wo->neg_accompression = 1; +  wo->neg_lqr           = 0;               /* no LQR implementation yet */ +  wo->neg_cbcp          = 0; +   +  ao->neg_mru           = 1; +  ao->mru               = PPP_MAXMRU; +  ao->neg_asyncmap      = 1; +  ao->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */ +  ao->neg_chap          = (CHAP_SUPPORT != 0); +  ao->chap_mdtype       = CHAP_DIGEST_MD5; +  ao->neg_upap          = (PAP_SUPPORT != 0); +  ao->neg_magicnumber   = 1; +  ao->neg_pcompression  = 1; +  ao->neg_accompression = 1; +  ao->neg_lqr           = 0;               /* no LQR implementation yet */ +  ao->neg_cbcp          = (CBCP_SUPPORT != 0); + +  /*  +   * Set transmit escape for the flag and escape characters plus anything +   * set for the allowable options. +   */ +  memset(xmit_accm[unit], 0, sizeof(xmit_accm[0])); +  xmit_accm[unit][15] = 0x60; +  xmit_accm[unit][0]  = (u_char)((ao->asyncmap        & 0xFF)); +  xmit_accm[unit][1]  = (u_char)((ao->asyncmap >> 8)  & 0xFF); +  xmit_accm[unit][2]  = (u_char)((ao->asyncmap >> 16) & 0xFF); +  xmit_accm[unit][3]  = (u_char)((ao->asyncmap >> 24) & 0xFF); +  LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n", +        xmit_accm[unit][0], +        xmit_accm[unit][1], +        xmit_accm[unit][2], +        xmit_accm[unit][3])); +   +  lcp_phase[unit] = PHASE_INITIALIZE; +} + + +/* + * lcp_open - LCP is allowed to come up. + */ +void +lcp_open(int unit) +{ +  fsm         *f  = &lcp_fsm[unit]; +  lcp_options *wo = &lcp_wantoptions[unit]; + +  f->flags = 0; +  if (wo->passive) { +    f->flags |= OPT_PASSIVE; +  } +  if (wo->silent) { +    f->flags |= OPT_SILENT; +  } +  fsm_open(f); + +  lcp_phase[unit] = PHASE_ESTABLISH; +} + + +/* + * lcp_close - Take LCP down. + */ +void +lcp_close(int unit, char *reason) +{ +  fsm *f = &lcp_fsm[unit]; + +  if (lcp_phase[unit] != PHASE_DEAD) { +    lcp_phase[unit] = PHASE_TERMINATE; +  } +  if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { +    /* +     * This action is not strictly according to the FSM in RFC1548, +     * but it does mean that the program terminates if you do an +     * lcp_close() in passive/silent mode when a connection hasn't +     * been established. +     */ +    f->state = LS_CLOSED; +    lcp_finished(f); +  } else { +    fsm_close(&lcp_fsm[unit], reason); +  } +} + + +/* + * lcp_lowerup - The lower layer is up. + */ +void +lcp_lowerup(int unit) +{ +  lcp_options *wo = &lcp_wantoptions[unit]; + +  /* +   * Don't use A/C or protocol compression on transmission, +   * but accept A/C and protocol compressed packets +   * if we are going to ask for A/C and protocol compression. +   */ +  ppp_set_xaccm(unit, &xmit_accm[unit]); +  ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0); +  ppp_recv_config(unit, PPP_MRU, 0x00000000l, +  wo->neg_pcompression, wo->neg_accompression); +  peer_mru[unit] = PPP_MRU; +  lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0] +                                 | ((u_long)xmit_accm[unit][1] << 8) +                                 | ((u_long)xmit_accm[unit][2] << 16) +                                 | ((u_long)xmit_accm[unit][3] << 24); +  LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n", +            xmit_accm[unit][3], +            xmit_accm[unit][2], +            xmit_accm[unit][1], +            xmit_accm[unit][0])); + +  fsm_lowerup(&lcp_fsm[unit]); +} + + +/* + * lcp_lowerdown - The lower layer is down. + */ +void +lcp_lowerdown(int unit) +{ +  fsm_lowerdown(&lcp_fsm[unit]); +} + +/* + * lcp_sprotrej - Send a Protocol-Reject for some protocol. + */ +void +lcp_sprotrej(int unit, u_char *p, int len) +{ +  /* +   * Send back the protocol and the information field of the +   * rejected packet.  We only get here if LCP is in the LS_OPENED state. +   */ + +  fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len); +} + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * lcp_input - Input LCP packet. + */ +static void +lcp_input(int unit, u_char *p, int len) +{ +  fsm *f = &lcp_fsm[unit]; + +  fsm_input(f, p, len); +} + + +/* + * lcp_extcode - Handle a LCP-specific code. + */ +static int +lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len) +{ +  u_char *magp; + +  switch( code ){ +    case PROTREJ: +      lcp_rprotrej(f, inp, len); +      break; +   +    case ECHOREQ: +      if (f->state != LS_OPENED) { +        break; +      } +      LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id)); +      magp = inp; +      PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp); +      fsm_sdata(f, ECHOREP, id, inp, len); +      break; + +    case ECHOREP: +      lcp_received_echo_reply(f, id, inp, len); +      break; +     +    case DISCREQ: +      break; +     +    default: +      return 0; +  } +  return 1; +} + + +/* + * lcp_rprotrej - Receive an Protocol-Reject. + * + * Figure out which protocol is rejected and inform it. + */ +static void +lcp_rprotrej(fsm *f, u_char *inp, int len) +{ +  int i; +  struct protent *protp; +  u_short prot; + +  if (len < sizeof (u_short)) { +    LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n")); +    return; +  } + +  GETSHORT(prot, inp); + +  LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot)); + +  /* +   * Protocol-Reject packets received in any state other than the LCP +   * LS_OPENED state SHOULD be silently discarded. +   */ +  if( f->state != LS_OPENED ) { +    LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n", f->state)); +    return; +  } + +  /* +   * Upcall the proper Protocol-Reject routine. +   */ +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (protp->protocol == prot && protp->enabled_flag) { +      (*protp->protrej)(f->unit); +      return; +    } +  } + +  LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n", prot)); +} + + +/* + * lcp_protrej - A Protocol-Reject was received. + */ +static void +lcp_protrej(int unit) +{ +  LWIP_UNUSED_ARG(unit); +  /* +   * Can't reject LCP! +   */ +  LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!\n")); +  fsm_protreject(&lcp_fsm[unit]); +} + + +/* + * lcp_resetci - Reset our CI. + */ +static void +lcp_resetci(fsm *f) +{ +  lcp_wantoptions[f->unit].magicnumber = magic(); +  lcp_wantoptions[f->unit].numloops = 0; +  lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit]; +  peer_mru[f->unit] = PPP_MRU; +  auth_reset(f->unit); +} + + +/* + * lcp_cilen - Return length of our CI. + */ +static int lcp_cilen(fsm *f) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; + +#define LENCIVOID(neg)  ((neg) ? CILEN_VOID : 0) +#define LENCICHAP(neg)  ((neg) ? CILEN_CHAP : 0) +#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) +#define LENCILONG(neg)  ((neg) ? CILEN_LONG : 0) +#define LENCILQR(neg)   ((neg) ? CILEN_LQR: 0) +#define LENCICBCP(neg)  ((neg) ? CILEN_CBCP: 0) +  /* +   * NB: we only ask for one of CHAP and UPAP, even if we will +   * accept either. +   */ +  return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) + +          LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) + +          LENCICHAP(go->neg_chap) + +          LENCISHORT(!go->neg_chap && go->neg_upap) + +          LENCILQR(go->neg_lqr) + +          LENCICBCP(go->neg_cbcp) + +          LENCILONG(go->neg_magicnumber) + +          LENCIVOID(go->neg_pcompression) + +          LENCIVOID(go->neg_accompression)); +} + + +/* + * lcp_addci - Add our desired CIs to a packet. + */ +static void +lcp_addci(fsm *f, u_char *ucp, int *lenp) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  u_char *start_ucp = ucp; + +#define ADDCIVOID(opt, neg) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_VOID, ucp); \ +  } +#define ADDCISHORT(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_SHORT, ucp); \ +    PUTSHORT(val, ucp); \ +  } +#define ADDCICHAP(opt, neg, val, digest) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_CHAP, ucp); \ +    PUTSHORT(val, ucp); \ +    PUTCHAR(digest, ucp); \ +  } +#define ADDCILONG(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_LONG, ucp); \ +    PUTLONG(val, ucp); \ +  } +#define ADDCILQR(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_LQR, ucp); \ +    PUTSHORT(PPP_LQR, ucp); \ +    PUTLONG(val, ucp); \ +  } +#define ADDCICHAR(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_CHAR, ucp); \ +    PUTCHAR(val, ucp); \ +  } + +  ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); +  ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); +  ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); +  ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +  ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +  ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); +  ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); +  ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); +  ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); + +  if (ucp - start_ucp != *lenp) { +    /* this should never happen, because peer_mtu should be 1500 */ +    LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n")); +  } +} + + +/* + * lcp_ackci - Ack our CIs. + * This should not modify any state if the Ack is bad. + * + * Returns: + *  0 - Ack was bad. + *  1 - Ack was good. + */ +static int +lcp_ackci(fsm *f, u_char *p, int len) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  u_char cilen, citype, cichar; +  u_short cishort; +  u32_t cilong; + +  /* +   * CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define ACKCIVOID(opt, neg) \ +  if (neg) { \ +    if ((len -= CILEN_VOID) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_VOID || citype != opt) \ +      goto bad; \ +  } +#define ACKCISHORT(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_SHORT) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_SHORT || citype != opt) \ +      goto bad; \ +    GETSHORT(cishort, p); \ +    if (cishort != val) \ +      goto bad; \ +  } +#define ACKCICHAR(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_CHAR) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_CHAR || citype != opt) \ +      goto bad; \ +    GETCHAR(cichar, p); \ +    if (cichar != val) \ +      goto bad; \ +  } +#define ACKCICHAP(opt, neg, val, digest) \ +  if (neg) { \ +    if ((len -= CILEN_CHAP) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_CHAP || citype != opt) \ +      goto bad; \ +    GETSHORT(cishort, p); \ +    if (cishort != val) \ +      goto bad; \ +    GETCHAR(cichar, p); \ +    if (cichar != digest) \ +      goto bad; \ +  } +#define ACKCILONG(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_LONG) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_LONG ||  citype != opt) \ +      goto bad; \ +    GETLONG(cilong, p); \ +    if (cilong != val) \ +      goto bad; \ +  } +#define ACKCILQR(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_LQR) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_LQR || citype != opt) \ +      goto bad; \ +    GETSHORT(cishort, p); \ +    if (cishort != PPP_LQR) \ +      goto bad; \ +    GETLONG(cilong, p); \ +    if (cilong != val) \ +      goto bad; \ +  } + +  ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); +  ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); +  ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); +  ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +  ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +  ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); +  ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); +  ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); +  ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); + +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n")); +  return (1); +bad: +  LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n")); +  return (0); +} + + +/* + * lcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if LCP is in the LS_OPENED state. + * + * Returns: + *  0 - Nak was bad. + *  1 - Nak was good. + */ +static int +lcp_nakci(fsm *f, u_char *p, int len) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  lcp_options *wo = &lcp_wantoptions[f->unit]; +  u_char citype, cichar, *next; +  u_short cishort; +  u32_t cilong; +  lcp_options no;     /* options we've seen Naks for */ +  lcp_options try;    /* options to request next time */ +  int looped_back = 0; +  int cilen; + +  BZERO(&no, sizeof(no)); +  try = *go; + +  /* +   * Any Nak'd CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define NAKCIVOID(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_VOID && \ +      p[1] == CILEN_VOID && \ +      p[0] == opt) { \ +    len -= CILEN_VOID; \ +    INCPTR(CILEN_VOID, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCICHAP(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_CHAP && \ +      p[1] == CILEN_CHAP && \ +      p[0] == opt) { \ +    len -= CILEN_CHAP; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETCHAR(cichar, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCICHAR(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_CHAR && \ +      p[1] == CILEN_CHAR && \ +      p[0] == opt) { \ +    len -= CILEN_CHAR; \ +    INCPTR(2, p); \ +    GETCHAR(cichar, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCISHORT(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_SHORT && \ +      p[1] == CILEN_SHORT && \ +      p[0] == opt) { \ +    len -= CILEN_SHORT; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCILONG(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_LONG && \ +      p[1] == CILEN_LONG && \ +      p[0] == opt) { \ +    len -= CILEN_LONG; \ +    INCPTR(2, p); \ +    GETLONG(cilong, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCILQR(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_LQR && \ +      p[1] == CILEN_LQR && \ +      p[0] == opt) { \ +    len -= CILEN_LQR; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETLONG(cilong, p); \ +    no.neg = 1; \ +    code \ +  } + +  /* +   * We don't care if they want to send us smaller packets than +   * we want.  Therefore, accept any MRU less than what we asked for, +   * but then ignore the new value when setting the MRU in the kernel. +   * If they send us a bigger MRU than what we asked, accept it, up to +   * the limit of the default MRU we'd get if we didn't negotiate. +   */ +  if (go->neg_mru && go->mru != PPP_DEFMRU) { +    NAKCISHORT(CI_MRU, neg_mru, +      if (cishort <= wo->mru || cishort < PPP_DEFMRU) { +        try.mru = cishort; +      } +    ); +  } + +  /* +   * Add any characters they want to our (receive-side) asyncmap. +   */ +  if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) { +    NAKCILONG(CI_ASYNCMAP, neg_asyncmap, +      try.asyncmap = go->asyncmap | cilong; +    ); +  } + +  /* +   * If they've nak'd our authentication-protocol, check whether +   * they are proposing a different protocol, or a different +   * hash algorithm for CHAP. +   */ +  if ((go->neg_chap || go->neg_upap) +      && len >= CILEN_SHORT +      && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { +    cilen = p[1]; +    len -= cilen; +    no.neg_chap = go->neg_chap; +    no.neg_upap = go->neg_upap; +    INCPTR(2, p); +    GETSHORT(cishort, p); +    if (cishort == PPP_PAP && cilen == CILEN_SHORT) { +      /* +       * If we were asking for CHAP, they obviously don't want to do it. +       * If we weren't asking for CHAP, then we were asking for PAP, +       * in which case this Nak is bad. +       */ +      if (!go->neg_chap) { +        goto bad; +      } +      try.neg_chap = 0; +     +    } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { +      GETCHAR(cichar, p); +      if (go->neg_chap) { +        /* +         * We were asking for CHAP/MD5; they must want a different +         * algorithm.  If they can't do MD5, we'll have to stop +         * asking for CHAP. +         */ +        if (cichar != go->chap_mdtype) { +          try.neg_chap = 0; +        } +      } else { +        /* +         * Stop asking for PAP if we were asking for it. +         */ +        try.neg_upap = 0; +      } +     +    } else { +      /* +       * We don't recognize what they're suggesting. +       * Stop asking for what we were asking for. +       */ +      if (go->neg_chap) { +        try.neg_chap = 0; +      } else { +        try.neg_upap = 0; +      } +      p += cilen - CILEN_SHORT; +    } +  } + +  /* +   * If they can't cope with our link quality protocol, we'll have +   * to stop asking for LQR.  We haven't got any other protocol. +   * If they Nak the reporting period, take their value XXX ? +   */ +  NAKCILQR(CI_QUALITY, neg_lqr, +    if (cishort != PPP_LQR) { +      try.neg_lqr = 0; +    } else { +      try.lqr_period = cilong; +    } +  ); + +  /* +   * Only implementing CBCP...not the rest of the callback options +   */ +  NAKCICHAR(CI_CALLBACK, neg_cbcp, +    try.neg_cbcp = 0; +  ); + +  /* +   * Check for a looped-back line. +   */ +  NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, +    try.magicnumber = magic(); +    looped_back = 1; +  ); + +  /* +   * Peer shouldn't send Nak for protocol compression or +   * address/control compression requests; they should send +   * a Reject instead.  If they send a Nak, treat it as a Reject. +   */ +  NAKCIVOID(CI_PCOMPRESSION, neg_pcompression, +    try.neg_pcompression = 0; +  ); +  NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, +    try.neg_accompression = 0; +  ); + +  /* +   * There may be remaining CIs, if the peer is requesting negotiation +   * on an option that we didn't include in our request packet. +   * If we see an option that we requested, or one we've already seen +   * in this packet, then this packet is bad. +   * If we wanted to respond by starting to negotiate on the requested +   * option(s), we could, but we don't, because except for the +   * authentication type and quality protocol, if we are not negotiating +   * an option, it is because we were told not to. +   * For the authentication type, the Nak from the peer means +   * `let me authenticate myself with you' which is a bit pointless. +   * For the quality protocol, the Nak means `ask me to send you quality +   * reports', but if we didn't ask for them, we don't want them. +   * An option we don't recognize represents the peer asking to +   * negotiate some option we don't support, so ignore it. +   */ +  while (len > CILEN_VOID) { +    GETCHAR(citype, p); +    GETCHAR(cilen, p); +    if (cilen < CILEN_VOID || (len -= cilen) < 0) { +      goto bad; +    } +    next = p + cilen - 2; + +    switch (citype) { +      case CI_MRU: +        if ((go->neg_mru && go->mru != PPP_DEFMRU) +            || no.neg_mru || cilen != CILEN_SHORT) { +          goto bad; +        } +        GETSHORT(cishort, p); +        if (cishort < PPP_DEFMRU) { +          try.mru = cishort; +        } +        break; +      case CI_ASYNCMAP: +        if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +            || no.neg_asyncmap || cilen != CILEN_LONG) { +          goto bad; +        } +        break; +      case CI_AUTHTYPE: +        if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) { +          goto bad; +        } +        break; +      case CI_MAGICNUMBER: +        if (go->neg_magicnumber || no.neg_magicnumber || +            cilen != CILEN_LONG) { +          goto bad; +        } +        break; +      case CI_PCOMPRESSION: +        if (go->neg_pcompression || no.neg_pcompression +            || cilen != CILEN_VOID) { +          goto bad; +        } +        break; +      case CI_ACCOMPRESSION: +        if (go->neg_accompression || no.neg_accompression +            || cilen != CILEN_VOID) { +          goto bad; +        } +        break; +      case CI_QUALITY: +        if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) { +          goto bad; +        } +        break; +    } +    p = next; +  } + +  /* If there is still anything left, this packet is bad. */ +  if (len != 0) { +    goto bad; +  } + +  /* +  * OK, the Nak is good.  Now we can update state. +  */ +  if (f->state != LS_OPENED) { +    if (looped_back) { +      if (++try.numloops >= lcp_loopbackfail) { +        LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n")); +        lcp_close(f->unit, "Loopback detected"); +      } +    } else { +      try.numloops = 0; +    } +    *go = try; +  } + +  return 1; + +bad: +  LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n")); +  return 0; +} + + +/* + * lcp_rejci - Peer has Rejected some of our CIs. + * This should not modify any state if the Reject is bad + * or if LCP is in the LS_OPENED state. + * + * Returns: + *  0 - Reject was bad. + *  1 - Reject was good. + */ +static int +lcp_rejci(fsm *f, u_char *p, int len) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  u_char cichar; +  u_short cishort; +  u32_t cilong; +  lcp_options try; /* options to request next time */ + +  try = *go; + +  /* +   * Any Rejected CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define REJCIVOID(opt, neg) \ +  if (go->neg && \ +      len >= CILEN_VOID && \ +      p[1] == CILEN_VOID && \ +      p[0] == opt) { \ +    len -= CILEN_VOID; \ +    INCPTR(CILEN_VOID, p); \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \ +  } +#define REJCISHORT(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_SHORT && \ +      p[1] == CILEN_SHORT && \ +      p[0] == opt) { \ +    len -= CILEN_SHORT; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    /* Check rejected value. */ \ +    if (cishort != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \ +  } +#define REJCICHAP(opt, neg, val, digest) \ +  if (go->neg && \ +      len >= CILEN_CHAP && \ +      p[1] == CILEN_CHAP && \ +      p[0] == opt) { \ +    len -= CILEN_CHAP; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETCHAR(cichar, p); \ +    /* Check rejected value. */ \ +    if (cishort != val || cichar != digest) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    try.neg_upap = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \ +  } +#define REJCILONG(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_LONG && \ +      p[1] == CILEN_LONG && \ +      p[0] == opt) { \ +    len -= CILEN_LONG; \ +    INCPTR(2, p); \ +    GETLONG(cilong, p); \ +    /* Check rejected value. */ \ +    if (cilong != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \ +  } +#define REJCILQR(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_LQR && \ +      p[1] == CILEN_LQR && \ +      p[0] == opt) { \ +    len -= CILEN_LQR; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETLONG(cilong, p); \ +    /* Check rejected value. */ \ +    if (cishort != PPP_LQR || cilong != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \ +  } +#define REJCICBCP(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_CBCP && \ +      p[1] == CILEN_CBCP && \ +      p[0] == opt) { \ +    len -= CILEN_CBCP; \ +    INCPTR(2, p); \ +    GETCHAR(cichar, p); \ +    /* Check rejected value. */ \ +    if (cichar != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \ +  } +   +  REJCISHORT(CI_MRU, neg_mru, go->mru); +  REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); +  REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype); +  if (!go->neg_chap) { +    REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); +  } +  REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); +  REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); +  REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); +  REJCIVOID(CI_PCOMPRESSION, neg_pcompression); +  REJCIVOID(CI_ACCOMPRESSION, neg_accompression); +   +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  /* +   * Now we can update state. +   */ +  if (f->state != LS_OPENED) { +    *go = try; +  } +  return 1; +   +bad: +  LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n")); +  return 0; +} + + +/* + * lcp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately.  If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + */ +static int +lcp_reqci(fsm *f,  +          u_char *inp,    /* Requested CIs */ +          int *lenp,      /* Length of requested CIs */ +          int reject_if_disagree) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  lcp_options *ho = &lcp_hisoptions[f->unit]; +  lcp_options *ao = &lcp_allowoptions[f->unit]; +  u_char *cip, *next;         /* Pointer to current and next CIs */ +  int cilen, citype, cichar;  /* Parsed len, type, char value */ +  u_short cishort;            /* Parsed short value */ +  u32_t cilong;               /* Parse long value */ +  int rc = CONFACK;           /* Final packet return code */ +  int orc;                    /* Individual option return code */ +  u_char *p;                  /* Pointer to next char to parse */ +  u_char *rejp;               /* Pointer to next char in reject frame */ +  u_char *nakp;               /* Pointer to next char in Nak frame */ +  int l = *lenp;              /* Length left */ +#if TRACELCP > 0 +  char traceBuf[80]; +  int traceNdx = 0; +#endif + +  /* +   * Reset all his options. +   */ +  BZERO(ho, sizeof(*ho)); + +  /* +   * Process all his options. +   */ +  next = inp; +  nakp = nak_buffer; +  rejp = inp; +  while (l) { +    orc = CONFACK;      /* Assume success */ +    cip = p = next;     /* Remember begining of CI */ +    if (l < 2 ||        /* Not enough data for CI header or */ +        p[1] < 2 ||     /*  CI length too small or */ +        p[1] > l) {     /*  CI length too big? */ +      LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n")); +      orc = CONFREJ;    /* Reject bad CI */ +      cilen = l;        /* Reject till end of packet */ +      l = 0;            /* Don't loop again */ +      citype = 0; +      goto endswitch; +    } +    GETCHAR(citype, p); /* Parse CI type */ +    GETCHAR(cilen, p);  /* Parse CI length */ +    l -= cilen;         /* Adjust remaining length */ +    next += cilen;      /* Step to next CI */ + +    switch (citype) {   /* Check CI type */ +      case CI_MRU: +        if (!ao->neg_mru) {    /* Allow option? */ +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n")); +          orc = CONFREJ;    /* Reject CI */ +          break; +        } else if (cilen != CILEN_SHORT) {  /* Check CI length */ +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n")); +          orc = CONFREJ;    /* Reject CI */ +          break; +        } +        GETSHORT(cishort, p);  /* Parse MRU */ + +        /* +         * He must be able to receive at least our minimum. +         * No need to check a maximum.  If he sends a large number, +         * we'll just ignore it. +         */ +        if (cishort < PPP_MINMRU) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n")); +          orc = CONFNAK;    /* Nak CI */ +          PUTCHAR(CI_MRU, nakp); +          PUTCHAR(CILEN_SHORT, nakp); +          PUTSHORT(PPP_MINMRU, nakp);  /* Give him a hint */ +          break; +        } +        ho->neg_mru = 1;    /* Remember he sent MRU */ +        ho->mru = cishort;    /* And remember value */ +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort); +        traceNdx = strlen(traceBuf); +#endif +        break; + +      case CI_ASYNCMAP: +        if (!ao->neg_asyncmap) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n")); +          orc = CONFREJ; +          break; +        } else if (cilen != CILEN_LONG) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n")); +          orc = CONFREJ; +          break; +        } +        GETLONG(cilong, p); +         +        /* +         * Asyncmap must have set at least the bits +         * which are set in lcp_allowoptions[unit].asyncmap. +         */ +        if ((ao->asyncmap & ~cilong) != 0) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n",  +                    cilong, ao->asyncmap)); +          orc = CONFNAK; +          PUTCHAR(CI_ASYNCMAP, nakp); +          PUTCHAR(CILEN_LONG, nakp); +          PUTLONG(ao->asyncmap | cilong, nakp); +          break; +        } +        ho->neg_asyncmap = 1; +        ho->asyncmap = cilong; +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong); +        traceNdx = strlen(traceBuf); +#endif +        break; + +      case CI_AUTHTYPE: +        if (cilen < CILEN_SHORT) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n")); +          orc = CONFREJ; +          break; +        } else if (!(ao->neg_upap || ao->neg_chap)) { +          /* +           * Reject the option if we're not willing to authenticate. +           */ +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n")); +          orc = CONFREJ; +          break; +        } +        GETSHORT(cishort, p); +         +        /* +         * Authtype must be UPAP or CHAP. +         * +         * Note: if both ao->neg_upap and ao->neg_chap are set, +         * and the peer sends a Configure-Request with two +         * authenticate-protocol requests, one for CHAP and one +         * for UPAP, then we will reject the second request. +         * Whether we end up doing CHAP or UPAP depends then on +         * the ordering of the CIs in the peer's Configure-Request. +         */ +         +        if (cishort == PPP_PAP) { +          if (ho->neg_chap) {  /* we've already accepted CHAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n")); +            orc = CONFREJ; +            break; +          } else if (cilen != CILEN_SHORT) { +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n")); +            orc = CONFREJ; +            break; +          } +          if (!ao->neg_upap) {  /* we don't want to do PAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n")); +            orc = CONFNAK;  /* NAK it and suggest CHAP */ +            PUTCHAR(CI_AUTHTYPE, nakp); +            PUTCHAR(CILEN_CHAP, nakp); +            PUTSHORT(PPP_CHAP, nakp); +            PUTCHAR(ao->chap_mdtype, nakp); +            break; +          } +          ho->neg_upap = 1; +#if TRACELCP > 0 +          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort); +          traceNdx = strlen(traceBuf); +#endif +          break; +        } +        if (cishort == PPP_CHAP) { +          if (ho->neg_upap) {  /* we've already accepted PAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n")); +            orc = CONFREJ; +            break; +          } else if (cilen != CILEN_CHAP) { +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n")); +            orc = CONFREJ; +            break; +          } +          if (!ao->neg_chap) {  /* we don't want to do CHAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n")); +            orc = CONFNAK;  /* NAK it and suggest PAP */ +            PUTCHAR(CI_AUTHTYPE, nakp); +            PUTCHAR(CILEN_SHORT, nakp); +            PUTSHORT(PPP_PAP, nakp); +            break; +          } +          GETCHAR(cichar, p);  /* get digest type*/ +          if (cichar != CHAP_DIGEST_MD5 +#ifdef CHAPMS +              && cichar != CHAP_MICROSOFT +#endif +          ) { +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar)); +            orc = CONFNAK; +            PUTCHAR(CI_AUTHTYPE, nakp); +            PUTCHAR(CILEN_CHAP, nakp); +            PUTSHORT(PPP_CHAP, nakp); +            PUTCHAR(ao->chap_mdtype, nakp); +            break; +          } +#if TRACELCP > 0 +          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar); +          traceNdx = strlen(traceBuf); +#endif +          ho->chap_mdtype = cichar; /* save md type */ +          ho->neg_chap = 1; +          break; +        } +         +        /* +         * We don't recognize the protocol they're asking for. +         * Nak it with something we're willing to do. +         * (At this point we know ao->neg_upap || ao->neg_chap.) +         */ +        orc = CONFNAK; +        PUTCHAR(CI_AUTHTYPE, nakp); +        if (ao->neg_chap) { +          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort)); +          PUTCHAR(CILEN_CHAP, nakp); +          PUTSHORT(PPP_CHAP, nakp); +          PUTCHAR(ao->chap_mdtype, nakp); +        } else { +          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort)); +          PUTCHAR(CILEN_SHORT, nakp); +          PUTSHORT(PPP_PAP, nakp); +        } +        break; +       +      case CI_QUALITY: +        GETSHORT(cishort, p); +        GETLONG(cilong, p); +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong); +        traceNdx = strlen(traceBuf); +#endif + +        if (!ao->neg_lqr || +            cilen != CILEN_LQR) { +          orc = CONFREJ; +          break; +        } +         +        /* +         * Check the protocol and the reporting period. +         * XXX When should we Nak this, and what with? +         */ +        if (cishort != PPP_LQR) { +          orc = CONFNAK; +          PUTCHAR(CI_QUALITY, nakp); +          PUTCHAR(CILEN_LQR, nakp); +          PUTSHORT(PPP_LQR, nakp); +          PUTLONG(ao->lqr_period, nakp); +          break; +        } +        break; +       +      case CI_MAGICNUMBER: +        if (!(ao->neg_magicnumber || go->neg_magicnumber) || +            cilen != CILEN_LONG) { +          orc = CONFREJ; +          break; +        } +        GETLONG(cilong, p); +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong); +        traceNdx = strlen(traceBuf); +#endif + +        /* +         * He must have a different magic number. +         */ +        if (go->neg_magicnumber && +            cilong == go->magicnumber) { +          cilong = magic();  /* Don't put magic() inside macro! */ +          orc = CONFNAK; +          PUTCHAR(CI_MAGICNUMBER, nakp); +          PUTCHAR(CILEN_LONG, nakp); +          PUTLONG(cilong, nakp); +          break; +        } +        ho->neg_magicnumber = 1; +        ho->magicnumber = cilong; +        break; +       +       +      case CI_PCOMPRESSION: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION"); +        traceNdx = strlen(traceBuf); +#endif +        if (!ao->neg_pcompression || +            cilen != CILEN_VOID) { +          orc = CONFREJ; +          break; +        } +        ho->neg_pcompression = 1; +        break; +       +      case CI_ACCOMPRESSION: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION"); +        traceNdx = strlen(traceBuf); +#endif +        if (!ao->neg_accompression || +            cilen != CILEN_VOID) { +          orc = CONFREJ; +          break; +        } +        ho->neg_accompression = 1; +        break; +       +      case CI_MRRU: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU"); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +       +      case CI_SSNHF: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF"); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +       +      case CI_EPDISC: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC"); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +       +      default: +#if TRACELCP +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +    } + +  endswitch: +#if TRACELCP +    if (traceNdx >= 80 - 32) { +      LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf)); +      traceNdx = 0; +    } +#endif +    if (orc == CONFACK && /* Good CI */ +        rc != CONFACK) {  /*  but prior CI wasnt? */ +      continue;           /* Don't send this one */ +    } + +    if (orc == CONFNAK) {     /* Nak this CI? */ +      if (reject_if_disagree  /* Getting fed up with sending NAKs? */ +          && citype != CI_MAGICNUMBER) { +        orc = CONFREJ;        /* Get tough if so */ +      } else { +        if (rc == CONFREJ) {  /* Rejecting prior CI? */ +          continue;           /* Don't send this one */ +        } +        rc = CONFNAK; +      } +    } +    if (orc == CONFREJ) {        /* Reject this CI */ +      rc = CONFREJ; +      if (cip != rejp) {         /* Need to move rejected CI? */ +        BCOPY(cip, rejp, cilen); /* Move it */ +      } +      INCPTR(cilen, rejp);       /* Update output pointer */ +    } +  } + +  /* +   * If we wanted to send additional NAKs (for unsent CIs), the +   * code would go here.  The extra NAKs would go at *nakp. +   * At present there are no cases where we want to ask the +   * peer to negotiate an option. +   */ + +  switch (rc) { +    case CONFACK: +      *lenp = (int)(next - inp); +      break; +    case CONFNAK: +      /* +       * Copy the Nak'd options from the nak_buffer to the caller's buffer. +       */ +      *lenp = (int)(nakp - nak_buffer); +      BCOPY(nak_buffer, inp, *lenp); +      break; +    case CONFREJ: +      *lenp = (int)(rejp - inp); +      break; +  } + +#if TRACELCP > 0 +  if (traceNdx > 0) { +    LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf)); +  } +#endif +  LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc))); +  return (rc);      /* Return final code */ +} + + +/* + * lcp_up - LCP has come UP. + */ +static void +lcp_up(fsm *f) +{ +  lcp_options *wo = &lcp_wantoptions[f->unit]; +  lcp_options *ho = &lcp_hisoptions[f->unit]; +  lcp_options *go = &lcp_gotoptions[f->unit]; +  lcp_options *ao = &lcp_allowoptions[f->unit]; + +  if (!go->neg_magicnumber) { +    go->magicnumber = 0; +  } +  if (!ho->neg_magicnumber) { +    ho->magicnumber = 0; +  } + +  /* +   * Set our MTU to the smaller of the MTU we wanted and +   * the MRU our peer wanted.  If we negotiated an MRU, +   * set our MRU to the larger of value we wanted and +   * the value we got in the negotiation. +   */ +  ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)), +                 (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl), +                  ho->neg_pcompression, ho->neg_accompression); +  /* +   * If the asyncmap hasn't been negotiated, we really should +   * set the receive asyncmap to ffffffff, but we set it to 0 +   * for backwards contemptibility. +   */ +  ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU), +                 (go->neg_asyncmap? go->asyncmap: 0x00000000), +                  go->neg_pcompression, go->neg_accompression); + +  if (ho->neg_mru) { +    peer_mru[f->unit] = ho->mru; +  } + +  lcp_echo_lowerup(f->unit); /* Enable echo messages */ + +  link_established(f->unit); +} + + +/* + * lcp_down - LCP has gone DOWN. + * + * Alert other protocols. + */ +static void +lcp_down(fsm *f) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; + +  lcp_echo_lowerdown(f->unit); + +  link_down(f->unit); + +  ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0); +  ppp_recv_config(f->unit, PPP_MRU, +                  (go->neg_asyncmap? go->asyncmap: 0x00000000), +                   go->neg_pcompression, go->neg_accompression); +  peer_mru[f->unit] = PPP_MRU; +} + + +/* + * lcp_starting - LCP needs the lower layer up. + */ +static void +lcp_starting(fsm *f) +{ +  link_required(f->unit); +} + + +/* + * lcp_finished - LCP has finished with the lower layer. + */ +static void +lcp_finished(fsm *f) +{ +  link_terminated(f->unit); +} + + +#if 0 +/* + * print_string - print a readable representation of a string using + * printer. + */ +static void +print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg) +{ +  int c; +   +  printer(arg, "\""); +  for (; len > 0; --len) { +    c = *p++; +    if (' ' <= c && c <= '~') { +        if (c == '\\' || c == '"') { +          printer(arg, "\\"); +        } +        printer(arg, "%c", c); +    } else { +      switch (c) { +        case '\n': +          printer(arg, "\\n"); +          break; +        case '\r': +          printer(arg, "\\r"); +          break; +        case '\t': +          printer(arg, "\\t"); +          break; +        default: +          printer(arg, "\\%.3o", c); +        } +    } +  } +  printer(arg, "\""); +} + + +/* + * lcp_printpkt - print the contents of an LCP packet. + */ +static char *lcp_codenames[] = { +  "ConfReq", "ConfAck", "ConfNak", "ConfRej", +  "TermReq", "TermAck", "CodeRej", "ProtRej", +  "EchoReq", "EchoRep", "DiscReq" +}; + +static int +lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ +  int code, id, len, olen; +  u_char *pstart, *optend; +  u_short cishort; +  u32_t cilong; + +  if (plen < HEADERLEN) { +    return 0; +  } +  pstart = p; +  GETCHAR(code, p); +  GETCHAR(id, p); +  GETSHORT(len, p); +  if (len < HEADERLEN || len > plen) { +    return 0; +  } + +  if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) { +    printer(arg, " %s", lcp_codenames[code-1]); +  } else { +    printer(arg, " code=0x%x", code); +  } +  printer(arg, " id=0x%x", id); +  len -= HEADERLEN; +  switch (code) { +    case CONFREQ: +    case CONFACK: +    case CONFNAK: +    case CONFREJ: +      /* print option list */ +      while (len >= 2) { +        GETCHAR(code, p); +        GETCHAR(olen, p); +        p -= 2; +        if (olen < 2 || olen > len) { +          break; +        } +        printer(arg, " <"); +        len -= olen; +        optend = p + olen; +        switch (code) { +          case CI_MRU: +            if (olen == CILEN_SHORT) { +              p += 2; +              GETSHORT(cishort, p); +              printer(arg, "mru %d", cishort); +            } +            break; +          case CI_ASYNCMAP: +            if (olen == CILEN_LONG) { +              p += 2; +              GETLONG(cilong, p); +              printer(arg, "asyncmap 0x%lx", cilong); +            } +            break; +          case CI_AUTHTYPE: +            if (olen >= CILEN_SHORT) { +              p += 2; +              printer(arg, "auth "); +              GETSHORT(cishort, p); +              switch (cishort) { +                case PPP_PAP: +                  printer(arg, "pap"); +                  break; +                case PPP_CHAP: +                  printer(arg, "chap"); +                  break; +                default: +                  printer(arg, "0x%x", cishort); +              } +            } +            break; +          case CI_QUALITY: +            if (olen >= CILEN_SHORT) { +              p += 2; +              printer(arg, "quality "); +              GETSHORT(cishort, p); +              switch (cishort) { +                case PPP_LQR: +                  printer(arg, "lqr"); +                  break; +                default: +                  printer(arg, "0x%x", cishort); +              } +            } +            break; +          case CI_CALLBACK: +            if (olen >= CILEN_CHAR) { +              p += 2; +              printer(arg, "callback "); +              GETSHORT(cishort, p); +              switch (cishort) { +                case CBCP_OPT: +                  printer(arg, "CBCP"); +                  break; +                default: +                  printer(arg, "0x%x", cishort); +              } +            } +            break; +          case CI_MAGICNUMBER: +            if (olen == CILEN_LONG) { +              p += 2; +              GETLONG(cilong, p); +              printer(arg, "magic 0x%x", cilong); +            } +            break; +          case CI_PCOMPRESSION: +            if (olen == CILEN_VOID) { +              p += 2; +              printer(arg, "pcomp"); +            } +            break; +          case CI_ACCOMPRESSION: +            if (olen == CILEN_VOID) { +              p += 2; +              printer(arg, "accomp"); +            } +            break; +        } +        while (p < optend) { +          GETCHAR(code, p); +          printer(arg, " %.2x", code); +        } +        printer(arg, ">"); +      } +      break; +     +    case TERMACK: +    case TERMREQ: +      if (len > 0 && *p >= ' ' && *p < 0x7f) { +        printer(arg, " "); +        print_string((char*)p, len, printer, arg); +        p += len; +        len = 0; +      } +      break; +     +    case ECHOREQ: +    case ECHOREP: +    case DISCREQ: +      if (len >= 4) { +        GETLONG(cilong, p); +        printer(arg, " magic=0x%x", cilong); +        p += 4; +        len -= 4; +      } +      break; +  } + +  /* print the rest of the bytes in the packet */ +  for (; len > 0; --len) { +    GETCHAR(code, p); +    printer(arg, " %.2x", code); +  } + +  return (int)(p - pstart); +} +#endif + +/* + * Time to shut down the link because there is nothing out there. + */ +static void +LcpLinkFailure (fsm *f) +{ +  if (f->state == LS_OPENED) { +    LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending)); +    LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n")); +    lcp_close(f->unit, "Peer not responding"); +  } +} + +/* + * Timer expired for the LCP echo requests from this process. + */ +static void +LcpEchoCheck (fsm *f) +{ +  LcpSendEchoRequest (f); + +  /* +   * Start the timer for the next interval. +   */ +  LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0); + +  TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval); +  lcp_echo_timer_running = 1; +} + +/* + * LcpEchoTimeout - Timer expired on the LCP echo + */ +static void +LcpEchoTimeout (void *arg) +{ +  if (lcp_echo_timer_running != 0) { +    lcp_echo_timer_running = 0; +    LcpEchoCheck ((fsm *) arg); +  } +} + +/* + * LcpEchoReply - LCP has received a reply to the echo + */ +static void +lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len) +{ +  u32_t magic; + +  LWIP_UNUSED_ARG(id); + +  /* Check the magic number - don't count replies from ourselves. */ +  if (len < 4) { +    LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len)); +    return; +  } +  GETLONG(magic, inp); +  if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) { +    LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n")); +    return; +  } +   +  /* Reset the number of outstanding echo frames */ +  lcp_echos_pending = 0; +} + +/* + * LcpSendEchoRequest - Send an echo request frame to the peer + */ +static void +LcpSendEchoRequest (fsm *f) +{ +  u32_t lcp_magic; +  u_char pkt[4], *pktp; + +  /* +   * Detect the failure of the peer at this point. +   */ +  if (lcp_echo_fails != 0) { +    if (lcp_echos_pending++ >= lcp_echo_fails) { +      LcpLinkFailure(f); +      lcp_echos_pending = 0; +    } +  } + +  /* +   * Make and send the echo request frame. +   */ +  if (f->state == LS_OPENED) { +    lcp_magic = lcp_gotoptions[f->unit].magicnumber; +    pktp = pkt; +    PUTLONG(lcp_magic, pktp); +    fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt)); +  } +} + +/* + * lcp_echo_lowerup - Start the timer for the LCP frame + */ + +static void +lcp_echo_lowerup (int unit) +{ +  fsm *f = &lcp_fsm[unit]; + +  /* Clear the parameters for generating echo frames */ +  lcp_echos_pending      = 0; +  lcp_echo_number        = 0; +  lcp_echo_timer_running = 0; + +  /* If a timeout interval is specified then start the timer */ +  if (lcp_echo_interval != 0) { +    LcpEchoCheck (f); +  } +} + +/* + * lcp_echo_lowerdown - Stop the timer for the LCP frame + */ + +static void +lcp_echo_lowerdown (int unit) +{ +  fsm *f = &lcp_fsm[unit]; + +  if (lcp_echo_timer_running != 0) { +    UNTIMEOUT (LcpEchoTimeout, f); +    lcp_echo_timer_running = 0; +  } +} + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/lcp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/lcp.h new file mode 100644 index 000000000..1a5e5a4c0 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/lcp.h @@ -0,0 +1,167 @@ +/***************************************************************************** +* lcp.h - Network Link Control Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * lcp.h - Link Control Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: lcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef LCP_H +#define LCP_H + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ +/* + * Options. + */ +#define CI_MRU           1  /* Maximum Receive Unit */ +#define CI_ASYNCMAP      2  /* Async Control Character Map */ +#define CI_AUTHTYPE      3  /* Authentication Type */ +#define CI_QUALITY       4  /* Quality Protocol */ +#define CI_MAGICNUMBER   5  /* Magic Number */ +#define CI_PCOMPRESSION  7  /* Protocol Field Compression */ +#define CI_ACCOMPRESSION 8  /* Address/Control Field Compression */ +#define CI_CALLBACK      13 /* callback */ +#define CI_MRRU          17 /* max reconstructed receive unit; multilink */ +#define CI_SSNHF         18 /* short sequence numbers for multilink */ +#define CI_EPDISC        19 /* endpoint discriminator */ + +/* + * LCP-specific packet types. + */ +#define PROTREJ          8  /* Protocol Reject */ +#define ECHOREQ          9  /* Echo Request */ +#define ECHOREP          10 /* Echo Reply */ +#define DISCREQ          11 /* Discard Request */ +#define CBCP_OPT         6  /* Use callback control protocol */ + + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * The state of options is described by an lcp_options structure. + */ +typedef struct lcp_options { +    u_int passive           : 1; /* Don't die if we don't get a response */ +    u_int silent            : 1; /* Wait for the other end to start first */ +    u_int restart           : 1; /* Restart vs. exit after close */ +    u_int neg_mru           : 1; /* Negotiate the MRU? */ +    u_int neg_asyncmap      : 1; /* Negotiate the async map? */ +    u_int neg_upap          : 1; /* Ask for UPAP authentication? */ +    u_int neg_chap          : 1; /* Ask for CHAP authentication? */ +    u_int neg_magicnumber   : 1; /* Ask for magic number? */ +    u_int neg_pcompression  : 1; /* HDLC Protocol Field Compression? */ +    u_int neg_accompression : 1; /* HDLC Address/Control Field Compression? */ +    u_int neg_lqr           : 1; /* Negotiate use of Link Quality Reports */ +    u_int neg_cbcp          : 1; /* Negotiate use of CBCP */ +#ifdef PPP_MULTILINK +    u_int neg_mrru          : 1; /* Negotiate multilink MRRU */ +    u_int neg_ssnhf         : 1; /* Negotiate short sequence numbers */ +    u_int neg_endpoint      : 1; /* Negotiate endpoint discriminator */ +#endif +    u_short mru;                 /* Value of MRU */ +#ifdef PPP_MULTILINK +    u_short mrru;                /* Value of MRRU, and multilink enable */ +#endif +    u_char chap_mdtype;          /* which MD type (hashing algorithm) */ +    u32_t asyncmap;              /* Value of async map */ +    u32_t magicnumber; +    int numloops;                /* Number of loops during magic number neg. */ +    u32_t lqr_period;            /* Reporting period for LQR 1/100ths second */ +#ifdef PPP_MULTILINK +    struct epdisc endpoint;      /* endpoint discriminator */ +#endif +} lcp_options; + +/* + * Values for phase from BSD pppd.h based on RFC 1661. + */ +typedef enum { +  PHASE_DEAD = 0, +  PHASE_INITIALIZE, +  PHASE_ESTABLISH, +  PHASE_AUTHENTICATE, +  PHASE_CALLBACK, +  PHASE_NETWORK, +  PHASE_TERMINATE +} LinkPhase; + + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ +extern lcp_options lcp_wantoptions[]; +extern lcp_options lcp_gotoptions[]; +extern lcp_options lcp_allowoptions[]; +extern lcp_options lcp_hisoptions[]; +extern ext_accm xmit_accm[]; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +void lcp_init     (int); +void lcp_open     (int); +void lcp_close    (int, char *); +void lcp_lowerup  (int); +void lcp_lowerdown(int); +void lcp_sprotrej (int, u_char *, int); /* send protocol reject */ + +extern struct protent lcp_protent; + +/* Default number of times we receive our magic number from the peer +   before deciding the link is looped-back. */ +#define DEFLOOPBACKFAIL 10 + +#endif /* LCP_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/magic.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/magic.c new file mode 100644 index 000000000..d3922bb56 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/magic.c @@ -0,0 +1,82 @@ +/***************************************************************************** +* magic.c - Network Random Number Generator program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD magic.c. +*****************************************************************************/ +/* + * magic.c - PPP Magic Number routines. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT + +#include "ppp.h" +#include "randm.h" +#include "magic.h" + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * magicInit - Initialize the magic number generator. + * + * Since we use another random number generator that has its own + * initialization, we do nothing here. + */ +void magicInit() +{ +  return; +} + +/* + * magic - Returns the next magic number. + */ +u32_t magic() +{ +  return avRandom(); +} + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/magic.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/magic.h new file mode 100644 index 000000000..bc5174993 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/magic.h @@ -0,0 +1,67 @@ +/***************************************************************************** +* magic.h - Network Random Number Generator header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * magic.h - PPP Magic Number definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: magic.h,v 1.2 2007/12/02 22:35:55 fbernon Exp $ + */ + +#ifndef MAGIC_H +#define MAGIC_H + +/***************************************************************************** +************************** PUBLIC FUNCTIONS ********************************** +*****************************************************************************/ + +/* Initialize the magic number generator */ +void  magicInit(void); + +/* Returns the next magic number */ +u32_t magic(void); + +#endif /* MAGIC_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/md5.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/md5.c new file mode 100644 index 000000000..d65ecedbf --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/md5.c @@ -0,0 +1,318 @@ +/* + *********************************************************************** + ** md5.c -- the source code for MD5 routines                         ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              ** + ** Created: 2/17/90 RLR                                              ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  ** + **                                                                   ** + ** License to copy and use this software is granted provided that    ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message-     ** + ** Digest Algorithm" in all material mentioning or referencing this  ** + ** software or this function.                                        ** + **                                                                   ** + ** License is also granted to make and use derivative works          ** + ** provided that such works are identified as "derived from the RSA  ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          ** + ** material mentioning or referencing the derived work.              ** + **                                                                   ** + ** RSA Data Security, Inc. makes no representations concerning       ** + ** either the merchantability of this software or the suitability    ** + ** of this software for any particular purpose.  It is provided "as  ** + ** is" without express or implied warranty of any kind.              ** + **                                                                   ** + ** These notices must be retained in any copies of any part of this  ** + ** documentation and/or software.                                    ** + *********************************************************************** + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if CHAP_SUPPORT || MD5_SUPPORT + +#include "ppp.h" +#include "pppdebug.h" + +#include "md5.h" + +/* + *********************************************************************** + **  Message-digest routines:                                         ** + **  To form the message digest for a message M                       ** + **    (1) Initialize a context buffer mdContext using MD5Init        ** + **    (2) Call MD5Update on mdContext and M                          ** + **    (3) Call MD5Final on mdContext                                 ** + **  The message digest is now in mdContext->digest[0...15]           ** + *********************************************************************** + */ + +/* forward declaration */ +static void Transform (u32_t *buf, u32_t *in); + +static unsigned char PADDING[64] = { +  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ +  {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } +#define GG(a, b, c, d, x, s, ac) \ +  {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } +#define HH(a, b, c, d, x, s, ac) \ +  {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } +#define II(a, b, c, d, x, s, ac) \ +  {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } + +#ifdef __STDC__ +#define UL(x) x##UL +#else +#ifdef WIN32 +#define UL(x) x##UL +#else +#define UL(x) x +#endif +#endif + +/* The routine MD5Init initializes the message-digest context +   mdContext. All fields are set to zero. + */ +void +MD5Init (MD5_CTX *mdContext) +{ +  mdContext->i[0] = mdContext->i[1] = (u32_t)0; + +  /* Load magic initialization constants. */ +  mdContext->buf[0] = (u32_t)0x67452301UL; +  mdContext->buf[1] = (u32_t)0xefcdab89UL; +  mdContext->buf[2] = (u32_t)0x98badcfeUL; +  mdContext->buf[3] = (u32_t)0x10325476UL; +} + +/* The routine MD5Update updates the message-digest context to +   account for the presence of each of the characters inBuf[0..inLen-1] +   in the message whose digest is being computed. + */ +void +MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen) +{ +  u32_t in[16]; +  int mdi; +  unsigned int i, ii; + +#if 0 +  ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf); +  ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf); +#endif +   +  /* compute number of bytes mod 64 */ +  mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + +  /* update number of bits */ +  if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0]) { +    mdContext->i[1]++; +  } +  mdContext->i[0] += ((u32_t)inLen << 3); +  mdContext->i[1] += ((u32_t)inLen >> 29); + +  while (inLen--) { +    /* add new character to buffer, increment mdi */ +    mdContext->in[mdi++] = *inBuf++; + +    /* transform if necessary */ +    if (mdi == 0x40) { +      for (i = 0, ii = 0; i < 16; i++, ii += 4) { +        in[i] = (((u32_t)mdContext->in[ii+3]) << 24) | +                (((u32_t)mdContext->in[ii+2]) << 16) | +                (((u32_t)mdContext->in[ii+1]) << 8)  | +                ((u32_t)mdContext->in[ii]); +      } +      Transform (mdContext->buf, in); +      mdi = 0; +    } +  } +} + +/* The routine MD5Final terminates the message-digest computation and +   ends with the desired message digest in mdContext->digest[0...15]. + */ +void +MD5Final (unsigned char hash[], MD5_CTX *mdContext) +{ +  u32_t in[16]; +  int mdi; +  unsigned int i, ii; +  unsigned int padLen; + +  /* save number of bits */ +  in[14] = mdContext->i[0]; +  in[15] = mdContext->i[1]; + +  /* compute number of bytes mod 64 */ +  mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + +  /* pad out to 56 mod 64 */ +  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); +  MD5Update (mdContext, PADDING, padLen); + +  /* append length in bits and transform */ +  for (i = 0, ii = 0; i < 14; i++, ii += 4) { +    in[i] = (((u32_t)mdContext->in[ii+3]) << 24) | +            (((u32_t)mdContext->in[ii+2]) << 16) | +            (((u32_t)mdContext->in[ii+1]) << 8)  | +            ((u32_t)mdContext->in[ii]); +  } +  Transform (mdContext->buf, in); + +  /* store buffer in digest */ +  for (i = 0, ii = 0; i < 4; i++, ii += 4) { +    mdContext->digest[ii]   = (unsigned char)(mdContext->buf[i] & 0xFF); +    mdContext->digest[ii+1] = +      (unsigned char)((mdContext->buf[i] >> 8)  & 0xFF); +    mdContext->digest[ii+2] = +      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); +    mdContext->digest[ii+3] = +      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); +  } +  SMEMCPY(hash, mdContext->digest, 16); +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void +Transform (u32_t *buf, u32_t *in) +{ +  u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + +  /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ +  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ +  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ +  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ +  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ +  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ +  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ +  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ +  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ +  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ +  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ +  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ +  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ +  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ +  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ +  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + +  /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ +  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ +  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ +  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ +  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ +  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */ +  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ +  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ +  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ +  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ +  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ +  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ +  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ +  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ +  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ +  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + +  /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ +  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ +  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ +  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ +  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ +  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ +  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ +  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ +  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ +  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ +  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ +  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */ +  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ +  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ +  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ +  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + +  /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 +  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ +  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ +  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ +  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ +  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ +  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ +  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ +  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ +  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ +  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ +  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ +  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ +  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ +  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ +  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ +  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + +  buf[0] += a; +  buf[1] += b; +  buf[2] += c; +  buf[3] += d; +} + +#endif /* CHAP_SUPPORT || MD5_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/md5.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/md5.h new file mode 100644 index 000000000..e129533f3 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/md5.h @@ -0,0 +1,55 @@ +/* + *********************************************************************** + ** md5.h -- header file for implementation of MD5                    ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              ** + ** Created: 2/17/90 RLR                                              ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               ** + ** Revised (for MD5): RLR 4/27/91                                    ** + **   -- G modified to have y&~z instead of y&z                       ** + **   -- FF, GG, HH modified to add in last register done             ** + **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     ** + **   -- distinct additive constant for each step                     ** + **   -- round 4 added, working mod 7                                 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  ** + **                                                                   ** + ** License to copy and use this software is granted provided that    ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message-     ** + ** Digest Algorithm" in all material mentioning or referencing this  ** + ** software or this function.                                        ** + **                                                                   ** + ** License is also granted to make and use derivative works          ** + ** provided that such works are identified as "derived from the RSA  ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          ** + ** material mentioning or referencing the derived work.              ** + **                                                                   ** + ** RSA Data Security, Inc. makes no representations concerning       ** + ** either the merchantability of this software or the suitability    ** + ** of this software for any particular purpose.  It is provided "as  ** + ** is" without express or implied warranty of any kind.              ** + **                                                                   ** + ** These notices must be retained in any copies of any part of this  ** + ** documentation and/or software.                                    ** + *********************************************************************** + */ + +#ifndef MD5_H +#define MD5_H + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { +  u32_t i[2];               /* number of _bits_ handled mod 2^64 */ +  u32_t buf[4];             /* scratch buffer */ +  unsigned char in[64];     /* input buffer */ +  unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5Init  ( MD5_CTX *mdContext); +void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen); +void MD5Final ( unsigned char hash[], MD5_CTX *mdContext); + +#endif /* MD5_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pap.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pap.c new file mode 100644 index 000000000..7c3fd7e4c --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pap.c @@ -0,0 +1,619 @@ +/***************************************************************************** +* pap.c - Network Password Authentication Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ +/* + * upap.c - User/Password Authentication Protocol. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "auth.h" +#include "pap.h" + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Protocol entry points. + */ +static void upap_init      (int); +static void upap_lowerup   (int); +static void upap_lowerdown (int); +static void upap_input     (int, u_char *, int); +static void upap_protrej   (int); + +static void upap_timeout   (void *); +static void upap_reqtimeout(void *); +static void upap_rauthreq  (upap_state *, u_char *, int, int); +static void upap_rauthack  (upap_state *, u_char *, int, int); +static void upap_rauthnak  (upap_state *, u_char *, int, int); +static void upap_sauthreq  (upap_state *); +static void upap_sresp     (upap_state *, u_char, u_char, char *, int); + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +struct protent pap_protent = { +  PPP_PAP, +  upap_init, +  upap_input, +  upap_protrej, +  upap_lowerup, +  upap_lowerdown, +  NULL, +  NULL, +#if 0 +  upap_printpkt, +  NULL, +#endif +  1, +  "PAP", +#if 0 +  NULL, +  NULL, +  NULL +#endif +}; + +upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */ + + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + *  Set the default login name and password for the pap sessions + */ +void +upap_setloginpasswd(int unit, const char *luser, const char *lpassword) +{ +  upap_state *u = &upap[unit]; +   +  /* Save the username and password we're given */ +  u->us_user = luser; +  u->us_userlen = strlen(luser); +  u->us_passwd = lpassword; +  u->us_passwdlen = strlen(lpassword); +} + + +/* + * upap_authwithpeer - Authenticate us with our peer (start client). + * + * Set new state and send authenticate's. + */ +void +upap_authwithpeer(int unit, char *user, char *password) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n", +             unit, user, password, u->us_clientstate)); + +  upap_setloginpasswd(unit, user, password); + +  u->us_transmits = 0; + +  /* Lower layer up yet? */ +  if (u->us_clientstate == UPAPCS_INITIAL || +      u->us_clientstate == UPAPCS_PENDING) { +    u->us_clientstate = UPAPCS_PENDING; +    return; +  } + +  upap_sauthreq(u);      /* Start protocol */ +} + + +/* + * upap_authpeer - Authenticate our peer (start server). + * + * Set new state. + */ +void +upap_authpeer(int unit) +{ +  upap_state *u = &upap[unit]; + +  /* Lower layer up yet? */ +  if (u->us_serverstate == UPAPSS_INITIAL || +      u->us_serverstate == UPAPSS_PENDING) { +    u->us_serverstate = UPAPSS_PENDING; +    return; +  } + +  u->us_serverstate = UPAPSS_LISTEN; +  if (u->us_reqtimeout > 0) { +    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); +  } +} + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * upap_init - Initialize a UPAP unit. + */ +static void +upap_init(int unit) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit)); +  u->us_unit         = unit; +  u->us_user         = NULL; +  u->us_userlen      = 0; +  u->us_passwd       = NULL; +  u->us_passwdlen    = 0; +  u->us_clientstate  = UPAPCS_INITIAL; +  u->us_serverstate  = UPAPSS_INITIAL; +  u->us_id           = 0; +  u->us_timeouttime  = UPAP_DEFTIMEOUT; +  u->us_maxtransmits = 10; +  u->us_reqtimeout   = UPAP_DEFREQTIME; +} + +/* + * upap_timeout - Retransmission timer for sending auth-reqs expired. + */ +static void +upap_timeout(void *arg) +{ +  upap_state *u = (upap_state *) arg; + +  UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n",  +        u->us_unit, u->us_timeouttime, u->us_clientstate)); + +  if (u->us_clientstate != UPAPCS_AUTHREQ) { +    return; +  } + +  if (u->us_transmits >= u->us_maxtransmits) { +    /* give up in disgust */ +    UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n")); +    u->us_clientstate = UPAPCS_BADAUTH; +    auth_withpeer_fail(u->us_unit, PPP_PAP); +    return; +  } + +  upap_sauthreq(u);    /* Send Authenticate-Request */ +} + + +/* + * upap_reqtimeout - Give up waiting for the peer to send an auth-req. + */ +static void +upap_reqtimeout(void *arg) +{ +  upap_state *u = (upap_state *) arg; + +  if (u->us_serverstate != UPAPSS_LISTEN) { +    return; /* huh?? */ +  } + +  auth_peer_fail(u->us_unit, PPP_PAP); +  u->us_serverstate = UPAPSS_BADAUTH; +} + + +/* + * upap_lowerup - The lower layer is up. + * + * Start authenticating if pending. + */ +static void +upap_lowerup(int unit) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate)); + +  if (u->us_clientstate == UPAPCS_INITIAL) { +    u->us_clientstate = UPAPCS_CLOSED; +  } else if (u->us_clientstate == UPAPCS_PENDING) { +    upap_sauthreq(u);  /* send an auth-request */ +  } + +  if (u->us_serverstate == UPAPSS_INITIAL) { +    u->us_serverstate = UPAPSS_CLOSED; +  } else if (u->us_serverstate == UPAPSS_PENDING) { +    u->us_serverstate = UPAPSS_LISTEN; +    if (u->us_reqtimeout > 0) { +      TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); +    } +  } +} + + +/* + * upap_lowerdown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void +upap_lowerdown(int unit) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate)); + +  if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */ +    UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */ +  } +  if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) { +    UNTIMEOUT(upap_reqtimeout, u); +  } + +  u->us_clientstate = UPAPCS_INITIAL; +  u->us_serverstate = UPAPSS_INITIAL; +} + + +/* + * upap_protrej - Peer doesn't speak this protocol. + * + * This shouldn't happen.  In any case, pretend lower layer went down. + */ +static void +upap_protrej(int unit) +{ +  upap_state *u = &upap[unit]; + +  if (u->us_clientstate == UPAPCS_AUTHREQ) { +    UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n")); +    auth_withpeer_fail(unit, PPP_PAP); +  } +  if (u->us_serverstate == UPAPSS_LISTEN) { +    UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n")); +    auth_peer_fail(unit, PPP_PAP); +  } +  upap_lowerdown(unit); +} + + +/* + * upap_input - Input UPAP packet. + */ +static void +upap_input(int unit, u_char *inpacket, int l) +{ +  upap_state *u = &upap[unit]; +  u_char *inp; +  u_char code, id; +  int len; + +  /* +   * Parse header (code, id and length). +   * If packet too short, drop it. +   */ +  inp = inpacket; +  if (l < UPAP_HEADERLEN) { +    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n")); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  GETSHORT(len, inp); +  if (len < UPAP_HEADERLEN) { +    UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n")); +    return; +  } +  if (len > l) { +    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n")); +    return; +  } +  len -= UPAP_HEADERLEN; + +  /* +   * Action depends on code. +   */ +  switch (code) { +    case UPAP_AUTHREQ: +      upap_rauthreq(u, inp, id, len); +      break; + +    case UPAP_AUTHACK: +      upap_rauthack(u, inp, id, len); +      break; + +    case UPAP_AUTHNAK: +      upap_rauthnak(u, inp, id, len); +      break; + +    default:        /* XXX Need code reject */ +      break; +  } +} + + +/* + * upap_rauth - Receive Authenticate. + */ +static void +upap_rauthreq(upap_state *u, u_char *inp, int id, int len) +{ +  u_char ruserlen, rpasswdlen; +  char *ruser, *rpasswd; +  int retcode; +  char *msg; +  int msglen; + +  UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id)); + +  if (u->us_serverstate < UPAPSS_LISTEN) { +    return; +  } + +  /* +   * If we receive a duplicate authenticate-request, we are +   * supposed to return the same status as for the first request. +   */ +  if (u->us_serverstate == UPAPSS_OPEN) { +    upap_sresp(u, UPAP_AUTHACK, id, "", 0);  /* return auth-ack */ +    return; +  } +  if (u->us_serverstate == UPAPSS_BADAUTH) { +    upap_sresp(u, UPAP_AUTHNAK, id, "", 0);  /* return auth-nak */ +    return; +  } + +  /* +   * Parse user/passwd. +   */ +  if (len < sizeof (u_char)) { +    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); +    return; +  } +  GETCHAR(ruserlen, inp); +  len -= sizeof (u_char) + ruserlen + sizeof (u_char); +  if (len < 0) { +    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); +    return; +  } +  ruser = (char *) inp; +  INCPTR(ruserlen, inp); +  GETCHAR(rpasswdlen, inp); +  if (len < rpasswdlen) { +    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); +    return; +  } +  rpasswd = (char *) inp; + +  /* +   * Check the username and password given. +   */ +  retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen); +  BZERO(rpasswd, rpasswdlen); + +  upap_sresp(u, retcode, id, msg, msglen); + +  if (retcode == UPAP_AUTHACK) { +    u->us_serverstate = UPAPSS_OPEN; +    auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen); +  } else { +    u->us_serverstate = UPAPSS_BADAUTH; +    auth_peer_fail(u->us_unit, PPP_PAP); +  } + +  if (u->us_reqtimeout > 0) { +    UNTIMEOUT(upap_reqtimeout, u); +  } +} + + +/* + * upap_rauthack - Receive Authenticate-Ack. + */ +static void +upap_rauthack(upap_state *u, u_char *inp, int id, int len) +{ +  u_char msglen; +  char *msg; + +  LWIP_UNUSED_ARG(id); + +  UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate)); + +  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ +    return; +  } + +  /* +   * Parse message. +   */ +  if (len < sizeof (u_char)) { +    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n")); +    return; +  } +  GETCHAR(msglen, inp); +  len -= sizeof (u_char); +  if (len < msglen) { +    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n")); +    return; +  } +  msg = (char *) inp; +  PRINTMSG(msg, msglen); + +  u->us_clientstate = UPAPCS_OPEN; + +  auth_withpeer_success(u->us_unit, PPP_PAP); +} + + +/* + * upap_rauthnak - Receive Authenticate-Nakk. + */ +static void +upap_rauthnak(upap_state *u, u_char *inp, int id, int len) +{ +  u_char msglen; +  char *msg; + +  LWIP_UNUSED_ARG(id); + +  UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate)); + +  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ +    return; +  } + +  /* +   * Parse message. +   */ +  if (len < sizeof (u_char)) { +    UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); +  } else { +    GETCHAR(msglen, inp); +    if(msglen > 0) { +      len -= sizeof (u_char); +      if (len < msglen) { +        UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); +        return; +      } +      msg = (char *) inp; +      PRINTMSG(msg, msglen); +    } +  } + +  u->us_clientstate = UPAPCS_BADAUTH; + +  UPAPDEBUG((LOG_ERR, "PAP authentication failed\n")); +  auth_withpeer_fail(u->us_unit, PPP_PAP); +} + + +/* + * upap_sauthreq - Send an Authenticate-Request. + */ +static void +upap_sauthreq(upap_state *u) +{ +  u_char *outp; +  int outlen; + +  outlen = UPAP_HEADERLEN + 2 * sizeof (u_char)  +         + u->us_userlen + u->us_passwdlen; +  outp = outpacket_buf[u->us_unit]; + +  MAKEHEADER(outp, PPP_PAP); + +  PUTCHAR(UPAP_AUTHREQ, outp); +  PUTCHAR(++u->us_id, outp); +  PUTSHORT(outlen, outp); +  PUTCHAR(u->us_userlen, outp); +  BCOPY(u->us_user, outp, u->us_userlen); +  INCPTR(u->us_userlen, outp); +  PUTCHAR(u->us_passwdlen, outp); +  BCOPY(u->us_passwd, outp, u->us_passwdlen); + +  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); + +  UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id)); + +  TIMEOUT(upap_timeout, u, u->us_timeouttime); +  ++u->us_transmits; +  u->us_clientstate = UPAPCS_AUTHREQ; +} + + +/* + * upap_sresp - Send a response (ack or nak). + */ +static void +upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen) +{ +  u_char *outp; +  int outlen; + +  outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; +  outp = outpacket_buf[u->us_unit]; +  MAKEHEADER(outp, PPP_PAP); + +  PUTCHAR(code, outp); +  PUTCHAR(id, outp); +  PUTSHORT(outlen, outp); +  PUTCHAR(msglen, outp); +  BCOPY(msg, outp, msglen); +  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); + +  UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate)); +} + +#if 0 +/* + * upap_printpkt - print the contents of a PAP packet. + */ +static int upap_printpkt( +  u_char *p, +  int plen, +  void (*printer) (void *, char *, ...), +  void *arg +) +{ +  LWIP_UNUSED_ARG(p); +  LWIP_UNUSED_ARG(plen); +  LWIP_UNUSED_ARG(printer); +  LWIP_UNUSED_ARG(arg); +  return 0; +} +#endif /* 0 */ + +#endif /* PAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pap.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pap.h new file mode 100644 index 000000000..0a09fc841 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pap.h @@ -0,0 +1,131 @@ +/***************************************************************************** +* pap.h -  PPP Password Authentication Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * upap.h - User/Password Authentication Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef PAP_H +#define PAP_H + +#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ +/* + * Packet header = Code, id, length. + */ +#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) + + +/* + * UPAP codes. + */ +#define UPAP_AUTHREQ 1 /* Authenticate-Request */ +#define UPAP_AUTHACK 2 /* Authenticate-Ack */ +#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ + +/* + * Client states. + */ +#define UPAPCS_INITIAL 0 /* Connection down */ +#define UPAPCS_CLOSED  1 /* Connection up, haven't requested auth */ +#define UPAPCS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ +#define UPAPCS_OPEN    4 /* We've received an Ack */ +#define UPAPCS_BADAUTH 5 /* We've received a Nak */ + +/* + * Server states. + */ +#define UPAPSS_INITIAL 0 /* Connection down */ +#define UPAPSS_CLOSED  1 /* Connection up, haven't requested auth */ +#define UPAPSS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPSS_LISTEN  3 /* Listening for an Authenticate */ +#define UPAPSS_OPEN    4 /* We've sent an Ack */ +#define UPAPSS_BADAUTH 5 /* We've sent a Nak */ + + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * Each interface is described by upap structure. + */ +typedef struct upap_state { +  int us_unit;           /* Interface unit number */ +  const char *us_user;   /* User */ +  int us_userlen;        /* User length */ +  const char *us_passwd; /* Password */ +  int us_passwdlen;      /* Password length */ +  int us_clientstate;    /* Client state */ +  int us_serverstate;    /* Server state */ +  u_char us_id;          /* Current id */ +  int us_timeouttime;    /* Timeout (seconds) for auth-req retrans. */ +  int us_transmits;      /* Number of auth-reqs sent */ +  int us_maxtransmits;   /* Maximum number of auth-reqs to send */ +  int us_reqtimeout;     /* Time to wait for auth-req from peer */ +} upap_state; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +extern upap_state upap[]; + +void upap_setloginpasswd(int unit, const char *luser, const char *lpassword); +void upap_authwithpeer  (int, char *, char *); +void upap_authpeer      (int); + +extern struct protent pap_protent; + +#endif /* PAP_SUPPORT */ + +#endif /* PAP_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp.c new file mode 100644 index 000000000..8720c3368 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp.c @@ -0,0 +1,1999 @@ +/***************************************************************************** +* ppp.c - Network Point to Point Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ + +/* + * ppp_defs.h - PPP definitions. + * + * if_pppvar.h - private structures and declarations for PPP. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies.  This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +/* + * if_ppp.h - Point-to-Point Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip.h" /* for ip_input() */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "randm.h" +#include "fsm.h" +#if PAP_SUPPORT +#include "pap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "chap.h" +#endif /* CHAP_SUPPORT */ +#include "ipcp.h" +#include "lcp.h" +#include "magic.h" +#include "auth.h" +#if VJ_SUPPORT +#include "vj.h" +#endif /* VJ_SUPPORT */ +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#endif /* PPPOE_SUPPORT */ + +#include <string.h> + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +/* + * The basic PPP frame. + */ +#define PPP_ADDRESS(p)  (((u_char *)(p))[0]) +#define PPP_CONTROL(p)  (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* PPP packet parser states.  Current state indicates operation yet to be + * completed. */ +typedef enum { +  PDIDLE = 0,  /* Idle state - waiting. */ +  PDSTART,     /* Process start flag. */ +  PDADDRESS,   /* Process address field. */ +  PDCONTROL,   /* Process control field. */ +  PDPROTOCOL1, /* Process protocol field 1. */ +  PDPROTOCOL2, /* Process protocol field 2. */ +  PDDATA       /* Process data byte. */ +} PPPDevStates; + +#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07]) + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ +/* + * PPP interface control block. + */ +typedef struct PPPControl_s { +  char openFlag;                /* True when in use. */ +#if PPPOE_SUPPORT +  struct netif *ethif; +  struct pppoe_softc *pppoe_sc; +#endif /* PPPOE_SUPPORT */ +  int  if_up;                   /* True when the interface is up. */ +  int  errCode;                 /* Code indicating why interface is down. */ +#if PPPOS_SUPPORT +  sio_fd_t fd;                  /* File device ID of port. */ +  int  kill_link;               /* Shut the link down. */ +  int  sig_hup;                 /* Carrier lost. */ +  struct pbuf *inHead, *inTail; /* The input packet. */ +  PPPDevStates inState;         /* The input process state. */ +  char inEscaped;               /* Escape next character. */ +  u16_t inProtocol;             /* The input protocol code. */ +  u16_t inFCS;                  /* Input Frame Check Sequence value. */ +#endif /* PPPOS_SUPPORT */ +  int  mtu;                     /* Peer's mru */ +  int  pcomp;                   /* Does peer accept protocol compression? */ +  int  accomp;                  /* Does peer accept addr/ctl compression? */ +  u_long lastXMit;              /* Time of last transmission. */ +  ext_accm inACCM;              /* Async-Ctl-Char-Map for input. */ +  ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */ +#if PPPOS_SUPPORT && VJ_SUPPORT +  int  vjEnabled;               /* Flag indicating VJ compression enabled. */ +  struct vjcompress vjComp;     /* Van Jabobsen compression header. */ +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + +  struct netif netif; + +  struct ppp_addrs addrs; + +  void (*linkStatusCB)(void *ctx, int errCode, void *arg); +  void *linkStatusCtx; + +} PPPControl; + + +/* + * Ioctl definitions. + */ + +struct npioctl { +  int         protocol; /* PPP procotol, e.g. PPP_IP */ +  enum NPmode mode; +}; + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +#if PPPOS_SUPPORT +static void pppMain(void *pd); +static void pppDrop(PPPControl *pc); +static void pppInProc(int pd, u_char *s, int l); +#endif /* PPPOS_SUPPORT */ + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +u_long subnetMask; + +static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */ + +/* + * PPP Data Link Layer "protocol" table. + * One entry per supported protocol. + * The last entry must be NULL. + */ +struct protent *ppp_protocols[] = { +  &lcp_protent, +#if PAP_SUPPORT +  &pap_protent, +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +  &chap_protent, +#endif /* CHAP_SUPPORT */ +#if CBCP_SUPPORT +  &cbcp_protent, +#endif /* CBCP_SUPPORT */ +  &ipcp_protent, +#if CCP_SUPPORT +  &ccp_protent, +#endif /* CCP_SUPPORT */ +  NULL +}; + + +/* + * Buffers for outgoing packets.  This must be accessed only from the appropriate + * PPP task so that it doesn't need to be protected to avoid collisions. + */ +u_char *outpacket_buf[NUM_PPP];   + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ + +#if PPPOS_SUPPORT +/* + * FCS lookup table as calculated by genfcstab. + */ +static const u_short fcstab[256] = { +  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, +  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, +  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, +  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, +  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, +  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, +  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, +  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, +  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, +  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, +  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, +  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, +  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, +  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, +  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, +  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, +  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, +  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, +  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, +  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, +  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, +  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, +  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, +  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, +  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, +  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, +  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, +  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, +  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, +  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, +  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, +  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/* PPP's Asynchronous-Control-Character-Map.  The mask array is used + * to select the specific bit for a character. */ +static u_char pppACCMMask[] = { +  0x01, +  0x02, +  0x04, +  0x08, +  0x10, +  0x20, +  0x40, +  0x80 +}; + + +void +pppMainWakeup(int pd) +{ +  PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd)); +  sio_read_abort(pppControl[pd].fd); +} +#endif /* PPPOS_SUPPORT */ + +void +pppLinkTerminated(int pd) +{ +  PPPControl *pc = &pppControl[pd]; + +  PPPDEBUG((LOG_DEBUG, "pppLinkTerminated: unit %d\n", pd)); + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    pppoe_disconnect(pc->pppoe_sc); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } +} + +void +pppLinkDown(int pd) +{ +  PPPControl *pc = &pppControl[pd]; + +  PPPDEBUG((LOG_DEBUG, "pppLinkDown: unit %d\n", pd)); + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    pppoe_disconnect(pc->pppoe_sc); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } +} + +/* these callbacks are necessary because lcp_* functions +   must be called in the same context as pppInput(), +   namely the tcpip_thread(), essentially because +   they manipulate timeouts which are thread-private +*/ + +static void +pppStartCB(void *arg) +{ +  int pd = (int)arg; + +  PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd)); +  lcp_lowerup(pd); +  lcp_open(pd); /* Start protocol */ +} + +static void +pppStopCB(void *arg) +{ +  int pd = (int)arg; + +  PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd)); +  lcp_close(pd, "User request"); +} + +static void +pppHupCB(void *arg) +{ +  int pd = (int)arg; + +  PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd)); +  lcp_lowerdown(pd); +  link_terminated(pd); +} + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* Initialize the PPP subsystem. */ + +struct ppp_settings ppp_settings; + +err_t +pppInit(void) +{ +  struct protent *protp; +  int i, j; + +  memset(&ppp_settings, 0, sizeof(ppp_settings)); +  ppp_settings.usepeerdns = 1; +  pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL); + +  magicInit(); + +  for (i = 0; i < NUM_PPP; i++) { +    pppControl[i].openFlag = 0; + +    subnetMask = htonl(0xffffff00); + +    outpacket_buf[i] = (u_char *)mem_malloc(PPP_MRU+PPP_HDRLEN); +    if(!outpacket_buf[i]) { +      return ERR_MEM; +    } + +    /* +     * Initialize to the standard option set. +     */ +    for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) { +      (*protp->init)(i); +    } +  } + +#if LINK_STATS +  /** @todo already done in stats_init (in fact, zeroed at boot). So, remove it? */ +  /* Clear the statistics. */ +  memset(&lwip_stats.link, 0, sizeof(lwip_stats.link)); +#endif /* LINK_STATS */ + +#if PPPOE_SUPPORT +  pppoe_init(); +#endif /* PPPOE_SUPPORT */ + +  return ERR_OK; +} + +void +pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd) +{ +  switch(authType) { +    case PPPAUTHTYPE_NONE: +    default: +#ifdef LWIP_PPP_STRICT_PAP_REJECT +      ppp_settings.refuse_pap = 1; +#else  /* LWIP_PPP_STRICT_PAP_REJECT */ +      /* some providers request pap and accept an empty login/pw */ +      ppp_settings.refuse_pap = 0; +#endif /* LWIP_PPP_STRICT_PAP_REJECT */ +      ppp_settings.refuse_chap = 1; +      break; + +    case PPPAUTHTYPE_ANY: +      /* Warning: Using PPPAUTHTYPE_ANY might have security consequences. +       * RFC 1994 says: +       * +       * In practice, within or associated with each PPP server, there is a +       * database which associates "user" names with authentication +       * information ("secrets").  It is not anticipated that a particular +       * named user would be authenticated by multiple methods.  This would +       * make the user vulnerable to attacks which negotiate the least secure +       * method from among a set (such as PAP rather than CHAP).  If the same +       * secret was used, PAP would reveal the secret to be used later with +       * CHAP. +       * +       * Instead, for each user name there should be an indication of exactly +       * one method used to authenticate that user name.  If a user needs to +       * make use of different authentication methods under different +       * circumstances, then distinct user names SHOULD be employed, each of +       * which identifies exactly one authentication method. +       * +       */ +      ppp_settings.refuse_pap = 0; +      ppp_settings.refuse_chap = 0; +      break; + +    case PPPAUTHTYPE_PAP: +      ppp_settings.refuse_pap = 0; +      ppp_settings.refuse_chap = 1; +      break; + +    case PPPAUTHTYPE_CHAP: +      ppp_settings.refuse_pap = 1; +      ppp_settings.refuse_chap = 0; +      break; +  } + +  if(user) { +    strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1); +    ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0'; +  } else { +    ppp_settings.user[0] = '\0'; +  } + +  if(passwd) { +    strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1); +    ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0'; +  } else { +    ppp_settings.passwd[0] = '\0'; +  } +} + +#if PPPOS_SUPPORT +/* Open a new PPP connection using the given I/O device. + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session.  If this port + * connects to a modem, the modem connection must be + * established before calling this. + * Return a new PPP connection descriptor on success or + * an error code (negative) on failure. */ +int +pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx) +{ +  PPPControl *pc; +  int pd; + +  /* Find a free PPP session descriptor. Critical region? */ +  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); + +  if (pd >= NUM_PPP) { +    pd = PPPERR_OPEN; +  } else { +    pppControl[pd].openFlag = !0; +  } + +  /* Launch a deamon thread. */ +  if (pd >= 0) { +    pppControl[pd].openFlag = 1; + +    lcp_init(pd); +    pc = &pppControl[pd]; +    pc->fd = fd; +#if PPPOE_SUPPORT +    pc->ethif= NULL; +#endif /* PPPOE_SUPPORT */ +    pc->kill_link = 0; +    pc->sig_hup = 0; +    pc->if_up = 0; +    pc->errCode = 0; +    pc->inState = PDIDLE; +    pc->inHead = NULL; +    pc->inTail = NULL; +    pc->inEscaped = 0; +    pc->lastXMit = 0; + +#if VJ_SUPPORT +    pc->vjEnabled = 0; +    vj_compress_init(&pc->vjComp); +#endif /* VJ_SUPPORT */ + +    /*  +     * Default the in and out accm so that escape and flag characters +     * are always escaped.  +     */ +    memset(pc->inACCM, 0, sizeof(ext_accm)); +    pc->inACCM[15] = 0x60; +    memset(pc->outACCM, 0, sizeof(ext_accm)); +    pc->outACCM[15] = 0x60; + +    pc->linkStatusCB = linkStatusCB; +    pc->linkStatusCtx = linkStatusCtx; + +    sys_thread_new(PPP_THREAD_NAME, pppMain, (void*)pd, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); +    if(!linkStatusCB) { +      while(pd >= 0 && !pc->if_up) { +        sys_msleep(500); +        if (lcp_phase[pd] == PHASE_DEAD) { +          pppClose(pd); +          if (pc->errCode) { +            pd = pc->errCode; +          } else { +            pd = PPPERR_CONNECT; +          } +        } +      } +    } +  } + +  return pd; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +static void pppOverEthernetLinkStatusCB(int pd, int up); + +void +pppOverEthernetClose(int pd) +{ +  PPPControl* pc = &pppControl[pd]; + +  /* *TJL* There's no lcp_deinit */ +  lcp_close(pd, NULL); + +  pppoe_destroy(&pc->netif); +} + +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx) +{ +  PPPControl *pc; +  int pd; + +  LWIP_UNUSED_ARG(service_name); +  LWIP_UNUSED_ARG(concentrator_name); + +  /* Find a free PPP session descriptor. Critical region? */ +  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); +  if (pd >= NUM_PPP) { +    pd = PPPERR_OPEN; +  } else { +    pppControl[pd].openFlag = !0; +  } + +  /* Launch a deamon thread. */ +  if (pd >= 0) { + +    pppControl[pd].openFlag = 1; + +    lcp_init(pd); + +    lcp_wantoptions[pd].mru = PPPOE_MAXMTU; +    lcp_wantoptions[pd].neg_asyncmap = 0; +    lcp_wantoptions[pd].neg_pcompression = 0; +    lcp_wantoptions[pd].neg_accompression = 0; + +    lcp_allowoptions[pd].mru = PPPOE_MAXMTU; +    lcp_allowoptions[pd].neg_asyncmap = 0; +    lcp_allowoptions[pd].neg_pcompression = 0; +    lcp_allowoptions[pd].neg_accompression = 0; + +    pc = &pppControl[pd]; +    pc->if_up = 0; +    pc->errCode = 0; +    pc->lastXMit = 0; +#if PPPOS_SUPPORT +    pc->kill_link = 0; +    pc->sig_hup = 0; +    pc->inState = PDIDLE; +    pc->inHead = NULL; +    pc->inTail = NULL; +    pc->inEscaped = 0; +#if VJ_SUPPORT +    pc->vjEnabled = 0; +#endif /* VJ_SUPPORT */ +#endif /* PPPOS_SUPPORT */ +    pc->ethif= ethif; + +    memset(pc->inACCM,  0, sizeof(ext_accm)); +    memset(pc->outACCM, 0, sizeof(ext_accm)); + +    pc->linkStatusCB  = linkStatusCB; +    pc->linkStatusCtx = linkStatusCtx; + +    if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) { +      pc->openFlag = 0; +      return PPPERR_OPEN; +    } + +    pppoe_connect(pc->pppoe_sc); + +    if(!linkStatusCB) { +      while(pd >= 0 && !pc->if_up) { +        sys_msleep(500); +        if (lcp_phase[pd] == PHASE_DEAD) { +          pppClose(pd); +          if (pc->errCode) { +            pd = pc->errCode; +          } else { +            pd = PPPERR_CONNECT; +          } +        } +      } +    } +  } + +  return pd; +} +#endif /* PPPOE_SUPPORT */ + + +/* Close a PPP connection and release the descriptor.  + * Any outstanding packets in the queues are dropped. + * Return 0 on success, an error code on failure. */ +int +pppClose(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 0; + +  /* Disconnect */ +#if PPPOE_SUPPORT +  if(pc->ethif) { +    PPPDEBUG((LOG_DEBUG, "pppClose: unit %d kill_link -> pppStopCB\n", pd)); +    pc->errCode = PPPERR_USER; +    /* This will leave us at PHASE_DEAD. */ +    tcpip_callback(pppStopCB, (void*)pd); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pc->kill_link = !0; +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } + +  if(!pc->linkStatusCB) { +    while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) { +      sys_msleep(500); +      break; +    } +  } + +  return st; +} + +/* This function is called when carrier is lost on the PPP channel. */ +void +pppSigHUP(int pd) +{ +  PPPControl *pc = &pppControl[pd]; + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    PPPDEBUG((LOG_DEBUG, "pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd)); +    tcpip_callback(pppHupCB, (void*)pd); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pc->sig_hup = 1; +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } +} + +#if PPPOS_SUPPORT +static void +nPut(PPPControl *pc, struct pbuf *nb) +{ +  struct pbuf *b; +  int c; + +  for(b = nb; b != NULL; b = b->next) { +    if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) { +      PPPDEBUG((LOG_WARNING, +               "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c)); +      LINK_STATS_INC(link.err); +      pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */ +      break; +    } +  } + +  pbuf_free(nb); +  LINK_STATS_INC(link.xmit); +} + +/*  + * pppAppend - append given character to end of given pbuf.  If outACCM + * is not NULL and the character needs to be escaped, do so. + * If pbuf is full, append another. + * Return the current pbuf. + */ +static struct pbuf * +pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM) +{ +  struct pbuf *tb = nb; +   +  /* Make sure there is room for the character and an escape code. +   * Sure we don't quite fill the buffer if the character doesn't +   * get escaped but is one character worth complicating this? */ +  /* Note: We assume no packet header. */ +  if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) { +    tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +    if (tb) { +      nb->next = tb; +    } else { +      LINK_STATS_INC(link.memerr); +    } +    nb = tb; +  } + +  if (nb) { +    if (outACCM && ESCAPE_P(*outACCM, c)) { +      *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE; +      *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS; +    } else { +      *((u_char*)nb->payload + nb->len++) = c; +    } +  } + +  return tb; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +static err_t +pppifOutputOverEthernet(int pd, struct pbuf *p) +{ +  PPPControl *pc = &pppControl[pd]; +  struct pbuf *pb; +  u_short protocol = PPP_IP; +  int i=0; + +  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + sizeof(protocol), PBUF_RAM); +  if(!pb) { +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return ERR_MEM; +  } + +  pbuf_header(pb, -pppoe_hdrlen); + +  pc->lastXMit = sys_jiffies(); + +  if (!pc->pcomp || protocol > 0xFF) { +    *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF; +  } +  *((u_char*)pb->payload + i) = protocol & 0xFF; + +  pbuf_chain(pb, p); + +  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { +    LINK_STATS_INC(link.err); +    return PPPERR_DEVICE; +  } + +  LINK_STATS_INC(link.xmit); +  return ERR_OK; +} +#endif /* PPPOE_SUPPORT */ + +/* Send a packet on the given connection. */ +static err_t +pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) +{ +  int pd = (int)netif->state; +  u_short protocol = PPP_IP; +  PPPControl *pc = &pppControl[pd]; +#if PPPOS_SUPPORT +  u_int fcsOut = PPP_INITFCS; +  struct pbuf *headMB = NULL, *tailMB = NULL, *p; +  u_char c; +#endif /* PPPOS_SUPPORT */ + +  LWIP_UNUSED_ARG(ipaddr); + +  /* Validate parameters. */ +  /* We let any protocol value go through - it can't hurt us +   * and the peer will just drop it if it's not accepting it. */ +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) { +    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n", +              pd, protocol, pb)); +    LINK_STATS_INC(link.opterr); +    LINK_STATS_INC(link.drop); +    return ERR_ARG; +  } + +  /* Check that the link is up. */ +  if (lcp_phase[pd] == PHASE_DEAD) { +    PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd)); +    LINK_STATS_INC(link.rterr); +    LINK_STATS_INC(link.drop); +    return ERR_RTE; +  } + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    return pppifOutputOverEthernet(pd, pb); +  } +#endif /* PPPOE_SUPPORT */ + +#if PPPOS_SUPPORT +  /* Grab an output buffer. */ +  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +  if (headMB == NULL) { +    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd)); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +    return ERR_MEM; +  } + +#if VJ_SUPPORT +  /*  +   * Attempt Van Jacobson header compression if VJ is configured and +   * this is an IP packet.  +   */ +  if (protocol == PPP_IP && pc->vjEnabled) { +    switch (vj_compress_tcp(&pc->vjComp, pb)) { +      case TYPE_IP: +        /* No change... +           protocol = PPP_IP_PROTOCOL; */ +        break; +      case TYPE_COMPRESSED_TCP: +        protocol = PPP_VJC_COMP; +        break; +      case TYPE_UNCOMPRESSED_TCP: +        protocol = PPP_VJC_UNCOMP; +        break; +      default: +        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd)); +        LINK_STATS_INC(link.proterr); +        LINK_STATS_INC(link.drop); +        pbuf_free(headMB); +        return ERR_VAL; +    } +  } +#endif /* VJ_SUPPORT */ + +  tailMB = headMB; + +  /* Build the PPP header. */ +  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) { +    tailMB = pppAppend(PPP_FLAG, tailMB, NULL); +  } + +  pc->lastXMit = sys_jiffies(); +  if (!pc->accomp) { +    fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS); +    tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM); +    fcsOut = PPP_FCS(fcsOut, PPP_UI); +    tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM); +  } +  if (!pc->pcomp || protocol > 0xFF) { +    c = (protocol >> 8) & 0xFF; +    fcsOut = PPP_FCS(fcsOut, c); +    tailMB = pppAppend(c, tailMB, &pc->outACCM); +  } +  c = protocol & 0xFF; +  fcsOut = PPP_FCS(fcsOut, c); +  tailMB = pppAppend(c, tailMB, &pc->outACCM); + +  /* Load packet. */ +  for(p = pb; p; p = p->next) { +    int n; +    u_char *sPtr; + +    sPtr = (u_char*)p->payload; +    n = p->len; +    while (n-- > 0) { +      c = *sPtr++; + +      /* Update FCS before checking for special characters. */ +      fcsOut = PPP_FCS(fcsOut, c); +       +      /* Copy to output buffer escaping special characters. */ +      tailMB = pppAppend(c, tailMB, &pc->outACCM); +    } +  } + +  /* Add FCS and trailing flag. */ +  c = ~fcsOut & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  c = (~fcsOut >> 8) & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + +  /* If we failed to complete the packet, throw it away. */ +  if (!tailMB) { +    PPPDEBUG((LOG_WARNING, +             "pppifOutput[%d]: Alloc err - dropping proto=%d\n",  +              pd, protocol)); +    pbuf_free(headMB); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +    return ERR_MEM; +  } + +  /* Send it. */ +  PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol)); + +  nPut(pc, headMB); +#endif /* PPPOS_SUPPORT */ + +  return ERR_OK; +} + +/* Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. */ +int +pppIOCtl(int pd, int cmd, void *arg) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 0; + +  if (pd < 0 || pd >= NUM_PPP) { +    st = PPPERR_PARAM; +  } else { +    switch(cmd) { +    case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */ +      if (arg) { +        *(int *)arg = (int)(pc->if_up); +      } else { +        st = PPPERR_PARAM; +      } +      break; +    case PPPCTLS_ERRCODE:       /* Set the PPP error code. */ +      if (arg) { +        pc->errCode = *(int *)arg; +      } else { +        st = PPPERR_PARAM; +      } +      break; +    case PPPCTLG_ERRCODE:       /* Get the PPP error code. */ +      if (arg) { +        *(int *)arg = (int)(pc->errCode); +      } else { +        st = PPPERR_PARAM; +      } +      break; +#if PPPOS_SUPPORT +    case PPPCTLG_FD: +      if (arg) { +        *(sio_fd_t *)arg = pc->fd; +      } else { +        st = PPPERR_PARAM; +      } +      break; +#endif /* PPPOS_SUPPORT */ +    default: +      st = PPPERR_PARAM; +      break; +    } +  } + +  return st; +} + +/* + * Return the Maximum Transmission Unit for the given PPP connection. + */ +u_int +pppMTU(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  u_int st; + +  /* Validate parameters. */ +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +  } else { +    st = pc->mtu; +  } + +  return st; +} + +#if PPPOE_SUPPORT +int +pppWriteOverEthernet(int pd, const u_char *s, int n) +{ +  PPPControl *pc = &pppControl[pd]; +  struct pbuf *pb; + +  /* skip address & flags */ +  s += 2; +  n -= 2; + +  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + n, PBUF_RAM); +  if(!pb) { +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return PPPERR_ALLOC; +  } + +  pbuf_header(pb, -pppoe_hdrlen); + +  pc->lastXMit = sys_jiffies(); + +  MEMCPY(pb->payload, s, n); + +  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { +    LINK_STATS_INC(link.err); +    return PPPERR_DEVICE; +  } + +  LINK_STATS_INC(link.xmit); +  return PPPERR_NONE; +} +#endif /* PPPOE_SUPPORT */ + +/* + * Write n characters to a ppp link. + *  RETURN: >= 0 Number of characters written + *           -1 Failed to write to device + */ +int +pppWrite(int pd, const u_char *s, int n) +{ +  PPPControl *pc = &pppControl[pd]; +#if PPPOS_SUPPORT +  u_char c; +  u_int fcsOut; +  struct pbuf *headMB, *tailMB; +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    return pppWriteOverEthernet(pd, s, n); +  } +#endif /* PPPOE_SUPPORT */ + +#if PPPOS_SUPPORT +  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +  if (headMB == NULL) { +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return PPPERR_ALLOC; +  } + +  tailMB = headMB; + +  /* If the link has been idle, we'll send a fresh flag character to +   * flush any noise. */ +  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) { +    tailMB = pppAppend(PPP_FLAG, tailMB, NULL); +  } +  pc->lastXMit = sys_jiffies(); + +  fcsOut = PPP_INITFCS; +  /* Load output buffer. */ +  while (n-- > 0) { +    c = *s++; + +    /* Update FCS before checking for special characters. */ +    fcsOut = PPP_FCS(fcsOut, c); + +    /* Copy to output buffer escaping special characters. */ +    tailMB = pppAppend(c, tailMB, &pc->outACCM); +  } +     +  /* Add FCS and trailing flag. */ +  c = ~fcsOut & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  c = (~fcsOut >> 8) & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + +  /* If we failed to complete the packet, throw it away. +   * Otherwise send it. */ +  if (!tailMB) { +    PPPDEBUG((LOG_WARNING, +             "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len)); +           /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ +    pbuf_free(headMB); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return PPPERR_ALLOC; +  } + +  PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len)); +                   /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ +  nPut(pc, headMB); +#endif /* PPPOS_SUPPORT */ + +  return PPPERR_NONE; +} + +/* + * ppp_send_config - configure the transmit characteristics of + * the ppp interface. + */ +void +ppp_send_config( int unit, int mtu, u32_t asyncmap, int pcomp, int accomp) +{ +  PPPControl *pc = &pppControl[unit]; +  int i; +   +  pc->mtu = mtu; +  pc->pcomp = pcomp; +  pc->accomp = accomp; +   +  /* Load the ACCM bits for the 32 control codes. */ +  for (i = 0; i < 32/8; i++) { +    pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF); +  } +  PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n", +            unit, +            pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3])); +} + + +/* + * ppp_set_xaccm - set the extended transmit ACCM for the interface. + */ +void +ppp_set_xaccm(int unit, ext_accm *accm) +{ +  SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm)); +  PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n", +            unit, +            pppControl[unit].outACCM[0], +            pppControl[unit].outACCM[1], +            pppControl[unit].outACCM[2], +            pppControl[unit].outACCM[3])); +} + + +/* + * ppp_recv_config - configure the receive-side characteristics of + * the ppp interface. + */ +void +ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp) +{ +  PPPControl *pc = &pppControl[unit]; +  int i; + +  LWIP_UNUSED_ARG(accomp); +  LWIP_UNUSED_ARG(pcomp); +  LWIP_UNUSED_ARG(mru); + +  /* Load the ACCM bits for the 32 control codes. */ +  for (i = 0; i < 32 / 8; i++) { +    pc->inACCM[i] = (u_char)(asyncmap >> (i * 8)); +  } +  PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n", +            unit, +            pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3])); +} + +#if 0 +/* + * ccp_test - ask kernel whether a given compression method + * is acceptable for use.  Returns 1 if the method and parameters + * are OK, 0 if the method is known but the parameters are not OK + * (e.g. code size should be reduced), or -1 if the method is unknown. + */ +int +ccp_test( int unit, int opt_len,  int for_transmit, u_char *opt_ptr) +{ +  return 0; /* XXX Currently no compression. */ +} + +/* + * ccp_flags_set - inform kernel about the current state of CCP. + */ +void +ccp_flags_set(int unit, int isopen, int isup) +{ +  /* XXX */ +} + +/* + * ccp_fatal_error - returns 1 if decompression was disabled as a + * result of an error detected after decompression of a packet, + * 0 otherwise.  This is necessary because of patent nonsense. + */ +int +ccp_fatal_error(int unit) +{ +  /* XXX */ +  return 0; +} +#endif + +/* + * get_idle_time - return how long the link has been idle. + */ +int +get_idle_time(int u, struct ppp_idle *ip) +{ +  /* XXX */ +  LWIP_UNUSED_ARG(u); +  LWIP_UNUSED_ARG(ip); + +  return 0; +} + + +/* + * Return user specified netmask, modified by any mask we might determine + * for address `addr' (in network byte order). + * Here we scan through the system's list of interfaces, looking for + * any non-point-to-point interfaces which might appear to be on the same + * network as `addr'.  If we find any, we OR in their netmask to the + * user-specified netmask. + */ +u32_t +GetMask(u32_t addr) +{ +  u32_t mask, nmask; + +  htonl(addr); +  if (IN_CLASSA(addr)) { /* determine network mask for address class */ +    nmask = IN_CLASSA_NET; +  } else if (IN_CLASSB(addr)) { +    nmask = IN_CLASSB_NET; +  } else {  +    nmask = IN_CLASSC_NET; +  } + +  /* class D nets are disallowed by bad_ip_adrs */ +  mask = subnetMask | htonl(nmask); +   +  /* XXX +   * Scan through the system's network interfaces. +   * Get each netmask and OR them into our mask. +   */ + +  return mask; +} + +/* + * sifvjcomp - config tcp header compression + */ +int +sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid) +{ +#if PPPOS_SUPPORT && VJ_SUPPORT +  PPPControl *pc = &pppControl[pd]; +   +  pc->vjEnabled = vjcomp; +  pc->vjComp.compressSlot = cidcomp; +  pc->vjComp.maxSlotIndex = maxcid; +  PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n", +            vjcomp, cidcomp, maxcid)); +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + +  return 0; +} + +/* + * pppifNetifInit - netif init callback + */ +static err_t +pppifNetifInit(struct netif *netif) +{ +  netif->name[0] = 'p'; +  netif->name[1] = 'p'; +  netif->output = pppifOutput; +  netif->mtu = pppMTU((int)netif->state); +  return ERR_OK; +} + + +/* + * sifup - Config the interface up and enable IP packets to pass. + */ +int +sifup(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    netif_remove(&pc->netif); +    if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) { +      netif_set_up(&pc->netif); +      pc->if_up = 1; +      pc->errCode = PPPERR_NONE; + +      PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); +      if(pc->linkStatusCB) { +        pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs); +      } +    } else { +      st = 0; +      PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd)); +    } +  } + +  return st; +} + +/* + * sifnpmode - Set the mode for handling packets for a given NP. + */ +int +sifnpmode(int u, int proto, enum NPmode mode) +{ +  LWIP_UNUSED_ARG(u); +  LWIP_UNUSED_ARG(proto); +  LWIP_UNUSED_ARG(mode); +  return 0; +} + +/* + * sifdown - Config the interface down and disable IP. + */ +int +sifdown(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd)); +  } else { +    pc->if_up = 0; +    netif_remove(&pc->netif); +    PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); +    if(pc->linkStatusCB) { +      pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL); +    } +  } +  return st; +} + +/** + * sifaddr - Config the interface IP addresses and netmask. + * @param pd Interface unit ??? + * @param o Our IP address ??? + * @param h His IP address ??? + * @param m IP subnet mask ??? + * @param ns1 Primary DNS + * @param ns2 Secondary DNS + */ +int +sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o)); +    SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h)); +    SMEMCPY(&pc->addrs.netmask, &m, sizeof(m)); +    SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1)); +    SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2)); +  } +  return st; +} + +/** + * cifaddr - Clear the interface IP addresses, and delete routes + * through the interface if possible. + * @param pd Interface unit ??? + * @param o Our IP address ??? + * @param h IP broadcast address ??? + */ +int +cifaddr( int pd, u32_t o, u32_t h) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  LWIP_UNUSED_ARG(o); +  LWIP_UNUSED_ARG(h); +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0); +    IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0); +    IP4_ADDR(&pc->addrs.netmask, 255,255,255,0); +    IP4_ADDR(&pc->addrs.dns1, 0,0,0,0); +    IP4_ADDR(&pc->addrs.dns2, 0,0,0,0); +  } +  return st; +} + +/* + * sifdefaultroute - assign a default route through the address given. + */ +int +sifdefaultroute(int pd, u32_t l, u32_t g) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; + +  LWIP_UNUSED_ARG(l); +  LWIP_UNUSED_ARG(g); + +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    netif_set_default(&pc->netif); +  } + +  /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */ + +  return st; +} + +/* + * cifdefaultroute - delete a default route through the address given. + */ +int +cifdefaultroute(int pd, u32_t l, u32_t g) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; + +  LWIP_UNUSED_ARG(l); +  LWIP_UNUSED_ARG(g); + +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    netif_set_default(NULL); +  } + +  return st; +} + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +#if PPPOS_SUPPORT +/* The main PPP process function.  This implements the state machine according + * to section 4 of RFC 1661: The Point-To-Point Protocol. */ +static void +pppMain(void *arg) +{ +  int pd = (int)arg; +  struct pbuf *p; +  PPPControl* pc; +  int c; + +  pc = &pppControl[pd]; + +  p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM); +  if (!p) { +    LWIP_ASSERT("p != NULL", p); +    pc->errCode = PPPERR_ALLOC; +    goto out; +  } + +  /* +   * Start the connection and handle incoming events (packet or timeout). +   */ +  PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd)); +  tcpip_callback(pppStartCB, arg); +  while (lcp_phase[pd] != PHASE_DEAD) { +    if (pc->kill_link) { +      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d kill_link -> pppStopCB\n", pd)); +      pc->errCode = PPPERR_USER; +      /* This will leave us at PHASE_DEAD. */ +      tcpip_callback(pppStopCB, arg); +      pc->kill_link = 0; +    } else if (pc->sig_hup) { +      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sig_hup -> pppHupCB\n", pd)); +      pc->sig_hup = 0; +      tcpip_callback(pppHupCB, arg); +    } else { +      c = sio_read(pc->fd, p->payload, p->len); +      if(c > 0) { +        pppInProc(pd, p->payload, c); +      } else { +        PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sio_read len=%d returned %d\n", pd, p->len, c)); +        sys_msleep(1); /* give other tasks a chance to run */ +      } +    } +  } +  PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd)); +  pppDrop(pc); /* bug fix #17726 */ +  pbuf_free(p); + +out: +  PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); +  if(pc->linkStatusCB) { +    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); +  } + +  pc->openFlag = 0; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT + +void +pppOverEthernetInitFailed(void* arg) +{ +  PPPControl* pc; +  int pd = (int)arg; + +  pppHupCB(arg); +  pppStopCB(arg); + +  pc = &pppControl[pd]; +  pppoe_destroy(&pc->netif); +  pc->openFlag = 0; + +  if(pc->linkStatusCB) { +    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); +  } +} + +static void +pppOverEthernetLinkStatusCB(int pd, int up) +{ +  if(up) { +    PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd)); +    tcpip_callback(pppStartCB, (void*)pd); +  } else { +    PPPControl* pc; +    pc = &pppControl[pd]; +    tcpip_callback(pppOverEthernetInitFailed, (void*)pd); +  } +} +#endif /* PPPOE_SUPPORT */ + +struct pbuf * +pppSingleBuf(struct pbuf *p) +{ +  struct pbuf *q, *b; +  u_char *pl; + +  if(p->tot_len == p->len) { +    return p; +  } + +  q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); +  if(!q) { +    PPPDEBUG((LOG_ERR, +             "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len)); +    return p; /* live dangerously */ +  } + +  for(b = p, pl = q->payload; b != NULL; b = b->next) { +    MEMCPY(pl, b->payload, b->len); +    pl += b->len; +  } + +  pbuf_free(p); + +  return q; +} + +struct pppInputHeader { +  int unit; +  u16_t proto; +}; + +/* + * Pass the processed input packet to the appropriate handler. + * This function and all handlers run in the context of the tcpip_thread + */ +static void +pppInput(void *arg) +{ +  struct pbuf *nb = (struct pbuf *)arg; +  u16_t protocol; +  int pd; + +  pd = ((struct pppInputHeader *)nb->payload)->unit; +  protocol = ((struct pppInputHeader *)nb->payload)->proto; +     +  if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) { +    LWIP_ASSERT("pbuf_header failed\n", 0); +    goto drop; +  } + +  LINK_STATS_INC(link.recv); + +  /* +   * Toss all non-LCP packets unless LCP is OPEN. +   * Until we get past the authentication phase, toss all packets +   * except LCP, LQR and authentication packets. +   */ +  if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) { +    if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) || +        (lcp_phase[pd] != PHASE_AUTHENTICATE)) { +      PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd])); +      goto drop; +    } +  } + +  switch(protocol) { +    case PPP_VJC_COMP:      /* VJ compressed TCP */ +#if VJ_SUPPORT +      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len)); +      /* +       * Clip off the VJ header and prepend the rebuilt TCP/IP header and +       * pass the result to IP. +       */ +      if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) { +        pppControl[pd].netif.input(nb, &pppControl[pd].netif); +        return; +      } +      /* Something's wrong so drop it. */ +      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd)); +#else  /* VJ_SUPPORT */ +      /* No handler for this protocol so drop the packet. */ +      PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload)); +#endif /* VJ_SUPPORT */ +      break; + +    case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */ +#if VJ_SUPPORT +      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len)); +      /* +       * Process the TCP/IP header for VJ header compression and then pass +       * the packet to IP. +       */ +      if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) { +        pppControl[pd].netif.input(nb, &pppControl[pd].netif); +        return; +      } +      /* Something's wrong so drop it. */ +      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd)); +#else  /* VJ_SUPPORT */ +      /* No handler for this protocol so drop the packet. */ +      PPPDEBUG((LOG_INFO, +               "pppInput[%d]: drop VJ UnComp in %d:.*H\n",  +                pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload)); +#endif /* VJ_SUPPORT */ +      break; + +    case PPP_IP:            /* Internet Protocol */ +      PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len)); +      if (pppControl[pd].netif.input) { +        pppControl[pd].netif.input(nb, &pppControl[pd].netif); +        return; +      } +      break; + +    default: { +      struct protent *protp; +      int i; + +      /* +       * Upcall the proper protocol input routine. +       */ +      for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +        if (protp->protocol == protocol && protp->enabled_flag) { +          PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len)); +          nb = pppSingleBuf(nb); +          (*protp->input)(pd, nb->payload, nb->len); +          goto out; +        } +      } + +      /* No handler for this protocol so reject the packet. */ +      PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len)); +      if (pbuf_header(nb, sizeof(protocol))) { +        LWIP_ASSERT("pbuf_header failed\n", 0); +        goto drop; +      } +#if BYTE_ORDER == LITTLE_ENDIAN +      protocol = htons(protocol); +      SMEMCPY(nb->payload, &protocol, sizeof(protocol)); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +      lcp_sprotrej(pd, nb->payload, nb->len); +    } +    break; +  } + +drop: +  LINK_STATS_INC(link.drop); + +out: +  pbuf_free(nb); +  return; +} + +#if PPPOS_SUPPORT +/* + * Drop the input packet. + */ +static void +pppDrop(PPPControl *pc) +{ +  if (pc->inHead != NULL) { +#if 0 +    PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload)); +#endif +    PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len)); +    if (pc->inTail && (pc->inTail != pc->inHead)) { +      pbuf_free(pc->inTail); +    } +    pbuf_free(pc->inHead); +    pc->inHead = NULL; +    pc->inTail = NULL; +  } +#if VJ_SUPPORT +  vj_uncompress_err(&pc->vjComp); +#endif /* VJ_SUPPORT */ + +  LINK_STATS_INC(link.drop); +} + +/** + * Process a received octet string. + */ +static void +pppInProc(int pd, u_char *s, int l) +{ +  PPPControl *pc = &pppControl[pd]; +  struct pbuf *nextNBuf; +  u_char curChar; + +  PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l)); +  while (l-- > 0) { +    curChar = *s++; +     +    /* Handle special characters. */ +    if (ESCAPE_P(pc->inACCM, curChar)) { +      /* Check for escape sequences. */ +      /* XXX Note that this does not handle an escaped 0x5d character which +       * would appear as an escape character.  Since this is an ASCII ']' +       * and there is no reason that I know of to escape it, I won't complicate +       * the code to handle this case. GLL */ +      if (curChar == PPP_ESCAPE) { +        pc->inEscaped = 1; +      /* Check for the flag character. */ +      } else if (curChar == PPP_FLAG) { +         /* If this is just an extra flag character, ignore it. */ +         if (pc->inState <= PDADDRESS) { +           /* ignore it */; +         /* If we haven't received the packet header, drop what has come in. */ +         } else if (pc->inState < PDDATA) { +           PPPDEBUG((LOG_WARNING, +                    "pppInProc[%d]: Dropping incomplete packet %d\n",  +                     pd, pc->inState)); +           LINK_STATS_INC(link.lenerr); +           pppDrop(pc); +         /* If the fcs is invalid, drop the packet. */ +         } else if (pc->inFCS != PPP_GOODFCS) { +           PPPDEBUG((LOG_INFO, +                    "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n",  +                     pd, pc->inFCS, pc->inProtocol)); +           LINK_STATS_INC(link.chkerr); +           pppDrop(pc); +         /* Otherwise it's a good packet so pass it on. */ +         } else { +           /* Trim off the checksum. */ +           if(pc->inTail->len >= 2) { +             pc->inTail->len -= 2; + +             pc->inTail->tot_len = pc->inTail->len; +             if (pc->inTail != pc->inHead) { +               pbuf_cat(pc->inHead, pc->inTail); +             } +           } else { +             pc->inTail->tot_len = pc->inTail->len; +             if (pc->inTail != pc->inHead) { +               pbuf_cat(pc->inHead, pc->inTail); +             } + +             pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2); +           } + +           /* Dispatch the packet thereby consuming it. */ +           if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) { +             PPPDEBUG((LOG_ERR, "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd)); +             pbuf_free(pc->inHead); +             LINK_STATS_INC(link.drop); +           } +           pc->inHead = NULL; +           pc->inTail = NULL; +         } + +         /* Prepare for a new packet. */ +         pc->inFCS = PPP_INITFCS; +         pc->inState = PDADDRESS; +         pc->inEscaped = 0; +      /* Other characters are usually control characters that may have +       * been inserted by the physical layer so here we just drop them. */ +      } else { +        PPPDEBUG((LOG_WARNING, +                 "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar)); +      } +    /* Process other characters. */ +    } else { +      /* Unencode escaped characters. */ +      if (pc->inEscaped) { +        pc->inEscaped = 0; +        curChar ^= PPP_TRANS; +      } + +      /* Process character relative to current state. */ +      switch(pc->inState) { +        case PDIDLE:                    /* Idle state - waiting. */ +          /* Drop the character if it's not 0xff +           * we would have processed a flag character above. */ +          if (curChar != PPP_ALLSTATIONS) { +            break; +          } + +        /* Fall through */ +        case PDSTART:                   /* Process start flag. */ +          /* Prepare for a new packet. */ +          pc->inFCS = PPP_INITFCS; + +        /* Fall through */ +        case PDADDRESS:                 /* Process address field. */ +          if (curChar == PPP_ALLSTATIONS) { +            pc->inState = PDCONTROL; +            break; +          } +          /* Else assume compressed address and control fields so +           * fall through to get the protocol... */ +        case PDCONTROL:                 /* Process control field. */ +          /* If we don't get a valid control code, restart. */ +          if (curChar == PPP_UI) { +            pc->inState = PDPROTOCOL1; +            break; +          } +#if 0 +          else { +            PPPDEBUG((LOG_WARNING, +                     "pppInProc[%d]: Invalid control <%d>\n", pd, curChar)); +                      pc->inState = PDSTART; +          } +#endif +        case PDPROTOCOL1:               /* Process protocol field 1. */ +          /* If the lower bit is set, this is the end of the protocol +           * field. */ +          if (curChar & 1) { +            pc->inProtocol = curChar; +            pc->inState = PDDATA; +          } else { +            pc->inProtocol = (u_int)curChar << 8; +            pc->inState = PDPROTOCOL2; +          } +          break; +        case PDPROTOCOL2:               /* Process protocol field 2. */ +          pc->inProtocol |= curChar; +          pc->inState = PDDATA; +          break; +        case PDDATA:                    /* Process data byte. */ +          /* Make space to receive processed data. */ +          if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) { +            if(pc->inTail) { +              pc->inTail->tot_len = pc->inTail->len; +              if (pc->inTail != pc->inHead) { +                pbuf_cat(pc->inHead, pc->inTail); +              } +            } +            /* If we haven't started a packet, we need a packet header. */ +            nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +            if (nextNBuf == NULL) { +              /* No free buffers.  Drop the input packet and let the +               * higher layers deal with it.  Continue processing +               * the received pbuf chain in case a new packet starts. */ +              PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd)); +              LINK_STATS_INC(link.memerr); +              pppDrop(pc); +              pc->inState = PDSTART;  /* Wait for flag sequence. */ +              break; +            } +            if (pc->inHead == NULL) { +              struct pppInputHeader *pih = nextNBuf->payload; + +              pih->unit = pd; +              pih->proto = pc->inProtocol; + +              nextNBuf->len += sizeof(*pih); + +              pc->inHead = nextNBuf; +            } +            pc->inTail = nextNBuf; +          } +          /* Load character into buffer. */ +          ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar; +          break; +      } + +      /* update the frame check sequence number. */ +      pc->inFCS = PPP_FCS(pc->inFCS, curChar); +    } +  } + +  avRandomize(); +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +void +pppInProcOverEthernet(int pd, struct pbuf *pb) +{ +  struct pppInputHeader *pih; +  u16_t inProtocol; + +  if(pb->len < sizeof(inProtocol)) { +    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: too small for protocol field\n")); +    goto drop; +  } + +  inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1]; + +  /* make room for pppInputHeader - should not fail */ +  if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) { +    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: could not allocate room for header\n")); +    goto drop; +  } + +  pih = pb->payload; + +  pih->unit = pd; +  pih->proto = inProtocol; + +  /* Dispatch the packet thereby consuming it. */ +  if(tcpip_callback(pppInput, pb) != ERR_OK) { +    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet[%d]: tcpip_callback() failed, dropping packet\n", pd)); +    goto drop; +  } + +  return; + +drop: +  LINK_STATS_INC(link.drop); +  pbuf_free(pb); +  return; +} +#endif /* PPPOE_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp.h new file mode 100644 index 000000000..d5caa0a7e --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp.h @@ -0,0 +1,465 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ + +#ifndef PPP_H +#define PPP_H + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/sio.h" +#include "lwip/api.h" +#include "lwip/sockets.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/tcpip.h" +#include "lwip/netif.h" + +/* + * pppd.h - PPP daemon global declarations. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ +/* + * ppp_defs.h - PPP definitions. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies.  This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +#define TIMEOUT(f, a, t)    sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a)) +#define UNTIMEOUT(f, a)     sys_untimeout((f), (a)) + + +#ifndef __u_char_defined + +/* Type definitions for BSD code. */ +typedef unsigned long  u_long; +typedef unsigned int   u_int; +typedef unsigned short u_short; +typedef unsigned char  u_char; + +#endif + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981, and numerous additions. + */ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN      4       /* octets for standard ppp header */ +#define PPP_FCSLEN      2       /* octets for FCS */ + + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */ +#define PPP_UI          0x03    /* Unnumbered Information */ +#define PPP_FLAG        0x7e    /* Flag Sequence */ +#define PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */ +#define PPP_TRANS       0x20    /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP          0x21    /* Internet Protocol */ +#define PPP_AT          0x29    /* AppleTalk Protocol */ +#define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */ +#define PPP_COMP        0xfd    /* compressed packet */ +#define PPP_IPCP        0x8021  /* IP Control Protocol */ +#define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */ +#define PPP_CCP         0x80fd  /* Compression Control Protocol */ +#define PPP_LCP         0xc021  /* Link Control Protocol */ +#define PPP_PAP         0xc023  /* Password Authentication Protocol */ +#define PPP_LQR         0xc025  /* Link Quality Report protocol */ +#define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP        0xc029  /* Callback Control Protocol */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS     0xffff  /* Initial FCS value */ +#define PPP_GOODFCS     0xf0b8  /* Good final FCS value */ +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u_char  ext_accm[32]; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { +  NPMODE_PASS,        /* pass the packet through */ +  NPMODE_DROP,        /* silently drop the packet */ +  NPMODE_ERROR,       /* return an error */ +  NPMODE_QUEUE        /* save it up for later. */ +}; + +/* + * Inline versions of get/put char/short/long. + * Pointer is advanced; we assume that both arguments + * are lvalues and will already be in registers. + * cp MUST be u_char *. + */ +#define GETCHAR(c, cp) { \ +    (c) = *(cp)++; \ +} +#define PUTCHAR(c, cp) { \ +    *(cp)++ = (u_char) (c); \ +} + + +#define GETSHORT(s, cp) { \ +    (s) = *(cp); (cp)++; (s) <<= 8; \ +    (s) |= *(cp); (cp)++; \ +} +#define PUTSHORT(s, cp) { \ +    *(cp)++ = (u_char) ((s) >> 8); \ +    *(cp)++ = (u_char) (s & 0xff); \ +} + +#define GETLONG(l, cp) { \ +    (l) = *(cp); (cp)++; (l) <<= 8; \ +    (l) |= *(cp); (cp)++; (l) <<= 8; \ +    (l) |= *(cp); (cp)++; (l) <<= 8; \ +    (l) |= *(cp); (cp)++; \ +} +#define PUTLONG(l, cp) { \ +    *(cp)++ = (u_char) ((l) >> 24); \ +    *(cp)++ = (u_char) ((l) >> 16); \ +    *(cp)++ = (u_char) ((l) >> 8); \ +    *(cp)++ = (u_char) (l); \ +} + + +#define INCPTR(n, cp)   ((cp) += (n)) +#define DECPTR(n, cp)   ((cp) -= (n)) + +#define BCMP(s0, s1, l)     memcmp((u_char *)(s0), (u_char *)(s1), (l)) +#define BCOPY(s, d, l)      MEMCPY((d), (s), (l)) +#define BZERO(s, n)         memset(s, 0, n) + +#if PPP_DEBUG +#define PRINTMSG(m, l)  { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); } +#else  /* PPP_DEBUG */ +#define PRINTMSG(m, l) +#endif /* PPP_DEBUG */ + +/* + * MAKEHEADER - Add PPP Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ +    PUTCHAR(PPP_ALLSTATIONS, p); \ +    PUTCHAR(PPP_UI, p); \ +    PUTSHORT(t, p); } + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* Error codes. */ +#define PPPERR_NONE      0 /* No error. */ +#define PPPERR_PARAM    -1 /* Invalid parameter. */ +#define PPPERR_OPEN     -2 /* Unable to open PPP session. */ +#define PPPERR_DEVICE   -3 /* Invalid I/O device for PPP. */ +#define PPPERR_ALLOC    -4 /* Unable to allocate resources. */ +#define PPPERR_USER     -5 /* User interrupt. */ +#define PPPERR_CONNECT  -6 /* Connection lost. */ +#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */ +#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */ + +/* + * PPP IOCTL commands. + */ +/* + * Get the up status - 0 for down, non-zero for up.  The argument must + * point to an int. + */ +#define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */ +#define PPPCTLS_ERRCODE  101 /* Set the error code */ +#define PPPCTLG_ERRCODE  102 /* Get the error code */ +#define PPPCTLG_FD       103 /* Get the fd associated with the ppp */ + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * The following struct gives the addresses of procedures to call + * for a particular protocol. + */ +struct protent { +    u_short protocol;       /* PPP protocol number */ +    /* Initialization procedure */ +    void (*init) (int unit); +    /* Process a received packet */ +    void (*input) (int unit, u_char *pkt, int len); +    /* Process a received protocol-reject */ +    void (*protrej) (int unit); +    /* Lower layer has come up */ +    void (*lowerup) (int unit); +    /* Lower layer has gone down */ +    void (*lowerdown) (int unit); +    /* Open the protocol */ +    void (*open) (int unit); +    /* Close the protocol */ +    void (*close) (int unit, char *reason); +#if 0 +    /* Print a packet in readable form */ +    int  (*printpkt) (u_char *pkt, int len, +              void (*printer) (void *, char *, ...), +              void *arg); +    /* Process a received data packet */ +    void (*datainput) (int unit, u_char *pkt, int len); +#endif +    int  enabled_flag;      /* 0 iff protocol is disabled */ +    char *name;         /* Text name of protocol */ +#if 0 +    /* Check requested options, assign defaults */ +    void (*check_options) (u_long); +    /* Configure interface for demand-dial */ +    int  (*demand_conf) (int unit); +    /* Say whether to bring up link for this pkt */ +    int  (*active_pkt) (u_char *pkt, int len); +#endif +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { +  u_short xmit_idle;      /* seconds since last NP packet sent */ +  u_short recv_idle;      /* seconds since last NP packet received */ +}; + +struct ppp_settings { + +  u_int  disable_defaultip : 1;       /* Don't use hostname for default IP addrs */ +  u_int  auth_required     : 1;       /* Peer is required to authenticate */ +  u_int  explicit_remote   : 1;       /* remote_name specified with remotename opt */ +  u_int  refuse_pap        : 1;       /* Don't wanna auth. ourselves with PAP */ +  u_int  refuse_chap       : 1;       /* Don't wanna auth. ourselves with CHAP */ +  u_int  usehostname       : 1;       /* Use hostname for our_name */ +  u_int  usepeerdns        : 1;       /* Ask peer for DNS adds */ + +  u_short idle_time_limit;            /* Shut down link if idle for this long */ +  int  maxconnect;                    /* Maximum connect time (seconds) */ + +  char user       [MAXNAMELEN   + 1]; /* Username for PAP */ +  char passwd     [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */ +  char our_name   [MAXNAMELEN   + 1]; /* Our name for authentication purposes */ +  char remote_name[MAXNAMELEN   + 1]; /* Peer's name for authentication */ +}; + +struct ppp_addrs { +  struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2; +}; + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +/* Buffers for outgoing packets. */ +extern u_char *outpacket_buf[NUM_PPP]; + +extern struct ppp_settings ppp_settings; + +extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */ + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* Initialize the PPP subsystem. */ +err_t pppInit(void); + +/* Warning: Using PPPAUTHTYPE_ANY might have security consequences. + * RFC 1994 says: + * + * In practice, within or associated with each PPP server, there is a + * database which associates "user" names with authentication + * information ("secrets").  It is not anticipated that a particular + * named user would be authenticated by multiple methods.  This would + * make the user vulnerable to attacks which negotiate the least secure + * method from among a set (such as PAP rather than CHAP).  If the same + * secret was used, PAP would reveal the secret to be used later with + * CHAP. + * + * Instead, for each user name there should be an indication of exactly + * one method used to authenticate that user name.  If a user needs to + * make use of different authentication methods under different + * circumstances, then distinct user names SHOULD be employed, each of + * which identifies exactly one authentication method. + * + */ +enum pppAuthType { +    PPPAUTHTYPE_NONE, +    PPPAUTHTYPE_ANY, +    PPPAUTHTYPE_PAP, +    PPPAUTHTYPE_CHAP +}; + +void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd); + +/* + * Open a new PPP connection using the given serial I/O device. + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session. + * Return a new PPP connection descriptor on success or + * an error code (negative) on failure.  + */ +int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx); + +/* + * Open a new PPP Over Ethernet (PPPOE) connection. + */ +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx); + +/* for source code compatibility */ +#define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls) + +/* + * Close a PPP connection and release the descriptor.  + * Any outstanding packets in the queues are dropped. + * Return 0 on success, an error code on failure.  + */ +int pppClose(int pd); + +/* + * Indicate to the PPP process that the line has disconnected. + */ +void pppSigHUP(int pd); + +/* + * Get and set parameters for the given connection. + * Return 0 on success, an error code on failure.  + */ +int  pppIOCtl(int pd, int cmd, void *arg); + +/* + * Return the Maximum Transmission Unit for the given PPP connection. + */ +u_int pppMTU(int pd); + +/* + * Write n characters to a ppp link. + * RETURN: >= 0 Number of characters written, -1 Failed to write to device. + */ +int pppWrite(int pd, const u_char *s, int n); + +void pppInProcOverEthernet(int pd, struct pbuf *pb); + +struct pbuf *pppSingleBuf(struct pbuf *p); + +void pppLinkTerminated(int pd); + +void pppLinkDown(int pd); + +void pppMainWakeup(int pd); + +/* Configure i/f transmit parameters */ +void ppp_send_config (int, int, u32_t, int, int); +/* Set extended transmit ACCM */ +void ppp_set_xaccm (int, ext_accm *); +/* Configure i/f receive parameters */ +void ppp_recv_config (int, int, u32_t, int, int); +/* Find out how long link has been idle */ +int  get_idle_time (int, struct ppp_idle *); + +/* Configure VJ TCP header compression */ +int  sifvjcomp (int, int, int, int); +/* Configure i/f down (for IP) */ +int  sifup (int); +/* Set mode for handling packets for proto */ +int  sifnpmode (int u, int proto, enum NPmode mode); +/* Configure i/f down (for IP) */ +int  sifdown (int); +/* Configure IP addresses for i/f */ +int  sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t); +/* Reset i/f IP addresses */ +int  cifaddr (int, u32_t, u32_t); +/* Create default route through i/f */ +int  sifdefaultroute (int, u32_t, u32_t); +/* Delete default route through i/f */ +int  cifdefaultroute (int, u32_t, u32_t); + +/* Get appropriate netmask for address */ +u32_t GetMask (u32_t);  + +#endif /* PPP_SUPPORT */ + +#endif /* PPP_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c new file mode 100644 index 000000000..c34c529b6 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c @@ -0,0 +1,1227 @@ +/***************************************************************************** +* ppp_oe.c - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann <martin@NetBSD.org>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *        This product includes software developed by the NetBSD + *        Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + *    contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "lwip/opt.h" + +#if PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "lwip/sys.h" + +#include "netif/ppp_oe.h" +#include "netif/etharp.h" + +#include <string.h> +#include <stdio.h> + +/** @todo Replace this part with a simple list like other lwIP lists */ +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List declarations. + */ +#define  LIST_HEAD(name, type)                                                 \ +struct name {                                                                  \ +  struct type *lh_first;  /* first element */                                  \ +} + +#define  LIST_HEAD_INITIALIZER(head)                                           \ +  { NULL } + +#define  LIST_ENTRY(type)                                                      \ +struct {                                                                       \ +  struct type *le_next;  /* next element */                                    \ +  struct type **le_prev; /* address of previous next element */                \ +} + +/* + * List functions. + */ + +#define  LIST_EMPTY(head)  ((head)->lh_first == NULL) + +#define  LIST_FIRST(head)  ((head)->lh_first) + +#define  LIST_FOREACH(var, head, field)                                        \ +  for ((var) = LIST_FIRST((head));                                             \ +      (var);                                                                   \ +      (var) = LIST_NEXT((var), field)) + +#define  LIST_INIT(head) do {                                                  \ +  LIST_FIRST((head)) = NULL;                                                   \ +} while (0) + +#define  LIST_INSERT_AFTER(listelm, elm, field) do {                           \ +  if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)         \ +    LIST_NEXT((listelm), field)->field.le_prev =                               \ +        &LIST_NEXT((elm), field);                                              \ +  LIST_NEXT((listelm), field) = (elm);                                         \ +  (elm)->field.le_prev = &LIST_NEXT((listelm), field);                         \ +} while (0) + +#define  LIST_INSERT_BEFORE(listelm, elm, field) do {                          \ +  (elm)->field.le_prev = (listelm)->field.le_prev;                             \ +  LIST_NEXT((elm), field) = (listelm);                                         \ +  *(listelm)->field.le_prev = (elm);                                           \ +  (listelm)->field.le_prev = &LIST_NEXT((elm), field);                         \ +} while (0) + +#define  LIST_INSERT_HEAD(head, elm, field) do {                               \ +  if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)                  \ +    LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);              \ +  LIST_FIRST((head)) = (elm);                                                  \ +  (elm)->field.le_prev = &LIST_FIRST((head));                                  \ +} while (0) + +#define  LIST_NEXT(elm, field)  ((elm)->field.le_next) + +#define  LIST_REMOVE(elm, field) do {                                          \ +  if (LIST_NEXT((elm), field) != NULL)                                         \ +    LIST_NEXT((elm), field)->field.le_prev =                                   \ +        (elm)->field.le_prev;                                                  \ +  *(elm)->field.le_prev = LIST_NEXT((elm), field);                             \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ + + +/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ +#define PPPOE_ADD_16(PTR, VAL) \ +    *(PTR)++ = (VAL) / 256;    \ +    *(PTR)++ = (VAL) % 256 + +/* Add a complete PPPoE header to the buffer pointed to by PTR */ +#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN)  \ +    *(PTR)++ = PPPOE_VERTYPE;  \ +    *(PTR)++ = (CODE);         \ +    PPPOE_ADD_16(PTR, SESS);   \ +    PPPOE_ADD_16(PTR, LEN) + +#define PPPOE_DISC_TIMEOUT (5*1000)  /* base for quick timeout calculation */ +#define PPPOE_SLOW_RETRY   (60*1000) /* persistent retry interval */ +#define PPPOE_DISC_MAXPADI  4        /* retry PADI four times (quickly) */ +#define PPPOE_DISC_MAXPADR  2        /* retry PADR twice */ + +#ifdef PPPOE_SERVER +/* from if_spppsubr.c */ +#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ +#endif + +struct pppoe_softc { +  LIST_ENTRY(pppoe_softc) sc_list; +  struct netif *sc_ethif;      /* ethernet interface we are using */ +  int sc_pd;                   /* ppp unit number */ +  void (*sc_linkStatusCB)(int pd, int up); + +  int sc_state;                /* discovery phase or session connected */ +  struct eth_addr sc_dest;     /* hardware address of concentrator */ +  u16_t sc_session;            /* PPPoE session id */ + +  char *sc_service_name;       /* if != NULL: requested name of service */ +  char *sc_concentrator_name;  /* if != NULL: requested concentrator id */ +  u8_t *sc_ac_cookie;          /* content of AC cookie we must echo back */ +  size_t sc_ac_cookie_len;     /* length of cookie data */ +#ifdef PPPOE_SERVER +  u8_t *sc_hunique;            /* content of host unique we must echo back */ +  size_t sc_hunique_len;       /* length of host unique */ +#endif +  int sc_padi_retried;         /* number of PADI retries already done */ +  int sc_padr_retried;         /* number of PADR retries already done */ +}; + +/* input routines */ +static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *); + +/* management routines */ +static int pppoe_do_disconnect(struct pppoe_softc *); +static void pppoe_abort_connect(struct pppoe_softc *); +static void pppoe_clear_softc(struct pppoe_softc *, const char *); + +/* internal timeout handling */ +static void pppoe_timeout(void *); + +/* sending actual protocol controll packets */ +static err_t pppoe_send_padi(struct pppoe_softc *); +static err_t pppoe_send_padr(struct pppoe_softc *); +#ifdef PPPOE_SERVER +static err_t pppoe_send_pado(struct pppoe_softc *); +static err_t pppoe_send_pads(struct pppoe_softc *); +#endif +static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); + +/* internal helper functions */ +static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *); +static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *); + +static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list; + +int pppoe_hdrlen; + +void +pppoe_init(void) +{ +  pppoe_hdrlen = sizeof(struct eth_hdr) + PPPOE_HEADERLEN; +  LIST_INIT(&pppoe_softc_list); +} + +err_t +pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr) +{ +  struct pppoe_softc *sc; + +  sc = mem_malloc(sizeof(struct pppoe_softc)); +  if(!sc) { +    *scptr = NULL; +    return ERR_MEM; +  } +  memset(sc, 0, sizeof(struct pppoe_softc)); + +  /* changed to real address later */ +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + +  sc->sc_pd = pd; +  sc->sc_linkStatusCB = linkStatusCB; +  sc->sc_ethif = ethif; + +  LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list); + +  *scptr = sc; + +  return ERR_OK; +} + +err_t +pppoe_destroy(struct netif *ifp) +{ +  struct pppoe_softc * sc; + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc->sc_ethif == ifp) { +      break; +    } +  } + +  if(!(sc && (sc->sc_ethif == ifp))) { +    return ERR_IF; +  } + +  tcpip_untimeout(pppoe_timeout, sc); +  LIST_REMOVE(sc, sc_list); + +  if (sc->sc_concentrator_name) { +    mem_free(sc->sc_concentrator_name); +  } +  if (sc->sc_service_name) { +    mem_free(sc->sc_service_name); +  } +  if (sc->sc_ac_cookie) { +    mem_free(sc->sc_ac_cookie); +  } +  mem_free(sc); + +  return ERR_OK; +} + +/* + * Find the interface handling the specified session. + * Note: O(number of sessions open), this is a client-side only, mean + * and lean implementation, so number of open sessions typically should + * be 1. + */ +static struct pppoe_softc * +pppoe_find_softc_by_session(u_int session, struct netif *rcvif) +{ +  struct pppoe_softc *sc; + +  if (session == 0) { +    return NULL; +  } + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc->sc_state == PPPOE_STATE_SESSION +        && sc->sc_session == session) { +      if (sc->sc_ethif == rcvif) { +        return sc; +      } else { +        return NULL; +      } +    } +  } +  return NULL; +} + +/* Check host unique token passed and return appropriate softc pointer, + * or NULL if token is bogus. */ +static struct pppoe_softc * +pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) +{ +  struct pppoe_softc *sc, *t; + +  if (LIST_EMPTY(&pppoe_softc_list)) { +    return NULL; +  } + +  if (len != sizeof sc) { +    return NULL; +  } +  MEMCPY(&t, token, len); + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc == t) { +      break; +    } +  } + +  if (sc == NULL) { +    PPPDEBUG((LOG_DEBUG, "pppoe: alien host unique tag, no session found\n")); +    return NULL; +  } + +  /* should be safe to access *sc now */ +  if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { +    printf("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n", +      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state); +    return NULL; +  } +  if (sc->sc_ethif != rcvif) { +    printf("%c%c%"U16_F": wrong interface, not accepting host unique\n", +      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +    return NULL; +  } +  return sc; +} + +static void +pppoe_linkstatus_up(void *arg) +{ +  struct pppoe_softc *sc = (struct pppoe_softc*)arg; + +  sc->sc_linkStatusCB(sc->sc_pd, 1); +} + +/* analyze and handle a single received packet while not in session state */ +static void +pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb) +{ +  u16_t tag, len; +  u16_t session, plen; +  struct pppoe_softc *sc; +  const char *err_msg; +  char devname[6]; +  char *error; +  u8_t *ac_cookie; +  size_t ac_cookie_len; +#ifdef PPPOE_SERVER +  u8_t *hunique; +  size_t hunique_len; +#endif +  struct pppoehdr *ph; +  struct pppoetag pt; +  int off = 0, err, errortag; +  struct eth_hdr *ethhdr; + +  pb = pppSingleBuf(pb); + +  strcpy(devname, "pppoe");  /* as long as we don't know which instance */ +  err_msg = NULL; +  errortag = 0; +  if (pb->len < sizeof(*ethhdr)) { +    goto done; +  } +  ethhdr = (struct eth_hdr *)pb->payload; +  off += sizeof(*ethhdr); + +  ac_cookie = NULL; +  ac_cookie_len = 0; +#ifdef PPPOE_SERVER +  hunique = NULL; +  hunique_len = 0; +#endif +  session = 0; +  if (pb->len - off <= PPPOE_HEADERLEN) { +    printf("pppoe: packet too short: %d\n", pb->len); +    goto done; +  } + +  ph = (struct pppoehdr *) (ethhdr + 1); +  if (ph->vertype != PPPOE_VERTYPE) { +    printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype); +    goto done; +  } +  session = ntohs(ph->session); +  plen = ntohs(ph->plen); +  off += sizeof(*ph); + +  if (plen + off > pb->len) { +    printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n", +        pb->len - off, plen); +    goto done; +  } +  if(pb->tot_len == pb->len) { +    pb->tot_len = pb->len = off + plen; /* ignore trailing garbage */ +  } +  tag = 0; +  len = 0; +  sc = NULL; +  while (off + sizeof(pt) <= pb->len) { +    MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); +    tag = ntohs(pt.tag); +    len = ntohs(pt.len); +    if (off + sizeof(pt) + len > pb->len) { +      printf("pppoe: tag 0x%x len 0x%x is too long\n", tag, len); +      goto done; +    } +    switch (tag) { +      case PPPOE_TAG_EOL: +        goto breakbreak; +      case PPPOE_TAG_SNAME: +        break;  /* ignored */ +      case PPPOE_TAG_ACNAME: +        break;  /* ignored */ +      case PPPOE_TAG_HUNIQUE: +        if (sc != NULL) { +          break; +        } +#ifdef PPPOE_SERVER +        hunique = (u8_t*)pb->payload + off + sizeof(pt); +        hunique_len = len; +#endif +        sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif); +        if (sc != NULL) { +          snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +        } +        break; +      case PPPOE_TAG_ACCOOKIE: +        if (ac_cookie == NULL) { +          ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); +          ac_cookie_len = len; +        } +        break; +      case PPPOE_TAG_SNAME_ERR: +        err_msg = "SERVICE NAME ERROR"; +        errortag = 1; +        break; +      case PPPOE_TAG_ACSYS_ERR: +        err_msg = "AC SYSTEM ERROR"; +        errortag = 1; +        break; +      case PPPOE_TAG_GENERIC_ERR: +        err_msg = "GENERIC ERROR"; +        errortag = 1; +        break; +    } +    if (err_msg) { +      error = NULL; +      if (errortag && len) { +        error = mem_malloc(len+1); +        if (error) { +          strncpy(error, (char*)pb->payload + off + sizeof(pt), len); +          error[len-1] = '\0'; +        } +      } +      if (error) { +        printf("%s: %s: %s\n", devname, err_msg, error); +        mem_free(error); +      } else { +        printf("%s: %s\n", devname, err_msg); +      } +      if (errortag) { +        goto done; +      } +    } +    off += sizeof(pt) + len; +  } + +breakbreak:; +  switch (ph->code) { +    case PPPOE_CODE_PADI: +#ifdef PPPOE_SERVER +      /* +       * got service name, concentrator name, and/or host unique. +       * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP. +       */ +      if (LIST_EMPTY(&pppoe_softc_list)) { +        goto done; +      } +      LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +        if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) { +          continue; +        } +        if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { +          continue; +        } +        if (sc->sc_state == PPPOE_STATE_INITIAL) { +          break; +        } +      } +      if (sc == NULL) { +        /* printf("pppoe: free passive interface is not found\n"); */ +        goto done; +      } +      if (hunique) { +        if (sc->sc_hunique) { +          mem_free(sc->sc_hunique); +        } +        sc->sc_hunique = mem_malloc(hunique_len); +        if (sc->sc_hunique == NULL) { +          goto done; +        } +        sc->sc_hunique_len = hunique_len; +        MEMCPY(sc->sc_hunique, hunique, hunique_len); +      } +      MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest); +      sc->sc_state = PPPOE_STATE_PADO_SENT; +      pppoe_send_pado(sc); +      break; +  #endif /* PPPOE_SERVER */ +    case PPPOE_CODE_PADR: +  #ifdef PPPOE_SERVER +      /* +       * get sc from ac_cookie if IFF_PASSIVE +       */ +      if (ac_cookie == NULL) { +        /* be quiet if there is not a single pppoe instance */ +        printf("pppoe: received PADR but not includes ac_cookie\n"); +        goto done; +      } +      sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif); +      if (sc == NULL) { +        /* be quiet if there is not a single pppoe instance */ +        if (!LIST_EMPTY(&pppoe_softc_list)) { +          printf("pppoe: received PADR but could not find request for it\n"); +        } +        goto done; +      } +      if (sc->sc_state != PPPOE_STATE_PADO_SENT) { +        printf("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +        goto done; +      } +      if (hunique) { +        if (sc->sc_hunique) { +          mem_free(sc->sc_hunique); +        } +        sc->sc_hunique = mem_malloc(hunique_len); +        if (sc->sc_hunique == NULL) { +          goto done; +        } +        sc->sc_hunique_len = hunique_len; +        MEMCPY(sc->sc_hunique, hunique, hunique_len); +      } +      pppoe_send_pads(sc); +      sc->sc_state = PPPOE_STATE_SESSION; +      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */ +      break; +  #else +      /* ignore, we are no access concentrator */ +      goto done; +  #endif /* PPPOE_SERVER */ +    case PPPOE_CODE_PADO: +      if (sc == NULL) { +        /* be quiet if there is not a single pppoe instance */ +        if (!LIST_EMPTY(&pppoe_softc_list)) { +          printf("pppoe: received PADO but could not find request for it\n"); +        } +        goto done; +      } +      if (sc->sc_state != PPPOE_STATE_PADI_SENT) { +        printf("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +        goto done; +      } +      if (ac_cookie) { +        if (sc->sc_ac_cookie) { +          mem_free(sc->sc_ac_cookie); +        } +        sc->sc_ac_cookie = mem_malloc(ac_cookie_len); +        if (sc->sc_ac_cookie == NULL) { +          goto done; +        } +        sc->sc_ac_cookie_len = ac_cookie_len; +        MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); +      } +      MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); +      tcpip_untimeout(pppoe_timeout, sc); +      sc->sc_padr_retried = 0; +      sc->sc_state = PPPOE_STATE_PADR_SENT; +      if ((err = pppoe_send_padr(sc)) != 0) { +        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +      } +      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); +      break; +    case PPPOE_CODE_PADS: +      if (sc == NULL) { +        goto done; +      } +      sc->sc_session = session; +      tcpip_untimeout(pppoe_timeout, sc); +      PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); +      sc->sc_state = PPPOE_STATE_SESSION; +      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */ +      break; +    case PPPOE_CODE_PADT: +      if (sc == NULL) { +        goto done; +      } +      pppoe_clear_softc(sc, "received PADT"); +      break; +    default: +      if(sc) { +        printf("%c%c%"U16_F": unknown code (0x%04x) session = 0x%04x\n", +            sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, +            ph->code, session); +      } else { +        printf("pppoe: unknown code (0x%04x) session = 0x%04x\n", ph->code, session); +      } +      break; +  } + +done: +  pbuf_free(pb); +  return; +} + +void +pppoe_disc_input(struct netif *netif, struct pbuf *p) +{ +  /* avoid error messages if there is not a single pppoe instance */ +  if (!LIST_EMPTY(&pppoe_softc_list)) { +    pppoe_dispatch_disc_pkt(netif, p); +  } else { +    pbuf_free(p); +  } +} + +void +pppoe_data_input(struct netif *netif, struct pbuf *pb) +{ +  u16_t session, plen; +  struct pppoe_softc *sc; +  struct pppoehdr *ph; +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS +  u8_t shost[ETHER_ADDR_LEN]; +#endif + +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS +  MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost)); +#endif +  if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) { +    /* bail out */ +    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header failed\n")); +    LINK_STATS_INC(link.lenerr); +    goto drop; +  }  + +  pb = pppSingleBuf (pb); + +  if (pb->len <= PPPOE_HEADERLEN) { +    printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len); +    goto drop; +  } + +  if (pb->len < sizeof(*ph)) { +    printf("pppoe_data_input: could not get PPPoE header\n"); +    goto drop; +  } +  ph = (struct pppoehdr *)pb->payload; + +  if (ph->vertype != PPPOE_VERTYPE) { +    printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype); +    goto drop; +  } +  if (ph->code != 0) { +    goto drop; +  } + +  session = ntohs(ph->session); +  sc = pppoe_find_softc_by_session(session, netif); +  if (sc == NULL) { +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS +    printf("pppoe: input for unknown session 0x%x, sending PADT\n", session); +    pppoe_send_padt(netif, session, shost); +#endif +    goto drop; +  } + +  plen = ntohs(ph->plen); + +  if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) { +    /* bail out */ +    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n")); +    LINK_STATS_INC(link.lenerr); +    goto drop; +  }  + +  PPPDEBUG((LOG_DEBUG, "pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", +        sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, +        pb->len, plen)); + +  if (pb->len < plen) { +    goto drop; +  } + +  pppInProcOverEthernet(sc->sc_pd, pb); + +  return; + +drop: +  pbuf_free(pb); +} + +static err_t +pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) +{ +  struct eth_hdr *ethhdr; +  u16_t etype; +  err_t res; + +  if (!sc->sc_ethif) { +    pbuf_free(pb); +    return ERR_IF; +  } + +  ethhdr = (struct eth_hdr *)pb->payload; +  etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; +  ethhdr->type = htons(etype); +  MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); +  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr)); + +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", +      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, +      sc->sc_state, sc->sc_session, +      sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], +      pb->tot_len)); + +  res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); + +  pbuf_free(pb); + +  return res; +} + +static err_t +pppoe_send_padi(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  int len, l1 = 0, l2 = 0; /* XXX: gcc */ + +  if (sc->sc_state >PPPOE_STATE_PADI_SENT) { +    PPPDEBUG((LOG_ERR, "ERROR: pppoe_send_padi in state %d", sc->sc_state)); +  } + +  /* calculate length of frame (excluding ethernet header + pppoe header) */ +  len = 2 + 2 + 2 + 2 + sizeof sc;  /* service name tag is required, host unique is send too */ +  if (sc->sc_service_name != NULL) { +    l1 = strlen(sc->sc_service_name); +    len += l1; +  } +  if (sc->sc_concentrator_name != NULL) { +    l2 = strlen(sc->sc_concentrator_name); +    len += 2 + 2 + l2; +  } + +  /* allocate a buffer */ +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } + +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  /* fill in pkt */ +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, len); +  PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +  if (sc->sc_service_name != NULL) { +    PPPOE_ADD_16(p, l1); +    MEMCPY(p, sc->sc_service_name, l1); +    p += l1; +  } else { +    PPPOE_ADD_16(p, 0); +  } +  if (sc->sc_concentrator_name != NULL) { +    PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); +    PPPOE_ADD_16(p, l2); +    MEMCPY(p, sc->sc_concentrator_name, l2); +    p += l2; +  } +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sizeof(sc)); +  MEMCPY(p, &sc, sizeof sc); + +  /* send pkt */ +  return pppoe_output(sc, pb); +} + +static void +pppoe_timeout(void *arg) +{ +  int retry_wait, err; +  struct pppoe_softc *sc = (struct pppoe_softc*)arg; + +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + +  switch (sc->sc_state) { +    case PPPOE_STATE_PADI_SENT: +      /* +       * We have two basic ways of retrying: +       *  - Quick retry mode: try a few times in short sequence +       *  - Slow retry mode: we already had a connection successfully +       *    established and will try infinitely (without user +       *    intervention) +       * We only enter slow retry mode if IFF_LINK1 (aka autodial) +       * is not set. +       */ + +      /* initialize for quick retry mode */ +      retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried); + +      sc->sc_padi_retried++; +      if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) { +#if 0 +        if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) { +          /* slow retry mode */ +          retry_wait = PPPOE_SLOW_RETRY; +        } else +#endif +        { +          pppoe_abort_connect(sc); +          return; +        } +      } +      if ((err = pppoe_send_padi(sc)) != 0) { +        sc->sc_padi_retried--; +        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +      } +      tcpip_timeout(retry_wait, pppoe_timeout, sc); +      break; + +    case PPPOE_STATE_PADR_SENT: +      sc->sc_padr_retried++; +      if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) { +        MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +        sc->sc_state = PPPOE_STATE_PADI_SENT; +        sc->sc_padr_retried = 0; +        if ((err = pppoe_send_padi(sc)) != 0) { +          PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +        } +        tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); +        return; +      } +      if ((err = pppoe_send_padr(sc)) != 0) { +        sc->sc_padr_retried--; +        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +      } +      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); +      break; +    case PPPOE_STATE_CLOSING: +      pppoe_do_disconnect(sc); +      break; +    default: +      return;  /* all done, work in peace */ +  } +} + +/* Start a connection (i.e. initiate discovery phase) */ +int +pppoe_connect(struct pppoe_softc *sc) +{ +  int err; + +  if (sc->sc_state != PPPOE_STATE_INITIAL) { +    return EBUSY; +  } + +#ifdef PPPOE_SERVER +  /* wait PADI if IFF_PASSIVE */ +  if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { +    return 0; +  } +#endif +  /* save state, in case we fail to send PADI */ +  sc->sc_state = PPPOE_STATE_PADI_SENT; +  sc->sc_padr_retried = 0; +  err = pppoe_send_padi(sc); +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +  tcpip_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); +  return err; +} + +/* disconnect */ +void +pppoe_disconnect(struct pppoe_softc *sc) +{ +  if (sc->sc_state < PPPOE_STATE_SESSION) { +    return; +  } +  /* +   * Do not call pppoe_disconnect here, the upper layer state +   * machine gets confused by this. We must return from this +   * function and defer disconnecting to the timeout handler. +   */ +  sc->sc_state = PPPOE_STATE_CLOSING; +  tcpip_timeout(20, pppoe_timeout, sc); +} + +static int +pppoe_do_disconnect(struct pppoe_softc *sc) +{ +  int err; + +  if (sc->sc_state < PPPOE_STATE_SESSION) { +    err = EBUSY; +  } else { +    PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); +    err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); +  } + +  /* cleanup softc */ +  sc->sc_state = PPPOE_STATE_INITIAL; +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +  if (sc->sc_ac_cookie) { +    mem_free(sc->sc_ac_cookie); +    sc->sc_ac_cookie = NULL; +  } +  sc->sc_ac_cookie_len = 0; +#ifdef PPPOE_SERVER +  if (sc->sc_hunique) { +    mem_free(sc->sc_hunique); +    sc->sc_hunique = NULL; +  } +  sc->sc_hunique_len = 0; +#endif +  sc->sc_session = 0; + +  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */ + +  return err; +} + +/* Connection attempt aborted */ +static void +pppoe_abort_connect(struct pppoe_softc *sc) +{ +  printf("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +  sc->sc_state = PPPOE_STATE_CLOSING; + +  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */ + +  /* clear connection state */ +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +  sc->sc_state = PPPOE_STATE_INITIAL; +} + +/* Send a PADR packet */ +static err_t +pppoe_send_padr(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  size_t len, l1 = 0; /* XXX: gcc */ + +  if (sc->sc_state != PPPOE_STATE_PADR_SENT) { +    return ERR_CONN; +  } + +  len = 2 + 2 + 2 + 2 + sizeof(sc);    /* service name, host unique */ +  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */ +    l1 = strlen(sc->sc_service_name); +    len += l1; +  } +  if (sc->sc_ac_cookie_len > 0) { +    len += 2 + 2 + sc->sc_ac_cookie_len;  /* AC cookie */ +  } +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); +  PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +  if (sc->sc_service_name != NULL) { +    PPPOE_ADD_16(p, l1); +    MEMCPY(p, sc->sc_service_name, l1); +    p += l1; +  } else { +    PPPOE_ADD_16(p, 0); +  } +  if (sc->sc_ac_cookie_len > 0) { +    PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); +    PPPOE_ADD_16(p, sc->sc_ac_cookie_len); +    MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len); +    p += sc->sc_ac_cookie_len; +  } +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sizeof(sc)); +  MEMCPY(p, &sc, sizeof sc); + +  return pppoe_output(sc, pb); +} + +/* send a PADT packet */ +static err_t +pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) +{ +  struct pbuf *pb; +  struct eth_hdr *ethhdr; +  err_t res; +  u8_t *p; + +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } + +  ethhdr = (struct eth_hdr *)pb->payload; +  ethhdr->type = htons(ETHTYPE_PPPOEDISC); +  MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); +  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr)); + +  p = (u8_t*)(ethhdr + 1); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); + +  res = outgoing_if->linkoutput(outgoing_if, pb); + +  pbuf_free(pb); + +  return res; +} + +#ifdef PPPOE_SERVER +static err_t +pppoe_send_pado(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  size_t len; + +  if (sc->sc_state != PPPOE_STATE_PADO_SENT) { +    return ERR_CONN; +  } + +  /* calc length */ +  len = 0; +  /* include ac_cookie */ +  len += 2 + 2 + sizeof(sc); +  /* include hunique */ +  len += 2 + 2 + sc->sc_hunique_len; +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); +  PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); +  PPPOE_ADD_16(p, sizeof(sc)); +  MEMCPY(p, &sc, sizeof(sc)); +  p += sizeof(sc); +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sc->sc_hunique_len); +  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); +  return pppoe_output(sc, pb); +} + +static err_t +pppoe_send_pads(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  size_t len, l1 = 0;  /* XXX: gcc */ + +  if (sc->sc_state != PPPOE_STATE_PADO_SENT) { +    return ERR_CONN; +  } + +  sc->sc_session = mono_time.tv_sec % 0xff + 1; +  /* calc length */ +  len = 0; +  /* include hunique */ +  len += 2 + 2 + 2 + 2 + sc->sc_hunique_len;  /* service name, host unique*/ +  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */ +    l1 = strlen(sc->sc_service_name); +    len += l1; +  } +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); +  PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +  if (sc->sc_service_name != NULL) { +    PPPOE_ADD_16(p, l1); +    MEMCPY(p, sc->sc_service_name, l1); +    p += l1; +  } else { +    PPPOE_ADD_16(p, 0); +  } +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sc->sc_hunique_len); +  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); +  return pppoe_output(sc, pb); +} +#endif + +err_t +pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) +{ +  u8_t *p; +  size_t len; + +  /* are we ready to process data yet? */ +  if (sc->sc_state < PPPOE_STATE_SESSION) { +    /*sppp_flush(&sc->sc_sppp.pp_if);*/ +    pbuf_free(pb); +    return ERR_CONN; +  } + +  len = pb->tot_len; + +  /* make room for Ethernet header - should not fail */ +  if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) { +    /* bail out */ +    PPPDEBUG((LOG_ERR, "pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); +    LINK_STATS_INC(link.lenerr); +    pbuf_free(pb); +    return ERR_BUF; +  }  + +  p = (u8_t*)pb->payload + sizeof(struct eth_hdr); +  PPPOE_ADD_HEADER(p, 0, sc->sc_session, len); + +  return pppoe_output(sc, pb); +} + +#if 0 /*def PFIL_HOOKS*/ +static int +pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir) +{ +  struct pppoe_softc *sc; +  int s; + +  if (mp != (struct pbuf **)PFIL_IFNET_DETACH) { +    return 0; +  } + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc->sc_ethif != ifp) { +      continue; +    } +    if (sc->sc_sppp.pp_if.if_flags & IFF_UP) { +      sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING); +      printf("%c%c%"U16_F": ethernet interface detached, going down\n", +          sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +    } +    sc->sc_ethif = NULL; +    pppoe_clear_softc(sc, "ethernet interface detached"); +  } + +  return 0; +} +#endif + +static void +pppoe_clear_softc(struct pppoe_softc *sc, const char *message) +{ +  LWIP_UNUSED_ARG(message); + +  /* stop timer */ +  tcpip_untimeout(pppoe_timeout, sc); +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); + +  /* fix our state */ +  sc->sc_state = PPPOE_STATE_INITIAL; + +  /* notify upper layers */ +  sc->sc_linkStatusCB(sc->sc_pd, 0); + +  /* clean up softc */ +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +  if (sc->sc_ac_cookie) { +    mem_free(sc->sc_ac_cookie); +    sc->sc_ac_cookie = NULL; +  } +  sc->sc_ac_cookie_len = 0; +  sc->sc_session = 0; +} + +#endif /* PPPOE_SUPPORT */ + diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h new file mode 100644 index 000000000..6253863c9 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h @@ -0,0 +1,86 @@ +/***************************************************************************** +* pppdebug.h - System debugging utilities. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* portions Copyright (c) 2001 by Cognizant Pty Ltd. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY (please don't use tabs!) +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-07-29 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +* +***************************************************************************** +*/ +#ifndef PPPDEBUG_H +#define PPPDEBUG_H + +/************************ +*** PUBLIC DATA TYPES *** +************************/ +/* Trace levels. */ +typedef enum { +LOG_CRITICAL = 0, +LOG_ERR      = 1, +LOG_NOTICE   = 2, +LOG_WARNING  = 3, +LOG_INFO     = 5, +LOG_DETAIL   = 6, +LOG_DEBUG    = 7 +} LogCodes; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ +/* + * ppp_trace - a form of printf to send tracing information to stderr + */ +void ppp_trace(int level, const char *format,...); + +#define TRACELCP PPP_DEBUG + +#if PPP_DEBUG + +#define AUTHDEBUG(a) ppp_trace a +#define IPCPDEBUG(a) ppp_trace a +#define UPAPDEBUG(a) ppp_trace a +#define LCPDEBUG(a)  ppp_trace a +#define FSMDEBUG(a)  ppp_trace a +#define CHAPDEBUG(a) ppp_trace a +#define PPPDEBUG(a)  ppp_trace a + +#else /* PPP_DEBUG */ + +#define AUTHDEBUG(a) +#define IPCPDEBUG(a) +#define UPAPDEBUG(a) +#define LCPDEBUG(a) +#define FSMDEBUG(a) +#define CHAPDEBUG(a) +#define PPPDEBUG(a) + +#endif /* PPP_DEBUG */ + +#endif /* PPPDEBUG_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/randm.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/randm.c new file mode 100644 index 000000000..0c622a0b0 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/randm.c @@ -0,0 +1,248 @@ +/***************************************************************************** +* randm.c - Random number generator program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Extracted from avos. +*****************************************************************************/ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "md5.h" +#include "randm.h" + +#include "ppp.h" +#include "pppdebug.h" + + +#if MD5_SUPPORT /* this module depends on MD5 */ +#define RANDPOOLSZ 16   /* Bytes stored in the pool of randomness. */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static char randPool[RANDPOOLSZ];   /* Pool of randomness. */ +static long randCount = 0;      /* Pseudo-random incrementer */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * Initialize the random number generator. + * + * Since this is to be called on power up, we don't have much + *  system randomess to work with.  Here all we use is the + *  real-time clock.  We'll accumulate more randomness as soon + *  as things start happening. + */ +void +avRandomInit() +{ +  avChurnRand(NULL, 0); +} + +/* + * Churn the randomness pool on a random event.  Call this early and often + *  on random and semi-random system events to build randomness in time for + *  usage.  For randomly timed events, pass a null pointer and a zero length + *  and this will use the system timer and other sources to add randomness. + *  If new random data is available, pass a pointer to that and it will be + *  included. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + */ +void +avChurnRand(char *randData, u32_t randLen) +{ +  MD5_CTX md5; + +  /* ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */ +  MD5Init(&md5); +  MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); +  if (randData) { +    MD5Update(&md5, (u_char *)randData, randLen); +  } else { +    struct { +      /* INCLUDE fields for any system sources of randomness */ +      char foobar; +    } sysData; + +    /* Load sysData fields here. */ +    MD5Update(&md5, (u_char *)&sysData, sizeof(sysData)); +  } +  MD5Final((u_char *)randPool, &md5); +/*  ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */ +} + +/* + * Use the random pool to generate random data.  This degrades to pseudo + *  random when used faster than randomness is supplied using churnRand(). + * Note: It's important that there be sufficient randomness in randPool + *  before this is called for otherwise the range of the result may be + *  narrow enough to make a search feasible. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + * + * XXX Why does he not just call churnRand() for each block?  Probably + *  so that you don't ever publish the seed which could possibly help + *  predict future values. + * XXX Why don't we preserve md5 between blocks and just update it with + *  randCount each time?  Probably there is a weakness but I wish that + *  it was documented. + */ +void +avGenRand(char *buf, u32_t bufLen) +{ +  MD5_CTX md5; +  u_char tmp[16]; +  u32_t n; + +  while (bufLen > 0) { +    n = LWIP_MIN(bufLen, RANDPOOLSZ); +    MD5Init(&md5); +    MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); +    MD5Update(&md5, (u_char *)&randCount, sizeof(randCount)); +    MD5Final(tmp, &md5); +    randCount++; +    MEMCPY(buf, tmp, n); +    buf += n; +    bufLen -= n; +  } +} + +/* + * Return a new random number. + */ +u32_t +avRandom() +{ +  u32_t newRand; + +  avGenRand((char *)&newRand, sizeof(newRand)); + +  return newRand; +} + +#else /* MD5_SUPPORT */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static int  avRandomized = 0;       /* Set when truely randomized. */ +static u32_t avRandomSeed = 0;      /* Seed used for random number generation. */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * Initialize the random number generator. + * + * Here we attempt to compute a random number seed but even if + * it isn't random, we'll randomize it later. + * + * The current method uses the fields from the real time clock, + * the idle process counter, the millisecond counter, and the + * hardware timer tick counter.  When this is invoked + * in startup(), then the idle counter and timer values may + * repeat after each boot and the real time clock may not be + * operational.  Thus we call it again on the first random + * event. + */ +void +avRandomInit() +{ +#if 0 +  /* Get a pointer into the last 4 bytes of clockBuf. */ +  u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]); + +  /* +   * Initialize our seed using the real-time clock, the idle +   * counter, the millisecond timer, and the hardware timer +   * tick counter.  The real-time clock and the hardware +   * tick counter are the best sources of randomness but +   * since the tick counter is only 16 bit (and truncated +   * at that), the idle counter and millisecond timer +   * (which may be small values) are added to help +   * randomize the lower 16 bits of the seed. +   */ +  readClk(); +  avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr +           + ppp_mtime() + ((u32_t)TM1 << 16) + TM1; +#else +  avRandomSeed += sys_jiffies(); /* XXX */ +#endif + +  /* Initialize the Borland random number generator. */ +  srand((unsigned)avRandomSeed); +} + +/* + * Randomize our random seed value.  Here we use the fact that + * this function is called at *truely random* times by the polling + * and network functions.  Here we only get 16 bits of new random + * value but we use the previous value to randomize the other 16 + * bits. + */ +void +avRandomize(void) +{ +  static u32_t last_jiffies; + +  if (!avRandomized) { +    avRandomized = !0; +    avRandomInit(); +    /* The initialization function also updates the seed. */ +  } else { +    /* avRandomSeed += (avRandomSeed << 16) + TM1; */ +    avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */ +  } +  last_jiffies = sys_jiffies(); +} + +/* + * Return a new random number. + * Here we use the Borland rand() function to supply a pseudo random + * number which we make truely random by combining it with our own + * seed which is randomized by truely random events.  + * Thus the numbers will be truely random unless there have been no + * operator or network events in which case it will be pseudo random + * seeded by the real time clock. + */ +u32_t +avRandom() +{ +  return ((((u32_t)rand() << 16) + rand()) + avRandomSeed); +} + +#endif /* MD5_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/randm.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/randm.h new file mode 100644 index 000000000..a0984b020 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/randm.h @@ -0,0 +1,81 @@ +/***************************************************************************** +* randm.h - Random number generator header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-05-29 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Extracted from avos. +*****************************************************************************/ + +#ifndef RANDM_H +#define RANDM_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ +/* + * Initialize the random number generator. + */ +void avRandomInit(void); + +/* + * Churn the randomness pool on a random event.  Call this early and often + * on random and semi-random system events to build randomness in time for + * usage.  For randomly timed events, pass a null pointer and a zero length + * and this will use the system timer and other sources to add randomness. + * If new random data is available, pass a pointer to that and it will be + * included. + */ +void avChurnRand(char *randData, u32_t randLen); + +/* + * Randomize our random seed value.  To be called for truely random events + * such as user operations and network traffic. + */ +#if MD5_SUPPORT +#define avRandomize() avChurnRand(NULL, 0) +#else  /* MD5_SUPPORT */ +void avRandomize(void); +#endif /* MD5_SUPPORT */ + +/* + * Use the random pool to generate random data.  This degrades to pseudo + * random when used faster than randomness is supplied using churnRand(). + * Thus it's important to make sure that the results of this are not + * published directly because one could predict the next result to at + * least some degree.  Also, it's important to get a good seed before + * the first use. + */ +void avGenRand(char *buf, u32_t bufLen); + +/* + * Return a new random number. + */ +u32_t avRandom(void); + + +#endif /* RANDM_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vj.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vj.c new file mode 100644 index 000000000..814ea72c5 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vj.c @@ -0,0 +1,660 @@ +/* + * Routines to compress and uncompess tcp packets (for transmission + * over low speed serial lines. + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + *   Initial distribution. + * + * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, + * so that the entire packet being decompressed doesn't have + * to be in contiguous memory (just the compressed header). + * + * Modified March 1998 by Guy Lancaster, glanca@gesn.com, + * for a 16 bit processor. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "vj.h" + +#include <string.h> + +#if VJ_SUPPORT + +#if LINK_STATS +#define INCR(counter) ++comp->stats.counter +#else +#define INCR(counter) +#endif + +#if defined(NO_CHAR_BITFIELDS) +#define getip_hl(base)  ((base).ip_hl_v&0xf) +#define getth_off(base) (((base).th_x2_off&0xf0)>>4) +#else +#define getip_hl(base)  ((base).ip_hl) +#define getth_off(base) ((base).th_off) +#endif + +void +vj_compress_init(struct vjcompress *comp) +{ +  register u_int i; +  register struct cstate *tstate = comp->tstate; +   +#if MAX_SLOTS == 0 +  memset((char *)comp, 0, sizeof(*comp)); +#endif +  comp->maxSlotIndex = MAX_SLOTS - 1; +  comp->compressSlot = 0;    /* Disable slot ID compression by default. */ +  for (i = MAX_SLOTS - 1; i > 0; --i) { +    tstate[i].cs_id = i; +    tstate[i].cs_next = &tstate[i - 1]; +  } +  tstate[0].cs_next = &tstate[MAX_SLOTS - 1]; +  tstate[0].cs_id = 0; +  comp->last_cs = &tstate[0]; +  comp->last_recv = 255; +  comp->last_xmit = 255; +  comp->flags = VJF_TOSS; +} + + +/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ + * checks for zero (since zero has to be encoded in the long, 3 byte + * form). + */ +#define ENCODE(n) { \ +  if ((u_short)(n) >= 256) { \ +    *cp++ = 0; \ +    cp[1] = (n); \ +    cp[0] = (n) >> 8; \ +    cp += 2; \ +  } else { \ +    *cp++ = (n); \ +  } \ +} +#define ENCODEZ(n) { \ +  if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ +    *cp++ = 0; \ +    cp[1] = (n); \ +    cp[0] = (n) >> 8; \ +    cp += 2; \ +  } else { \ +    *cp++ = (n); \ +  } \ +} + +#define DECODEL(f) { \ +  if (*cp == 0) {\ +    u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \ +    (f) = htonl(tmp); \ +    cp += 3; \ +  } else { \ +    u32_t tmp = ntohl(f) + (u32_t)*cp++; \ +    (f) = htonl(tmp); \ +  } \ +} + +#define DECODES(f) { \ +  if (*cp == 0) {\ +    u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \ +    (f) = htons(tmp); \ +    cp += 3; \ +  } else { \ +    u_short tmp = ntohs(f) + (u_short)*cp++; \ +    (f) = htons(tmp); \ +  } \ +} + +#define DECODEU(f) { \ +  if (*cp == 0) {\ +    (f) = htons(((u_short)cp[1] << 8) | cp[2]); \ +    cp += 3; \ +  } else { \ +    (f) = htons((u_short)*cp++); \ +  } \ +} + +/* + * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a + * packet.  This assumes that nb and comp are not null and that the first + * buffer of the chain contains a valid IP header. + * Return the VJ type code indicating whether or not the packet was + * compressed. + */ +u_int +vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) +{ +  register struct ip *ip = (struct ip *)pb->payload; +  register struct cstate *cs = comp->last_cs->cs_next; +  register u_short hlen = getip_hl(*ip); +  register struct tcphdr *oth; +  register struct tcphdr *th; +  register u_short deltaS, deltaA; +  register u_long deltaL; +  register u_int changes = 0; +  u_char new_seq[16]; +  register u_char *cp = new_seq; + +  /*   +   * Check that the packet is IP proto TCP. +   */ +  if (ip->ip_p != IPPROTO_TCP) { +    return (TYPE_IP); +  } + +  /* +   * Bail if this is an IP fragment or if the TCP packet isn't +   * `compressible' (i.e., ACK isn't set or some other control bit is +   * set).   +   */ +  if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40) { +    return (TYPE_IP); +  } +  th = (struct tcphdr *)&((long *)ip)[hlen]; +  if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { +    return (TYPE_IP); +  } +  /* +   * Packet is compressible -- we're going to send either a +   * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need +   * to locate (or create) the connection state.  Special case the +   * most recently used connection since it's most likely to be used +   * again & we don't have to do any reordering if it's used. +   */ +  INCR(vjs_packets); +  if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr  +      || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr  +      || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { +    /* +     * Wasn't the first -- search for it. +     * +     * States are kept in a circularly linked list with +     * last_cs pointing to the end of the list.  The +     * list is kept in lru order by moving a state to the +     * head of the list whenever it is referenced.  Since +     * the list is short and, empirically, the connection +     * we want is almost always near the front, we locate +     * states via linear search.  If we don't find a state +     * for the datagram, the oldest state is (re-)used. +     */ +    register struct cstate *lcs; +    register struct cstate *lastcs = comp->last_cs; +     +    do { +      lcs = cs; cs = cs->cs_next; +      INCR(vjs_searches); +      if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr +          && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr +          && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { +        goto found; +      } +    } while (cs != lastcs); + +    /* +     * Didn't find it -- re-use oldest cstate.  Send an +     * uncompressed packet that tells the other side what +     * connection number we're using for this conversation. +     * Note that since the state list is circular, the oldest +     * state points to the newest and we only need to set +     * last_cs to update the lru linkage. +     */ +    INCR(vjs_misses); +    comp->last_cs = lcs; +    hlen += getth_off(*th); +    hlen <<= 2; +    /* Check that the IP/TCP headers are contained in the first buffer. */ +    if (hlen > pb->len) { +      return (TYPE_IP); +    } +    goto uncompressed; + +    found: +    /* +     * Found it -- move to the front on the connection list. +     */ +    if (cs == lastcs) { +      comp->last_cs = lcs; +    } else { +      lcs->cs_next = cs->cs_next; +      cs->cs_next = lastcs->cs_next; +      lastcs->cs_next = cs; +    } +  } + +  oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen]; +  deltaS = hlen; +  hlen += getth_off(*th); +  hlen <<= 2; +  /* Check that the IP/TCP headers are contained in the first buffer. */ +  if (hlen > pb->len) { +    PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", hlen)); +    return (TYPE_IP); +  } + +  /* +   * Make sure that only what we expect to change changed. The first +   * line of the `if' checks the IP protocol version, header length & +   * type of service.  The 2nd line checks the "Don't fragment" bit. +   * The 3rd line checks the time-to-live and protocol (the protocol +   * check is unnecessary but costless).  The 4th line checks the TCP +   * header length.  The 5th line checks IP options, if any.  The 6th +   * line checks TCP options, if any.  If any of these things are +   * different between the previous & current datagram, we send the +   * current datagram `uncompressed'. +   */ +  if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0]  +      || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3]  +      || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4]  +      || getth_off(*th) != getth_off(*oth)  +      || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))  +      || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2))) { +    goto uncompressed; +  } + +  /* +   * Figure out which of the changing fields changed.  The +   * receiver expects changes in the order: urgent, window, +   * ack, seq (the order minimizes the number of temporaries +   * needed in this section of code). +   */ +  if (th->th_flags & TCP_URG) { +    deltaS = ntohs(th->th_urp); +    ENCODEZ(deltaS); +    changes |= NEW_U; +  } else if (th->th_urp != oth->th_urp) { +    /* argh! URG not set but urp changed -- a sensible +     * implementation should never do this but RFC793 +     * doesn't prohibit the change so we have to deal +     * with it. */ +    goto uncompressed; +  } + +  if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) { +    ENCODE(deltaS); +    changes |= NEW_W; +  } + +  if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) { +    if (deltaL > 0xffff) { +      goto uncompressed; +    } +    deltaA = (u_short)deltaL; +    ENCODE(deltaA); +    changes |= NEW_A; +  } + +  if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) { +    if (deltaL > 0xffff) { +      goto uncompressed; +    } +    deltaS = (u_short)deltaL; +    ENCODE(deltaS); +    changes |= NEW_S; +  } + +  switch(changes) { +  case 0: +    /* +     * Nothing changed. If this packet contains data and the +     * last one didn't, this is probably a data packet following +     * an ack (normal on an interactive connection) and we send +     * it compressed.  Otherwise it's probably a retransmit, +     * retransmitted ack or window probe.  Send it uncompressed +     * in case the other side missed the compressed version. +     */ +    if (ip->ip_len != cs->cs_ip.ip_len && +      ntohs(cs->cs_ip.ip_len) == hlen) { +      break; +    } + +  /* (fall through) */ + +  case SPECIAL_I: +  case SPECIAL_D: +    /* +     * actual changes match one of our special case encodings -- +     * send packet uncompressed. +     */ +    goto uncompressed; + +  case NEW_S|NEW_A: +    if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { +      /* special case for echoed terminal traffic */ +      changes = SPECIAL_I; +      cp = new_seq; +    } +    break; + +  case NEW_S: +    if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { +      /* special case for data xfer */ +      changes = SPECIAL_D; +      cp = new_seq; +    } +    break; +  } + +  deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id)); +  if (deltaS != 1) { +    ENCODEZ(deltaS); +    changes |= NEW_I; +  } +  if (th->th_flags & TCP_PSH) { +    changes |= TCP_PUSH_BIT; +  } +  /* +   * Grab the cksum before we overwrite it below.  Then update our +   * state with this packet's header. +   */ +  deltaA = ntohs(th->th_sum); +  BCOPY(ip, &cs->cs_ip, hlen); + +  /* +   * We want to use the original packet as our compressed packet. +   * (cp - new_seq) is the number of bytes we need for compressed +   * sequence numbers.  In addition we need one byte for the change +   * mask, one for the connection id and two for the tcp checksum. +   * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how +   * many bytes of the original packet to toss so subtract the two to +   * get the new packet size. +   */ +  deltaS = (u_short)(cp - new_seq); +  if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { +    comp->last_xmit = cs->cs_id; +    hlen -= deltaS + 4; +    if(pbuf_header(pb, -hlen)){ +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +    } +    cp = (u_char *)pb->payload; +    *cp++ = changes | NEW_C; +    *cp++ = cs->cs_id; +  } else { +    hlen -= deltaS + 3; +    if(pbuf_header(pb, -hlen)) { +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +    } +    cp = (u_char *)pb->payload; +    *cp++ = changes; +  } +  *cp++ = deltaA >> 8; +  *cp++ = deltaA; +  BCOPY(new_seq, cp, deltaS); +  INCR(vjs_compressed); +  return (TYPE_COMPRESSED_TCP); + +  /* +   * Update connection state cs & send uncompressed packet (that is, +   * a regular ip/tcp packet but with the 'conversation id' we hope +   * to use on future compressed packets in the protocol field). +   */ +uncompressed: +  BCOPY(ip, &cs->cs_ip, hlen); +  ip->ip_p = cs->cs_id; +  comp->last_xmit = cs->cs_id; +  return (TYPE_UNCOMPRESSED_TCP); +} + +/* + * Called when we may have missed a packet. + */ +void +vj_uncompress_err(struct vjcompress *comp) +{ +  comp->flags |= VJF_TOSS; +  INCR(vjs_errorin); +} + +/* + * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. + * Return 0 on success, -1 on failure. + */ +int +vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) +{ +  register u_int hlen; +  register struct cstate *cs; +  register struct ip *ip; +   +  ip = (struct ip *)nb->payload; +  hlen = getip_hl(*ip) << 2; +  if (ip->ip_p >= MAX_SLOTS +      || hlen + sizeof(struct tcphdr) > nb->len +      || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2) +          > nb->len +      || hlen > MAX_HDR) { +    PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",  +          ip->ip_p, hlen, nb->len)); +    comp->flags |= VJF_TOSS; +    INCR(vjs_errorin); +    return -1; +  } +  cs = &comp->rstate[comp->last_recv = ip->ip_p]; +  comp->flags &=~ VJF_TOSS; +  ip->ip_p = IPPROTO_TCP; +  BCOPY(ip, &cs->cs_ip, hlen); +  cs->cs_hlen = hlen; +  INCR(vjs_uncompressedin); +  return 0; +} + +/* + * Uncompress a packet of type TYPE_COMPRESSED_TCP. + * The packet is composed of a buffer chain and the first buffer + * must contain an accurate chain length. + * The first buffer must include the entire compressed TCP/IP header.  + * This procedure replaces the compressed header with the uncompressed + * header and returns the length of the VJ header. + */ +int +vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) +{ +  u_char *cp; +  struct tcphdr *th; +  struct cstate *cs; +  u_short *bp; +  struct pbuf *n0 = *nb; +  u32_t tmp; +  u_int vjlen, hlen, changes; + +  INCR(vjs_compressedin); +  cp = (u_char *)n0->payload; +  changes = *cp++; +  if (changes & NEW_C) { +    /*  +     * Make sure the state index is in range, then grab the state. +     * If we have a good state index, clear the 'discard' flag.  +     */ +    if (*cp >= MAX_SLOTS) { +      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp)); +      goto bad; +    } + +    comp->flags &=~ VJF_TOSS; +    comp->last_recv = *cp++; +  } else { +    /*  +     * this packet has an implicit state index.  If we've +     * had a line error since the last time we got an +     * explicit state index, we have to toss the packet.  +     */ +    if (comp->flags & VJF_TOSS) { +      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n")); +      INCR(vjs_tossed); +      return (-1); +    } +  } +  cs = &comp->rstate[comp->last_recv]; +  hlen = getip_hl(cs->cs_ip) << 2; +  th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; +  th->th_sum = htons((*cp << 8) | cp[1]); +  cp += 2; +  if (changes & TCP_PUSH_BIT) { +    th->th_flags |= TCP_PSH; +  } else { +    th->th_flags &=~ TCP_PSH; +  } + +  switch (changes & SPECIALS_MASK) { +  case SPECIAL_I: +    { +      register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; +      /* some compilers can't nest inline assembler.. */ +      tmp = ntohl(th->th_ack) + i; +      th->th_ack = htonl(tmp); +      tmp = ntohl(th->th_seq) + i; +      th->th_seq = htonl(tmp); +    } +    break; + +  case SPECIAL_D: +    /* some compilers can't nest inline assembler.. */ +    tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; +    th->th_seq = htonl(tmp); +    break; + +  default: +    if (changes & NEW_U) { +      th->th_flags |= TCP_URG; +      DECODEU(th->th_urp); +    } else { +      th->th_flags &=~ TCP_URG; +    } +    if (changes & NEW_W) { +      DECODES(th->th_win); +    } +    if (changes & NEW_A) { +      DECODEL(th->th_ack); +    } +    if (changes & NEW_S) { +      DECODEL(th->th_seq); +    } +    break; +  } +  if (changes & NEW_I) { +    DECODES(cs->cs_ip.ip_id); +  } else { +    cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1; +    cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id); +  } + +  /* +   * At this point, cp points to the first byte of data in the +   * packet.  Fill in the IP total length and update the IP +   * header checksum. +   */ +  vjlen = (u_short)(cp - (u_char*)n0->payload); +  if (n0->len < vjlen) { +    /*  +     * We must have dropped some characters (crc should detect +     * this but the old slip framing won't)  +     */ +    PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n",  +          n0->len, vjlen)); +    goto bad; +  } + +#if BYTE_ORDER == LITTLE_ENDIAN +  tmp = n0->tot_len - vjlen + cs->cs_hlen; +  cs->cs_ip.ip_len = htons(tmp); +#else +  cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen); +#endif + +  /* recompute the ip header checksum */ +  bp = (u_short *) &cs->cs_ip; +  cs->cs_ip.ip_sum = 0; +  for (tmp = 0; hlen > 0; hlen -= 2) { +    tmp += *bp++; +  } +  tmp = (tmp & 0xffff) + (tmp >> 16); +  tmp = (tmp & 0xffff) + (tmp >> 16); +  cs->cs_ip.ip_sum = (u_short)(~tmp); +   +  /* Remove the compressed header and prepend the uncompressed header. */ +  if(pbuf_header(n0, -((s16_t)(vjlen)))) { +    /* Can we cope with this failing?  Just assert for now */ +    LWIP_ASSERT("pbuf_header failed\n", 0); +    goto bad; +  } + +  if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) { +    struct pbuf *np, *q; +    u8_t *bufptr; + +    np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); +    if(!np) { +      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n")); +      goto bad; +    } + +    if(pbuf_header(np, -cs->cs_hlen)) { +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +      goto bad; +    } + +    bufptr = n0->payload; +    for(q = np; q != NULL; q = q->next) { +      MEMCPY(q->payload, bufptr, q->len); +      bufptr += q->len; +    } + +    if(n0->next) { +      pbuf_chain(np, n0->next); +      pbuf_dechain(n0); +    } +    pbuf_free(n0); +    n0 = np; +  } + +  if(pbuf_header(n0, cs->cs_hlen)) { +    struct pbuf *np; + +    LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); +    np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); +    if(!np) { +      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n")); +      goto bad; +    } +    pbuf_cat(np, n0); +    n0 = np; +  } +  LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen); +  MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen); + +  *nb = n0; + +  return vjlen; + +bad: +  comp->flags |= VJF_TOSS; +  INCR(vjs_errorin); +  return (-1); +} + +#endif /* VJ_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vj.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vj.h new file mode 100644 index 000000000..b9617da4d --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vj.h @@ -0,0 +1,155 @@ +/* + * Definitions for tcp compression routines. + * + * $Id: vj.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + */ + +#ifndef VJ_H +#define VJ_H + +#include "vjbsdhdr.h" + +#define MAX_SLOTS 16 /* must be > 2 and < 256 */ +#define MAX_HDR   128 + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits).  The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet.  The next two octets are the TCP checksum + * from the original datagram.  The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + *  + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowlegement, sequence number and IP ID.  (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.)  Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0.  (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type.  There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows.  Top + * three bits are actual packet type.  For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* packet types */ +#define TYPE_IP               0x40 +#define TYPE_UNCOMPRESSED_TCP 0x70 +#define TYPE_COMPRESSED_TCP   0x80 +#define TYPE_ERROR            0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + + +/* + * "state" data for each active tcp conversation on the wire.  This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { +  struct cstate *cs_next; /* next most recently used state (xmit only) */ +  u_short cs_hlen;        /* size of hdr (receive only) */ +  u_char cs_id;           /* connection # associated with this state */ +  u_char cs_filler; +  union { +    char csu_hdr[MAX_HDR]; +    struct ip csu_ip;     /* ip/tcp hdr from most recent packet */ +  } vjcs_u; +}; +#define cs_ip vjcs_u.csu_ip +#define cs_hdr vjcs_u.csu_hdr + + +struct vjstat { +  unsigned long vjs_packets;        /* outbound packets */ +  unsigned long vjs_compressed;     /* outbound compressed packets */ +  unsigned long vjs_searches;       /* searches for connection state */ +  unsigned long vjs_misses;         /* times couldn't find conn. state */ +  unsigned long vjs_uncompressedin; /* inbound uncompressed packets */ +  unsigned long vjs_compressedin;   /* inbound compressed packets */ +  unsigned long vjs_errorin;        /* inbound unknown type packets */ +  unsigned long vjs_tossed;         /* inbound packets tossed because of error */ +}; + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct vjcompress { +  struct cstate *last_cs;          /* most recently used tstate */ +  u_char last_recv;                /* last rcvd conn. id */ +  u_char last_xmit;                /* last sent conn. id */ +  u_short flags; +  u_char maxSlotIndex; +  u_char compressSlot;             /* Flag indicating OK to compress slot ID. */ +#if LINK_STATS +  struct vjstat stats; +#endif +  struct cstate tstate[MAX_SLOTS]; /* xmit connection states */ +  struct cstate rstate[MAX_SLOTS]; /* receive connection states */ +}; + +/* flag values */ +#define VJF_TOSS 1U /* tossing rcvd frames because of input err */ + +extern void  vj_compress_init    (struct vjcompress *comp); +extern u_int vj_compress_tcp     (struct vjcompress *comp, struct pbuf *pb); +extern void  vj_uncompress_err   (struct vjcompress *comp); +extern int   vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp); +extern int   vj_uncompress_tcp   (struct pbuf **nb, struct vjcompress *comp); + +#endif /* VJ_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h new file mode 100644 index 000000000..f46267614 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h @@ -0,0 +1,75 @@ +#ifndef VJBSDHDR_H +#define VJBSDHDR_H + +#include "lwip/tcp.h" + +/* + * Structure of an internet header, naked of options. + * + * We declare ip_len and ip_off to be short, rather than u_short + * pragmatically since otherwise unsigned comparisons can result + * against negative integers quite easily, and fail in subtle ways. + */ +PACK_STRUCT_BEGIN +struct ip +{ +#if defined(NO_CHAR_BITFIELDS) +  u_char   ip_hl_v;  /* bug in GCC for mips means the bitfield stuff will sometimes break - so we use a char for both and get round it with macro's instead... */ +#else +#if BYTE_ORDER == LITTLE_ENDIAN +  unsigned ip_hl:4,              /* header length */ +           ip_v :4;              /* version */ +#elif BYTE_ORDER == BIG_ENDIAN  +  unsigned ip_v :4,              /* version */ +           ip_hl:4;              /* header length */ +#else +  COMPLAIN - NO BYTE ORDER SELECTED! +#endif +#endif +  u_char  ip_tos;                /* type of service */ +  u_short ip_len;                /* total length */ +  u_short ip_id;                 /* identification */ +  u_short ip_off;                /* fragment offset field */ +#define  IP_DF 0x4000            /* dont fragment flag */ +#define  IP_MF 0x2000            /* more fragments flag */ +#define  IP_OFFMASK 0x1fff       /* mask for fragmenting bits */ +  u_char  ip_ttl;                /* time to live */ +  u_char  ip_p;                  /* protocol */ +  u_short ip_sum;                /* checksum */ +  struct  in_addr ip_src,ip_dst; /* source and dest address */ +}; +PACK_STRUCT_END + +typedef u32_t tcp_seq; + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +PACK_STRUCT_BEGIN +struct tcphdr   +{ +  u_short  th_sport;    /* source port */ +  u_short  th_dport;    /* destination port */ +  tcp_seq  th_seq;      /* sequence number */ +  tcp_seq  th_ack;      /* acknowledgement number */ +#if defined(NO_CHAR_BITFIELDS) +  u_char   th_x2_off; +#else +#if BYTE_ORDER == LITTLE_ENDIAN +  unsigned th_x2 :4,    /* (unused) */ +           th_off:4;    /* data offset */ +#endif +#if BYTE_ORDER == BIG_ENDIAN  +  unsigned th_off:4,    /* data offset */ +           th_x2 :4;    /* (unused) */ +#endif +#endif +  u_char   th_flags; +  u_short  th_win;      /* window */ +  u_short  th_sum;      /* checksum */ +  u_short  th_urp;      /* urgent pointer */ +}; +PACK_STRUCT_END + +#endif /* VJBSDHDR_H */ diff --git a/firmware/microblaze/lwip/lwip-1.3.1/src/netif/slipif.c b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/slipif.c new file mode 100644 index 000000000..6cb2db442 --- /dev/null +++ b/firmware/microblaze/lwip/lwip-1.3.1/src/netif/slipif.c @@ -0,0 +1,279 @@ +/** + * @file + * SLIP Interface + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved.  + * + * Redistribution and use in source and binary forms, with or without  + * modification, are permitted provided that the following conditions  + * are met:  + * 1. Redistributions of source code must retain the above copyright  + *    notice, this list of conditions and the following disclaimer.  + * 2. Redistributions in binary form must reproduce the above copyright  + *    notice, this list of conditions and the following disclaimer in the  + *    documentation and/or other materials provided with the distribution.  + * 3. Neither the name of the Institute nor the names of its contributors  + *    may be used to endorse or promote products derived from this software  + *    without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND  + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  + * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE  + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  + * SUCH DAMAGE.  + * + * This file is built upon the file: src/arch/rtxc/netif/sioslip.c + * + * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>  + */ + +/*  + * This is an arch independent SLIP netif. The specific serial hooks must be + * provided by another file. They are sio_open, sio_recv and sio_send + */ + +#include "netif/slipif.h" +#include "lwip/opt.h" + +#if LWIP_HAVE_SLIPIF + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/sio.h" + +#define SLIP_END     0300 /* 0xC0 */ +#define SLIP_ESC     0333 /* 0xDB */ +#define SLIP_ESC_END 0334 /* 0xDC */ +#define SLIP_ESC_ESC 0335 /* 0xDD */ + +#define MAX_SIZE     1500 + +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chaing packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +err_t +slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +{ +  struct pbuf *q; +  u16_t i; +  u8_t c; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); +  LWIP_ASSERT("p != NULL", (p != NULL)); + +  LWIP_UNUSED_ARG(ipaddr); + +  /* Send pbuf out on the serial I/O device. */ +  sio_send(SLIP_END, netif->state); + +  for (q = p; q != NULL; q = q->next) { +    for (i = 0; i < q->len; i++) { +      c = ((u8_t *)q->payload)[i]; +      switch (c) { +      case SLIP_END: +        sio_send(SLIP_ESC, netif->state); +        sio_send(SLIP_ESC_END, netif->state); +        break; +      case SLIP_ESC: +        sio_send(SLIP_ESC, netif->state); +        sio_send(SLIP_ESC_ESC, netif->state); +        break; +      default: +        sio_send(c, netif->state); +        break; +      } +    } +  } +  sio_send(SLIP_END, netif->state); +  return ERR_OK; +} + +/** + * Handle the incoming SLIP stream character by character + * + * Poll the serial layer by calling sio_recv() + * + * @param netif the lwip network interface structure for this slipif + * @return The IP packet when SLIP_END is received  + */ +static struct pbuf * +slipif_input(struct netif *netif) +{ +  u8_t c; +  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ +  struct pbuf *p, *q; +  u16_t recved; +  u16_t i; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + +  q = p = NULL; +  recved = i = 0; +  c = 0; + +  while (1) { +    c = sio_recv(netif->state); +    switch (c) { +    case SLIP_END: +      if (recved > 0) { +        /* Received whole packet. */ +        /* Trim the pbuf to the size of the received packet. */ +        pbuf_realloc(q, recved); +         +        LINK_STATS_INC(link.recv); +         +        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n")); +        return q; +      } +      break; + +    case SLIP_ESC: +      c = sio_recv(netif->state); +      switch (c) { +      case SLIP_ESC_END: +        c = SLIP_END; +        break; +      case SLIP_ESC_ESC: +        c = SLIP_ESC; +        break; +      } +      /* FALLTHROUGH */ + +    default: +      /* byte received, packet not yet completely received */ +      if (p == NULL) { +        /* allocate a new pbuf */ +        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); +        p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL); + +        if (p == NULL) { +          LINK_STATS_INC(link.drop); +          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); +          /* don't process any further since we got no pbuf to receive to */ +          break; +        } + +        if (q != NULL) { +          /* 'chain' the pbuf to the existing chain */ +          pbuf_cat(q, p); +        } else { +          /* p is the first pbuf in the chain */ +          q = p; +        } +      } + +      /* this automatically drops bytes if > MAX_SIZE */ +      if ((p != NULL) && (recved <= MAX_SIZE)) { +        ((u8_t *)p->payload)[i] = c; +        recved++; +        i++; +        if (i >= p->len) { +          /* on to the next pbuf */ +          i = 0; +          if (p->next != NULL && p->next->len > 0) { +            /* p is a chain, on to the next in the chain */ +            p = p->next; +          } else { +            /* p is a single pbuf, set it to NULL so next time a new +             * pbuf is allocated */ +            p = NULL; +          } +        } +      } +      break; +    } +  } +  return NULL; +} + +#if !NO_SYS +/** + * The SLIP input thread. + * + * Feed the IP layer with incoming packets + * + * @param nf the lwip network interface structure for this slipif + */ +static void +slipif_loop(void *nf) +{ +  struct pbuf *p; +  struct netif *netif = (struct netif *)nf; + +  while (1) { +    p = slipif_input(netif); +    if (p != NULL) { +      if (netif->input(p, netif) != ERR_OK) { +        pbuf_free(p); +        p = NULL; +      } +    } +  } +} +#endif /* !NO_SYS */ + +/** + * SLIP netif initialization + * + * Call the arch specific sio_open and remember + * the opened device in the state field of the netif. + * + * @param netif the lwip network interface structure for this slipif + * @return ERR_OK if serial line could be opened, + *         ERR_IF is serial line couldn't be opened + * + * @note netif->num must contain the number of the serial port to open + *       (0 by default) + */ +err_t +slipif_init(struct netif *netif) +{ + +  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); + +  netif->name[0] = 's'; +  netif->name[1] = 'l'; +  netif->output = slipif_output; +  netif->mtu = MAX_SIZE; +  netif->flags = NETIF_FLAG_POINTTOPOINT; + +  /* Try to open the serial port (netif->num contains the port number). */ +  netif->state = sio_open(netif->num); +  if (!netif->state) { +    /* Opening the serial port failed. */ +    return ERR_IF; +  } + +  /* initialize the snmp variables and counters inside the struct netif +   * ifSpeed: no assumption can be made without knowing more about the +   * serial line! +   */ +  NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0); + +  /* Create a thread to poll the serial line. */ +  sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); +  return ERR_OK; +} +#endif /* LWIP_HAVE_SLIPIF */ diff --git a/firmware/microblaze/lwip/lwipopts.h b/firmware/microblaze/lwip/lwipopts.h new file mode 100644 index 000000000..3839eea83 --- /dev/null +++ b/firmware/microblaze/lwip/lwipopts.h @@ -0,0 +1,196 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Our lwip options + */ + +#define NO_SYS				1 + + +// ---------- Memory options ---------- +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + *    4 byte alignment -> #define MEM_ALIGNMENT 4 + *    2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#define MEM_ALIGNMENT      		4 + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#define MEM_SIZE        		256 + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the lenght needed is returned. + */ +#define MEM_USE_POOLS                   0 + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your  + * inlude path somewhere.  + */ +#define MEMP_USE_CUSTOM_POOLS           0 + +// ---------- Internal Memory Pool Sizes ---------- +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#define MEMP_NUM_PBUF                   8 + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#define MEMP_NUM_UDP_PCB                4 + +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#define PBUF_LINK_HLEN                  16 +#define	ETH_PAD_SIZE			2 + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.  + */ +#define PBUF_POOL_SIZE                  8 + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +//#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(128+28+PBUF_LINK_HLEN) + + +// ---------- ARP options ---------- +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#define ARP_TABLE_SIZE                  5 + +/** + * ARP_QUEUEING==1: Outgoing packets are queued during hardware address + * resolution. + */ +#define ARP_QUEUEING                    0 + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#define MEMP_NUM_ARP_QUEUE              5 + +// ---------- IP options ---------- +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#define IP_OPTIONS_ALLOWED              0 + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#define IP_REASSEMBLY                   0 + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#define IP_FRAG                         0 + +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#define LWIP_DHCP                       0 + +/** + * LWIP_IGMP==1: Turn on IGMP module.  + */ +#define LWIP_IGMP                       0 + +/** + * LWIP_UDP==1: Turn on UDP. + */ +#define LWIP_UDP                        1 + +/** + * LWIP_TCP==1: Turn on TCP. + */ +#define LWIP_TCP                        0 + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN                    0 + +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET                     0 + +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#define LWIP_STATS                      0 + +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#define CHECKSUM_GEN_IP                 0 +  +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#define CHECKSUM_GEN_UDP                0 +  +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#define CHECKSUM_CHECK_IP               0 + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#define CHECKSUM_CHECK_UDP              0 + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#define LWIP_NETIF_LINK_CALLBACK        1 diff --git a/firmware/microblaze/lwip/lwippools.h b/firmware/microblaze/lwip/lwippools.h new file mode 100644 index 000000000..caee23c82 --- /dev/null +++ b/firmware/microblaze/lwip/lwippools.h @@ -0,0 +1,24 @@ +#ifndef INCLUDED_LWIPPOOLS_H +#define INCLUDED_LWIPPOOLS_H + +/* + * from comment at top of mem.c: + * + * To let mem_malloc() use pools (prevents fragmentation and is much faster than + * a heap but might waste some memory), define MEM_USE_POOLS to 1, define + * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list + * of pools like this (more pools can be added between _START and _END): + * + * Define three pools with sizes 256, 512, and 1512 bytes + * LWIP_MALLOC_MEMPOOL_START + * LWIP_MALLOC_MEMPOOL(20, 256) + * LWIP_MALLOC_MEMPOOL(10, 512) + * LWIP_MALLOC_MEMPOOL(5, 1512) + * LWIP_MALLOC_MEMPOOL_END + */ + +LWIP_MALLOC_MEMPOOL_START +LWIP_MALLOC_MEMPOOL(2, 256) +LWIP_MALLOC_MEMPOOL_END + +#endif /* INCLUDED_LWIPPOOLS_H */ diff --git a/firmware/microblaze/lwip_port/arch/cc.h b/firmware/microblaze/lwip_port/arch/cc.h new file mode 100644 index 000000000..d8d53ecf8 --- /dev/null +++ b/firmware/microblaze/lwip_port/arch/cc.h @@ -0,0 +1,65 @@ +#ifndef INCLUDED_ARCH_CC_H +#define INCLUDED_ARCH_CC_H + +#define BYTE_ORDER BIG_ENDIAN + + +#if 1 +#include <stdint.h> + +typedef uint8_t    u8_t; +typedef int8_t     s8_t; +typedef uint16_t   u16_t; +typedef int16_t    s16_t; +typedef uint32_t   u32_t; +typedef int32_t    s32_t; + +#else + +typedef unsigned   char    u8_t; +typedef signed     char    s8_t; +typedef unsigned   short   u16_t; +typedef signed     short   s16_t; +typedef unsigned   long    u32_t; +typedef signed     long    s32_t; +#endif + +typedef u32_t mem_ptr_t; + +#if 1   /* minimal printf */ +#define U16_F "u" +#define S16_F "d" +#define X16_F "x" +#define U32_F "u" +#define S32_F "d" +#define X32_F "x" + +#else + +#define U16_F "hu" +#define S16_F "hd" +#define X16_F "hx" +#define U32_F "lu" +#define S32_F "ld" +#define X32_F "lx" +#endif + +#if 1	// gcc: don't pack +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END +#else	// gcc: do pack +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END +#endif + +//#define LWIP_PLATFORM_ASSERT(msg) ((void)0) +void abort(void); +#define LWIP_PLATFORM_ASSERT(msg) abort() + + +#endif /* INCLUDED_ARCH_CC_H */ + diff --git a/firmware/microblaze/lwip_port/arch/perf.h b/firmware/microblaze/lwip_port/arch/perf.h new file mode 100644 index 000000000..f0906d03f --- /dev/null +++ b/firmware/microblaze/lwip_port/arch/perf.h @@ -0,0 +1,2 @@ +#define PERF_START     ((void) 0) +#define PERF_STOP(msg) ((void) 0) diff --git a/firmware/microblaze/lwip_port/netif/eth_driver.c b/firmware/microblaze/lwip_port/netif/eth_driver.c new file mode 100644 index 000000000..18c6eaf3e --- /dev/null +++ b/firmware/microblaze/lwip_port/netif/eth_driver.c @@ -0,0 +1,303 @@ +/** + * @file + * Ethernet Interface for quadradio + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * Copyright (c) 2010 Ettus Research LLC + * All rights reserved.  + *  + * Redistribution and use in source and binary forms, with or without modification,  + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + *    this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + *    this list of conditions and the following disclaimer in the documentation + *    and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + *    derived from this software without specific prior written permission.  + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING  + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include <lwip/stats.h> +#include <lwip/snmp.h> +#include "netif/etharp.h" +#include "netif/ppp_oe.h" +#include "eth_driver.h" + +#if 0	// don't build + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * Helper struct to hold private data used to operate your ethernet interface. + */ +struct quadradioif { +  int	ethno; +}; + +/* Forward declarations. */ +static void  quadradioif_input(struct netif *netif); + +/** + * In this function, the hardware should be initialized. + * Called from quadradioif_init(). + * + * @param netif the already initialized lwip network interface structure + *        for this quadradioif + */ +static void +low_level_init(struct netif *netif) +{ +  struct quadradioif *quadradioif = netif->state; +   +  /* set MAC hardware address length */ +  netif->hwaddr_len = ETHARP_HWADDR_LEN; + +  /* set MAC hardware address */ +  netif->hwaddr[0] = ; +  ... +  netif->hwaddr[5] = ; + +  /* maximum transfer unit */ +  netif->mtu = 1500; +   +  /* device capabilities */ +  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ +  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; +  +  /* Do whatever else is needed to initialize interface. */   +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this quadradioif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + *         an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + *       strange results. You might consider waiting for space in the DMA queue + *       to become availale since the stack doesn't retry to send a packet + *       dropped because of memory failure (except for the TCP timers). + */ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ +  struct quadradioif *quadradioif = netif->state; +  struct pbuf *q; + +  initiate transfer(); +   +#if ETH_PAD_SIZE +  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +  for(q = p; q != NULL; q = q->next) { +    /* Send the data from the pbuf to the interface, one pbuf at a +       time. The size of the data in each pbuf is kept in the ->len +       variable. */ +    send data from(q->payload, q->len); +  } + +  signal that packet should be sent(); + +#if ETH_PAD_SIZE +  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif +   +  LINK_STATS_INC(link.xmit); + +  return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this quadradioif + * @return a pbuf filled with the received packet (including MAC header) + *         NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif) +{ +  struct quadradioif *quadradioif = netif->state; +  struct pbuf *p, *q; +  u16_t len; + +  /* Obtain the size of the packet and put it into the "len" +     variable. */ +  len = ; + +#if ETH_PAD_SIZE +  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + +  /* We allocate a pbuf chain of pbufs from the pool. */ +  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); +   +  if (p != NULL) { + +#if ETH_PAD_SIZE +    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +    /* We iterate over the pbuf chain until we have read the entire +     * packet into the pbuf. */ +    for(q = p; q != NULL; q = q->next) { +      /* Read enough bytes to fill this pbuf in the chain. The +       * available data in the pbuf is given by the q->len +       * variable. */ +      read data into(q->payload, q->len); +    } +    acknowledge that packet has been read(); + +#if ETH_PAD_SIZE +    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + +    LINK_STATS_INC(link.recv); +  } else { +    drop packet(); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +  } + +  return p;   +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this quadradioif + */ +static void +quadradioif_input(struct netif *netif) +{ +  struct quadradioif *quadradioif; +  struct eth_hdr *ethhdr; +  struct pbuf *p; + +  quadradioif = netif->state; + +  /* move received packet into a new pbuf */ +  p = low_level_input(netif); +  /* no packet could be read, silently ignore this */ +  if (p == NULL) return; +  /* points to packet payload, which starts with an Ethernet header */ +  ethhdr = p->payload; + +  switch (htons(ethhdr->type)) { +  /* IP or ARP packet? */ +  case ETHTYPE_IP: +  case ETHTYPE_ARP: +#if PPPOE_SUPPORT +  /* PPPoE packet? */ +  case ETHTYPE_PPPOEDISC: +  case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ +    /* full packet send to tcpip_thread to process */ +    if (netif->input(p, netif)!=ERR_OK) +     { LWIP_DEBUGF(NETIF_DEBUG, ("quadradioif_input: IP input error\n")); +       pbuf_free(p); +       p = NULL; +     } +    break; + +  default: +    pbuf_free(p); +    p = NULL; +    break; +  } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this quadradioif + * @return ERR_OK if the loopif is initialized + *         ERR_MEM if private data couldn't be allocated + *         any other err_t on error + */ +err_t +quadradioif_init(struct netif *netif) +{ +  struct quadradioif *quadradioif; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +     +  quadradioif = mem_malloc(sizeof(struct quadradioif)); +  if (quadradioif == NULL) { +    LWIP_DEBUGF(NETIF_DEBUG, ("quadradioif_init: out of memory\n")); +    return ERR_MEM; +  } + +#if LWIP_NETIF_HOSTNAME +  /* Initialize interface hostname */ +  netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + +  /* +   * Initialize the snmp variables and counters inside the struct netif. +   * The last argument should be replaced with your link speed, in units +   * of bits per second. +   */ +  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + +  netif->state = quadradioif; +  netif->name[0] = IFNAME0; +  netif->name[1] = IFNAME1; +  /* We directly use etharp_output() here to save a function call. +   * You can instead declare your own function an call etharp_output() +   * from it if you have to do some checks before sending (e.g. if link +   * is available...) */ +  netif->output = etharp_output; +  netif->linkoutput = low_level_output; +   +  quadradioif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); +   +  /* initialize the hardware */ +  low_level_init(netif); + +  return ERR_OK; +} + +#endif /* 0 */ diff --git a/firmware/microblaze/lwip_port/netif/eth_driver.h b/firmware/microblaze/lwip_port/netif/eth_driver.h new file mode 100644 index 000000000..72a212091 --- /dev/null +++ b/firmware/microblaze/lwip_port/netif/eth_driver.h @@ -0,0 +1,23 @@ +/* -*- c -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qpn_port.h" + +void eth_driver_init(QActive *); +void eth_driver_handle_input(int ethno, int bufno, size_t nbytes); +void eth_driver_buffer_sig(int bufno); diff --git a/firmware/microblaze/u2_flash_tool b/firmware/microblaze/u2_flash_tool new file mode 100755 index 000000000..2b66a4ac0 --- /dev/null +++ b/firmware/microblaze/u2_flash_tool @@ -0,0 +1,116 @@ +#!/usr/bin/env python + +import sys +from optparse import OptionParser + +SECTOR_SIZE = 512                 # bytes +MAX_FILE_SIZE =  1 * (2**20)      # maximum number of bytes we'll burn to a slot + +FPGA_OFFSET = 0                   # offset in flash to fpga image +FIRMWARE_OFFSET = 1 * (2**20)     # offset in flash to firmware image + +def read_file_data(filename): +    f = open(filename, "rb") +    file_data = f.read(MAX_FILE_SIZE) +    t = len(file_data) % SECTOR_SIZE +    if t != 0: +        file_data += (SECTOR_SIZE - t)*chr(0)  # pad to an even sector size w/ zeros +    return file_data + + +def write_flash(offset, filename, devname): +    file_data = read_file_data(filename) +    dev = open(devname, "wb") +    dev.seek(offset, 0)                 # seek to absolute byte offset +    dev.write(file_data) +    dev.flush() +    dev.close() +    return True + + +def verify_flash(offset, filename, devname): +    file_data = read_file_data(filename) +    dev = open(devname, "rb") +    dev.seek(offset, 0)                 # seek to absolute byte offset +    dev_data = dev.read(len(file_data)) +    if len(dev_data) != len(file_data): +        sys.stderr.write("short read on device %s\n" % (devname,)) +        return False + +    if file_data == dev_data: +        return True + +    # doesn't match +    nwrong = 0 +    for i in range(len(file_data)): +        if dev_data[i] != file_data[i]: +            sys.stderr.write("mismatch at offset %7d.  Expected 0x%02x, got 0x%02x\n" % ( +                i, ord(file_data[i]), ord(dev_data[i]))) +            nwrong += 1 +            if nwrong > 16: +                sys.stderr.write("> 16 errors, stopping comparison\n") +                break +    return False + +def read_flash(offset, filename, devname): +    dev = open(devname, "rb") +    dev.seek(offset, 0)                 # seek to absolute byte offset +    dev_data = dev.read(MAX_FILE_SIZE) +    dev.close() +    open(filename, "wb").write(dev_data) + +     +def main(): +    parser = OptionParser(usage="%prog: [options] filename") +    parser.add_option("-w", "--write", action="store_const", const="write", dest="mode", +                      help="write FILE to TARGET slot") +    parser.add_option("-v", "--verify",  action="store_const", const="verify", dest="mode", +                      help="verify FILE against TARGET slot") +    parser.add_option("-r", "--read",  action="store_const", const="read", dest="mode", +                      help="read TARGET slot, write to FILE") +    parser.add_option("-t", "--target", type="choice", choices=("fpga", "s/w"), default="s/w", +                      help="select TARGET slot from: fpga, s/w [default=%default]") +    parser.add_option("", "--dev", default=None, +                      help="specify flash device file, e.g., /dev/sdb.  Be careful!") +    parser.set_defaults(target="s/w", mode=None) + +    (options, args) = parser.parse_args() +    if len(args) != 1: +        parser.print_help() +        raise SystemExit + +    filename = args[0] + +    if options.mode is None: +        sys.stderr.write("specify mode with -w, -v or -r\n") +        parser.print_help() +        raise SystemExit + +    if options.dev is None: +        sys.stderr.write("specify the device file with --dev\n") +        parser.print_help() +        raise SystemExit + +    offset = { "fpga" : FPGA_OFFSET, "s/w" : FIRMWARE_OFFSET }[options.target] +     +    if options.mode == "write": +        r = (write_flash(offset, filename, options.dev) +             and verify_flash(offset, filename, options.dev)) +    elif options.mode == "verify": +        r = verify_flash(offset, filename, options.dev) +    elif options.mode == "read": +        r = read_flash(offset, filename, options.dev) +    else: +        raise NotImplemented + +    if not r: +        raise SystemExit, 1 + + +if __name__ == "__main__": +    main() + +     + + +     diff --git a/firmware/microblaze/usrp2/.gitignore b/firmware/microblaze/usrp2/.gitignore new file mode 100644 index 000000000..18f715618 --- /dev/null +++ b/firmware/microblaze/usrp2/.gitignore @@ -0,0 +1,9 @@ +/Makefile +/Makefile.in +/*.a +/*.bin +/*.dump +/*.ihx +/*.elf +/*.rom +/*.map diff --git a/firmware/microblaze/usrp2/Makefile.am b/firmware/microblaze/usrp2/Makefile.am new file mode 100644 index 000000000..7a58e7253 --- /dev/null +++ b/firmware/microblaze/usrp2/Makefile.am @@ -0,0 +1,47 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +AM_CFLAGS = \ +	$(COMMON_CFLAGS) + +AM_LDFLAGS = \ +	$(COMMON_LFLAGS) \ +	-Wl,-defsym -Wl,_TEXT_START_ADDR=0x0050 \ +	-Wl,-defsym -Wl,_STACK_SIZE=3072 +	 +LDADD = libusrp2.a + +LDADD = libusrp2.a + +######################################################################## +# USRP2 specific library and programs +######################################################################## +noinst_LIBRARIES = libusrp2.a + +libusrp2_a_SOURCES = \ +	$(COMMON_SRCS) \ +	sd.c \ +	ethernet.c \ +  udp_fw_update.c + +noinst_PROGRAMS = \ +	usrp2_txrx_uhd.elf + +usrp2_txrx_uhd_elf_SOURCES = \ +	$(top_srcdir)/apps/txrx_uhd.c diff --git a/firmware/microblaze/usrp2/eth_phy.h b/firmware/microblaze/usrp2/eth_phy.h new file mode 100644 index 000000000..6c16f97b7 --- /dev/null +++ b/firmware/microblaze/usrp2/eth_phy.h @@ -0,0 +1,219 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* Much of this was extracted from the Linux e1000_hw.h file */ + +#ifndef INCLUDED_ETH_PHY_H +#define INCLUDED_ETH_PHY_H + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ + +#define PHY_CTRL         0x00 /* Control Register */ +#define PHY_STATUS       0x01 /* Status Regiser */ +#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */ + +/* PHY 1000 MII Register additions in DP83856 */ +/* The part implements 0x00 thru 0x1f; we use these. */ + +#define	PHY_LINK_AN	 0x11 /* Link and Auto Negotiation Status Reg */ +#define PHY_INT_STATUS	 0x14 /* Interupt Status Reg (RO) */ +#define PHY_INT_MASK	 0x15 /* Interrupt Mask Reg  (RW) */ +#define PHY_INT_CLEAR    0x17 /* Interrupt Clear Reg (RW) */ + + +/* Bit definitions for some of the registers above */ + +/* PHY Control Register (PHY_CTRL) */ +#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */ +#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */ +#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN       0x0800  /* Power down */ +#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */ + +/* PHY Status Register (PHY_STATUS) */ +#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */ +#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register (PHY_AUTONEG_ADV) */ +#define NWAY_AR_SELECTOR_FIELD 0x0001   /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS    0x0020   /* 10T   Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS    0x0040   /* 10T   Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS  0x0080   /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS  0x0100   /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS     0x0200   /* 100T4 Capable */ +#define NWAY_AR_PAUSE          0x0400   /* Pause operation desired */ +#define NWAY_AR_ASM_DIR        0x0800   /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT   0x2000   /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE      0x8000   /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) (PHY_LP_ABILITY) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register (PHY_AUTONEG_EXP) */ +#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */ + +/* Next Page TX Register (PHY_NEXT_PAGE_TX) */ +#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define NPTX_TOGGLE         0x0800 /* Toggles between exchanges +                                    * of different NP +                                    */ +#define NPTX_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg +                                    * 0 = cannot comply with msg +                                    */ +#define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */ +#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow +                                    * 0 = sending last NP +                                    */ + +/* Link Partner Next Page Register (PHY_LP_NEXT_PAGE) */ +#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges +                                       * of different NP +                                       */ +#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg +                                       * 0 = cannot comply with msg +                                       */ +#define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */ +#define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */ +#define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow +                                        * 0 = sending last NP +                                        */ + +/* 1000BASE-T Control Register (PHY_1000T_CTRL) */ +#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */ +#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */ +                                        /* 0=DTE device */ +#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */ +                                        /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */ +                                        /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register (PHY_1000T_STATUS) */ +#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local TX is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */ +#define SR_1000T_REMOTE_RX_STATUS_SHIFT          12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT           13 +#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT    5 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_20            20 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_100           100 + +/* Extended Status Register (PHY_EXT_STATUS) */ +#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +#define PHY_TX_POLARITY_MASK   0x0100 /* register 10h bit 8 (polarity bit) */ +#define PHY_TX_NORMAL_POLARITY 0      /* register 10h bit 8 (normal polarity) */ + +#define AUTO_POLARITY_DISABLE  0x0010 /* register 11h bit 4 */ +                                      /* (0=enable, 1=disable) */ + +/* Link and Auto Negotiation Status Reg (PHY_LINK_AN) [READ-ONLY] */ +#define	LANSR_MASTER           0x0001 /* 1=PHY is currently in master mode */ +#define	LANSR_FULL_DUPLEX      0x0002 /* 1=PHY is currently full duplex */ +#define LANSR_LINK_GOOD        0x0004 /* 1=a good link is established */ +#define LANSR_SPEED_MASK       0x0018 +#define	  LANSR_SPEED_10       0x0000 /*   10Mb/s */ +#define	  LANSR_SPEED_100      0x0008 /*  100Mb/s */ +#define	  LANSR_SPEED_1000     0x0010 /* 1000Mb/s */ +#define	  LANSR_SPEED_RSRVD    0x0018 /* reserved */ +#define LANSR_NON_COMP_MODE    0x0020 /* 1=detects only in non-compliant mode */ +#define	LANSR_DEEP_LOOPBACK    0x0040 /* 1=the PHY operates in deep loopback mode */ +#define	LANSR_SHALLOW_LOOPBACK 0x0080 /* 1=the PHY operates in shallow loopback mode */ +#define LANSR_RSRVD_8	       0x0100 /* reserved */ +#define LANSR_FIFO_ERR	       0x0200 /* 1=FIFO error occurred */ +#define	LANSR_MDIX_XOVER       0x0400 /* 1=PHY's MDI is in cross-over mode */ +#define	LANSR_RSRVD_11	       0x0800 /* resevered */ +#define	LANSR_TP_POLARITY_REV  0xf000 /* Twisted pair polarity status A:D([15:12]) 1=reversed */ + +/* Interrupt status, mask and clear regs (PHY_INT_{STATUS,MASK,CLEAR}) */ +#define	PHY_INT_RSRVD_0	       0x0001 /* reserved */ +#define	PHY_INT_RSRVD_1	       0x0002 /* reserved */ +#define	PHY_INT_RSRVD_2	       0x0004 /* reserved */ +#define	PHY_INT_REM_FLT_CNG    0x0008 /* Remote Fault Changed */ +#define	PHY_INT_AN_CMPL	       0x0010 /* Auto-negotiation completion */ +#define	PHY_INT_NXT_PG_RCVD    0x0020 /* Next Page Received */ +#define PHY_INT_JABBER_CNG     0x0040 /* Jabber Changed */ +#define PHY_INT_NO_LINK	       0x0080 /* No link after auto-negotiation */ +#define PHY_INT_NO_HCD	       0x0100 /* AN couldn't determine highest common denominator */ +#define PHY_INT_MAS_SLA_ERR    0x0200 /* Master / Slave Error: couldn't resolve */ +#define PHY_INT_PRL_DET_FLT    0x0400 /* Parallel detection fault */ +#define PHY_INT_POL_CNG	       0x0800 /* Polarity of any channel changed */ +#define	PHY_INT_MDIX_CNG       0x1000 /* MDIX changed.  A pair swap occurred. */ +#define PHY_INT_DPLX_CNG       0x2000 /* Duplex changed */ +#define PHY_INT_LNK_CNG	       0x4000 /* Link changed (asserted when a link is established or broken) */ +#define PHY_INT_SPD_CNG	       0x8000 /* Speed changed */ + +#endif /* INCLUDED_ETH_PHY_H */ diff --git a/firmware/microblaze/usrp2/ethernet.c b/firmware/microblaze/usrp2/ethernet.c new file mode 100644 index 000000000..5d4654bda --- /dev/null +++ b/firmware/microblaze/usrp2/ethernet.c @@ -0,0 +1,290 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ethernet.h" +#include "eth_phy.h" +#include "eth_mac.h" +#include "eth_mac_regs.h" +#include "pic.h" +#include "hal_io.h" +#include "nonstdio.h" + +#define VERBOSE 1 + +static ethernet_t ed_state; +static ethernet_link_changed_callback_t ed_callback = 0; + +void  +ethernet_register_link_changed_callback(ethernet_link_changed_callback_t new_callback) +{ +  ed_callback = new_callback; +} + + +static void +ed_set_mac_speed(int speed) +{ +  printf("Speed set to %d\n",speed); +  /* +  switch(speed){ +  case 10: +    eth_mac->speed = 1; +    break; +  case 100: +    eth_mac->speed = 2; +    break; +  case 1000: +    eth_mac->speed = 4; +    break; +  default: +    break; +  } +  */ +} + +static void +ed_link_up(int speed) +{ +  // putstr("ed_link_up: "); puthex16_nl(speed); + +  ed_set_mac_speed(speed); + +  if (ed_callback)		// fire link changed callback +    (*ed_callback)(speed); +} + +static void +ed_link_down(void) +{ +  // putstr("ed_link_down\n"); + +  if (ed_callback)		// fire link changed callback +    (*ed_callback)(0); +} + + +static void +ed_link_speed_change(int speed) +{ +  ed_link_down(); +  ed_link_up(speed); +} + +static void +print_flow_control(int flow_control) +{ +  static const char *flow_control_msg[4] = { +    "NONE", "WE_TX", "WE_RX", "SYMMETRIC" +  }; +  putstr("ethernet flow control: "); +  puts(flow_control_msg[flow_control & 0x3]); +} + +static void +check_flow_control_resolution(void) +{ +  static const unsigned char table[16] = { +    // index = {local_asm, local_pause, partner_asm, partner_pause} +    FC_NONE,  FC_NONE,  FC_NONE,  FC_NONE, +    FC_NONE,  FC_SYMM,  FC_NONE,  FC_SYMM, +    FC_NONE,  FC_NONE,  FC_NONE,  FC_WE_TX, +    FC_NONE,  FC_SYMM,  FC_WE_RX, FC_SYMM +  }; + +  int us = eth_mac_miim_read(PHY_AUTONEG_ADV); +  int lp = eth_mac_miim_read(PHY_LP_ABILITY); +  int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3); +  ed_state.flow_control = table[index]; + +  if (1) +    print_flow_control(ed_state.flow_control); +} + +/* + * Read the PHY state register to determine link state and speed + */ +static void +ed_check_phy_state(void) +{ +  int lansr = eth_mac_miim_read(PHY_LINK_AN); +  eth_link_state_t new_state = LS_UNKNOWN; +  int new_speed = S_UNKNOWN; + +  if (VERBOSE){ +    putstr("LANSR: "); +    puthex16_nl(lansr); +  } + +  if (lansr & LANSR_LINK_GOOD){		// link's up +    if (VERBOSE) +      puts("  LINK_GOOD"); + +    new_state = LS_UP; +    switch (lansr & LANSR_SPEED_MASK){ +    case LANSR_SPEED_10: +      new_speed = 10; +      break; +       +    case LANSR_SPEED_100: +      new_speed = 100; +      break; +       +    case LANSR_SPEED_1000: +      new_speed = 1000; +      break; + +    default: +      new_speed = S_UNKNOWN; +      break; +    } + +    check_flow_control_resolution(); +  } +  else {				// link's down +    if (VERBOSE) +      puts("  NOT LINK_GOOD"); +     +    new_state = LS_DOWN; +    new_speed = S_UNKNOWN; +  } + +  if (new_state != ed_state.link_state){ +    ed_state.link_state = new_state;		// remember new state +    if (new_state == LS_UP) +      ed_link_up(new_speed); +    else if (new_state == LS_DOWN) +      ed_link_down(); +  } +  else if (new_state == LS_UP && new_speed != ed_state.link_speed){ +    ed_state.link_speed = new_speed;		// remember new speed +    ed_link_speed_change(new_speed); +  } +} + +/* + * This is fired when the ethernet PHY state changes + */ +static void +eth_phy_irq_handler(unsigned irq) +{ +  ed_check_phy_state(); +  eth_mac_miim_write(PHY_INT_CLEAR, ~0);	// clear all ints +} + +void +ethernet_init(void) +{ +  eth_mac_init(ethernet_mac_addr()); + +  ed_state.link_state = LS_UNKNOWN; +  ed_state.link_speed = S_UNKNOWN; + +  // initialize MAC registers +  //  eth_mac->tx_hwmark = 0x1e; +  //eth_mac->tx_lwmark = 0x19; + +  //eth_mac->crc_chk_en = 1; +  //eth_mac->rx_max_length = 2048; + +  // configure PAUSE frame stuff +  //eth_mac->tx_pause_en = 1;		// pay attn to pause frames sent to us + +  //eth_mac->pause_quanta_set = 38;	// a bit more than 1 max frame 16kb/512 + fudge +  //eth_mac->pause_frame_send_en = 1;	// enable sending pause frames + + +  // setup PHY to interrupt on changes + +  unsigned mask = +    (PHY_INT_AN_CMPL		// auto-neg completed +     | PHY_INT_NO_LINK		// no link after auto-neg +     | PHY_INT_NO_HCD		// no highest common denominator +     | PHY_INT_MAS_SLA_ERR	// couldn't resolve master/slave  +     | PHY_INT_PRL_DET_FLT	// parallel detection fault +     | PHY_INT_LNK_CNG		// link established or broken +     | PHY_INT_SPD_CNG		// speed changed +     ); + +  eth_mac_miim_write(PHY_INT_CLEAR, ~0);	// clear all pending interrupts +  eth_mac_miim_write(PHY_INT_MASK, mask);	// enable the ones we want + +  pic_register_handler(IRQ_PHY, eth_phy_irq_handler); + +  // Advertise our flow control configuation. +  // +  // We and the link partner each specify two bits in the base page +  // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR. +  // The bits say what a device is "willing" to do, not what may actually +  // happen as a result of the negotiation.  There are 4 cases: +  // +  // PAUSE  ASM_DIR +  // +  //  0        0        I have no flow control capability. +  // +  //  1        0        I both assert and respond to flow control. +  // +  //  0        1        I assert flow control, but cannot respond.  That is, +  //                    I want to be able to send PAUSE frames, but will ignore any +  //		 	you send to me.  (This is our configuration.) +  // +  //  1        1        I can both assert and respond to flow control AND I am willing +  //                    to operate symmetrically OR asymmetrically in EITHER direction. +  //                    (We hope the link partner advertises this, otherwise we don't +  //			get what we want.) + +  int t = eth_mac_miim_read(PHY_AUTONEG_ADV); +  t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR); +  t |= NWAY_AR_ASM_DIR; + +  // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex +  t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS); + +  eth_mac_miim_write(PHY_AUTONEG_ADV, t); +  int r = eth_mac_miim_read(PHY_AUTONEG_ADV);  		// DEBUG, read back +  if (t != r){ +    printf("PHY_AUTONEG_ADV: wrote 0x%x, got 0x%x\n", t, r); +  } + +  // Restart autonegotation.   +  // We want to ensure that we're advertising our PAUSE capabilities. +  t = eth_mac_miim_read(PHY_CTRL); +  eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG); +} + +int +ethernet_check_errors(void) +{ +  // these registers are reset when read +   +  int	r = 0; +  /* +  if (eth_mac_read_rmon(0x05) != 0) +    r |= RME_RX_CRC; +  if (eth_mac_read_rmon(0x06) != 0) +    r |= RME_RX_FIFO_FULL; +  if (eth_mac_read_rmon(0x07) != 0) +    r |= RME_RX_2SHORT_2LONG; +   +  if (eth_mac_read_rmon(0x25) != 0) +    r |= RME_TX_JAM_DROP; +  if (eth_mac_read_rmon(0x26) != 0) +    r |= RME_TX_FIFO_UNDER; +  if (eth_mac_read_rmon(0x27) != 0) +    r |= RME_TX_FIFO_OVER; +  */ +  return r; +} diff --git a/firmware/microblaze/usrp2/memory_map.h b/firmware/microblaze/usrp2/memory_map.h new file mode 100644 index 000000000..eac0c217f --- /dev/null +++ b/firmware/microblaze/usrp2/memory_map.h @@ -0,0 +1,801 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* Overall Memory Map + *   0000-7FFF  32K   RAM space (16K on 1500, 24K on 2000, 32K on DSP) + *   8000-BFFF  16K   Buffer Pool + *   C000-FFFF  16K   Peripherals + */ + + +#ifndef INCLUDED_MEMORY_MAP_H +#define INCLUDED_MEMORY_MAP_H + +#include <stdint.h> + + +#define MASTER_CLK_RATE        100000000		// 100 MHz + + +//////////////////////////////////////////////////////////////// +// +//         Memory map for embedded wishbone bus +// +//////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////// +// Main RAM, Slave 0 + +#define RAM_BASE 0x0000 + +//////////////////////////////////////////////////////////////// +// Buffer Pool RAM, Slave 1 +// +// The buffers themselves are located in Slave 1, Buffer Pool RAM. +// The status registers are in Slave 5, Buffer Pool Status. +// The control register is in Slave 7, Settings Bus. + +#define BUFFER_POOL_RAM_BASE 0x8000 + +#define	NBUFFERS                8 +#define BP_NLINES	   0x0200	// number of 32-bit lines in a buffer +#define BP_LAST_LINE	(BP_NLINES - 1)	// last line in a buffer + +#define buffer_pool_ram \ +  ((uint32_t *) BUFFER_POOL_RAM_BASE) + +#define buffer_ram(n) (&buffer_pool_ram[(n) * BP_NLINES]) + + +///////////////////////////////////////////////////// +// SPI Core, Slave 2.  See core docs for more info +#define SPI_BASE 0xC000   // Base address (16-bit) + +typedef struct { +  volatile uint32_t	txrx0; +  volatile uint32_t	txrx1; +  volatile uint32_t	txrx2; +  volatile uint32_t	txrx3; +  volatile uint32_t	ctrl; +  volatile uint32_t	div; +  volatile uint32_t	ss; +} spi_regs_t; + +#define spi_regs ((spi_regs_t *) SPI_BASE) + + +// Masks for controlling different peripherals +#define SPI_SS_AD9510    1 +#define SPI_SS_AD9777    2 +#define SPI_SS_RX_DAC    4 +#define SPI_SS_RX_ADC    8 +#define SPI_SS_RX_DB    16 +#define SPI_SS_TX_DAC   32 +#define SPI_SS_TX_ADC   64 +#define SPI_SS_TX_DB   128 +#define SPI_SS_ADS64P44 256 + +// Masks for different parts of CTRL reg +#define SPI_CTRL_ASS      (1<<13) +#define SPI_CTRL_IE       (1<<12) +#define SPI_CTRL_LSB      (1<<11) +#define SPI_CTRL_TXNEG    (1<<10) +#define SPI_CTRL_RXNEG    (1<< 9) +#define SPI_CTRL_GO_BSY   (1<< 8) +#define SPI_CTRL_CHAR_LEN_MASK 0x7F + +//////////////////////////////////////////////// +// I2C, Slave 3 +// See Wishbone I2C-Master Core Specification. + +#define I2C_BASE 0xC400 + +typedef struct { +  volatile uint32_t  prescaler_lo;	// r/w +  volatile uint32_t  prescaler_hi;	// r/w +  volatile uint32_t  ctrl;		// r/w +  volatile uint32_t  data;		// wr = transmit reg; rd = receive reg +  volatile uint32_t  cmd_status;	// wr = command reg;  rd = status reg +} i2c_regs_t; + +#define i2c_regs ((i2c_regs_t *) I2C_BASE) + +#define	I2C_CTRL_EN	(1 << 7)	// core enable +#define	I2C_CTRL_IE	(1 << 6)	// interrupt enable + +// +// STA, STO, RD, WR, and IACK bits are cleared automatically +// +#define	I2C_CMD_START	(1 << 7)	// generate (repeated) start condition +#define I2C_CMD_STOP	(1 << 6)	// generate stop condition +#define	I2C_CMD_RD	(1 << 5)	// read from slave +#define I2C_CMD_WR	(1 << 4)	// write to slave +#define	I2C_CMD_NACK	(1 << 3)	// when a rcvr, send ACK (ACK=0) or NACK (ACK=1) +#define I2C_CMD_RSVD_2	(1 << 2)	// reserved +#define	I2C_CMD_RSVD_1	(1 << 1)	// reserved +#define I2C_CMD_IACK	(1 << 0)	// set to clear pending interrupt + +#define I2C_ST_RXACK	(1 << 7)	// Received acknowledgement from slave (1 = NAK, 0 = ACK) +#define	I2C_ST_BUSY	(1 << 6)	// 1 after START signal detected; 0 after STOP signal detected +#define	I2C_ST_AL	(1 << 5)	// Arbitration lost.  1 when core lost arbitration +#define	I2C_ST_RSVD_4	(1 << 4)	// reserved +#define	I2C_ST_RSVD_3	(1 << 3)	// reserved +#define	I2C_ST_RSVD_2	(1 << 2)	// reserved +#define I2C_ST_TIP	(1 << 1)	// Transfer-in-progress +#define	I2C_ST_IP	(1 << 0)	// Interrupt pending + + +//////////////////////////////////////////////// +// GPIO, Slave 4 +// +// These go to the daughterboard i/o pins + +#define GPIO_BASE 0xC800 + +typedef struct { +  volatile uint32_t	io;	  // tx data in high 16, rx in low 16 +  volatile uint32_t     ddr;      // 32 bits, 1 means output. tx in high 16, rx in low 16 +  volatile uint32_t	tx_sel;   // 16 2-bit fields select which source goes to TX DB +  volatile uint32_t	rx_sel;   // 16 2-bit fields select which source goes to RX DB +} gpio_regs_t; + +// each 2-bit sel field is layed out this way +#define GPIO_SEL_SW	   0 // if pin is an output, set by software in the io reg +#define	GPIO_SEL_ATR	   1 // if pin is an output, set by ATR logic +#define	GPIO_SEL_DEBUG_0   2 // if pin is an output, debug lines from FPGA fabric +#define	GPIO_SEL_DEBUG_1   3 // if pin is an output, debug lines from FPGA fabric + +#define gpio_base ((gpio_regs_t *) GPIO_BASE) + +/////////////////////////////////////////////////// +// Buffer Pool Status, Slave 5 +// +// The buffers themselves are located in Slave 1, Buffer Pool RAM. +// The status registers are in Slave 5, Buffer Pool Status. +// The control register is in Slave 7, Settings Bus. + +#define BUFFER_POOL_STATUS_BASE 0xCC00 + +typedef struct { +  volatile uint32_t last_line[NBUFFERS]; // last line xfer'd in buffer +  volatile uint32_t status;	         // error and done flags +  volatile uint32_t hw_config;	         // see below +  volatile uint32_t dummy[3]; +  volatile uint32_t irqs; +  volatile uint32_t pri_enc_bp_status; +  volatile uint32_t cycle_count; +} buffer_pool_status_t; + +#define buffer_pool_status ((buffer_pool_status_t *) BUFFER_POOL_STATUS_BASE) + +/* + * Buffer n's xfer is done. + * Clear this bit by issuing bp_clear_buf(n) + */ +#define BPS_DONE(n)     (0x00000001 << (n)) +#define BPS_DONE_0	BPS_DONE(0) +#define BPS_DONE_1	BPS_DONE(1) +#define BPS_DONE_2	BPS_DONE(2) +#define BPS_DONE_3	BPS_DONE(3) +#define BPS_DONE_4	BPS_DONE(4) +#define BPS_DONE_5	BPS_DONE(5) +#define BPS_DONE_6	BPS_DONE(6) +#define BPS_DONE_7	BPS_DONE(7) + +/* + * Buffer n's xfer had an error. + * Clear this bit by issuing bp_clear_buf(n) + */ +#define BPS_ERROR(n)	(0x00000100 << (n)) +#define BPS_ERROR_0	BPS_ERROR(0) +#define BPS_ERROR_1	BPS_ERROR(1) +#define BPS_ERROR_2	BPS_ERROR(2) +#define BPS_ERROR_3	BPS_ERROR(3) +#define BPS_ERROR_4	BPS_ERROR(4) +#define BPS_ERROR_5	BPS_ERROR(5) +#define BPS_ERROR_6	BPS_ERROR(6) +#define BPS_ERROR_7	BPS_ERROR(7) + +/* + * Buffer n is idle.  A buffer is idle if it's not + * DONE, ERROR, or processing a transaction.  If it's + * IDLE, it's safe to start a new transaction. + * + * Clear this bit by starting a xfer with + * bp_send_from_buf or bp_receive_to_buf. + */ +#define BPS_IDLE(n)     (0x00010000 << (n)) +#define BPS_IDLE_0	BPS_IDLE(0) +#define BPS_IDLE_1	BPS_IDLE(1) +#define BPS_IDLE_2	BPS_IDLE(2) +#define BPS_IDLE_3	BPS_IDLE(3) +#define BPS_IDLE_4	BPS_IDLE(4) +#define BPS_IDLE_5	BPS_IDLE(5) +#define BPS_IDLE_6	BPS_IDLE(6) +#define BPS_IDLE_7	BPS_IDLE(7) + +/* + * Buffer n has a "slow path" packet in it. + * This bit is orthogonal to the bits above and indicates that + * the FPGA ethernet rx protocol engine has identified this packet + * as one requiring firmware intervention. + */ +#define BPS_SLOWPATH(n) (0x01000000 << (n)) +#define BPS_SLOWPATH_0	BPS_SLOWPATH(0) +#define BPS_SLOWPATH_1	BPS_SLOWPATH(1) +#define BPS_SLOWPATH_2	BPS_SLOWPATH(2) +#define BPS_SLOWPATH_3	BPS_SLOWPATH(3) +#define BPS_SLOWPATH_4	BPS_SLOWPATH(4) +#define BPS_SLOWPATH_5	BPS_SLOWPATH(5) +#define BPS_SLOWPATH_6	BPS_SLOWPATH(6) +#define BPS_SLOWPATH_7	BPS_SLOWPATH(7) + + +#define BPS_DONE_ALL	  0x000000ff	// mask of all dones +#define BPS_ERROR_ALL	  0x0000ff00	// mask of all errors +#define BPS_IDLE_ALL      0x00ff0000	// mask of all idles +#define BPS_SLOWPATH_ALL  0xff000000	// mask of all slowpaths + +// The hw_config register + +#define	HWC_SIMULATION		0x80000000 +#define	HWC_WB_CLK_DIV_MASK	0x0000000f + +/*! + * \brief return non-zero if we're running under the simulator + */ +inline static int +hwconfig_simulation_p(void) +{ +  return buffer_pool_status->hw_config & HWC_SIMULATION; +} + +/*! + * \brief Return Wishbone Clock divisor. + * The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor. + */ +inline static int +hwconfig_wishbone_divisor(void) +{ +  return buffer_pool_status->hw_config & HWC_WB_CLK_DIV_MASK; +} + +/////////////////////////////////////////////////// +// Ethernet Core, Slave 6 + +#define ETH_BASE 0xD000 + +#include "eth_mac_regs.h" + +#define eth_mac ((eth_mac_regs_t *) ETH_BASE) + +//////////////////////////////////////////////////// +// Settings Bus, Slave #7, Not Byte Addressable! +// +// Output-only from processor point-of-view. +// 1KB of address space (== 256 32-bit write-only regs) + + +#define MISC_OUTPUT_BASE        0xD400 +#define	TX_PROTOCOL_ENGINE_BASE 0xD480 +#define	RX_PROTOCOL_ENGINE_BASE 0xD4C0 +#define BUFFER_POOL_CTRL_BASE   0xD500 +#define LAST_SETTING_REG        0xD7FC	// last valid setting register + +#define SR_MISC 0 +#define SR_TX_PROT_ENG 32 +#define SR_RX_PROT_ENG 48 +#define SR_BUFFER_POOL_CTRL 64 +#define SR_UDP_SM 96 +#define SR_TX_DSP 208 +#define SR_TX_CTRL 224 +#define SR_RX_DSP 160 +#define SR_RX_CTRL 176 +#define SR_TIME64 192 +#define SR_SIMTIMER 198 +#define SR_LAST 255 + +#define	_SR_ADDR(sr)	(MISC_OUTPUT_BASE + (sr) * sizeof(uint32_t)) + +// --- buffer pool control regs --- + +typedef struct { +  volatile uint32_t ctrl; +} buffer_pool_ctrl_t; + +// buffer pool ports + +#define	PORT_SERDES	0	// serial/deserializer +#define	PORT_DSP	1	// DSP tx or rx pipeline +#define	PORT_ETH	2	// ethernet tx or rx +#define	PORT_RAM	3	// RAM tx or rx + +// the buffer pool ctrl register fields + +#define BPC_BUFFER(n) (((n) & 0xf) << 28) +#define   BPC_BUFFER_MASK      BPC_BUFFER(~0) +#define   BPC_BUFFER_0	       BPC_BUFFER(0) +#define   BPC_BUFFER_1	       BPC_BUFFER(1) +#define   BPC_BUFFER_2	       BPC_BUFFER(2) +#define   BPC_BUFFER_3	       BPC_BUFFER(3) +#define   BPC_BUFFER_4	       BPC_BUFFER(4) +#define   BPC_BUFFER_5	       BPC_BUFFER(5) +#define   BPC_BUFFER_6	       BPC_BUFFER(6) +#define   BPC_BUFFER_7	       BPC_BUFFER(7) +#define	  BPC_BUFFER_NIL       BPC_BUFFER(0x8)	// disable + +#define BPC_PORT(n) (((n) & 0x7) << 25) +#define   BPC_PORT_MASK        BPC_PORT(~0) +#define   BPC_PORT_SERDES      BPC_PORT(PORT_SERDES) +#define   BPC_PORT_DSP	       BPC_PORT(PORT_DSP) +#define   BPC_PORT_ETH         BPC_PORT(PORT_ETH) +#define   BPC_PORT_RAM         BPC_PORT(PORT_RAM) +#define   BPC_PORT_NIL	       BPC_PORT(0x4)   	// disable + +#define	BPC_CLR	       	       (1 << 24)  // mutually excl commands +#define	BPC_READ	       (1 << 23) +#define BPC_WRITE              (1 << 22) + +#define BPC_STEP(step) (((step) & 0xf) << 18) +#define   BPC_STEP_MASK	       BPC_STEP(~0) +#define BPC_LAST_LINE(line) (((line) & 0x1ff) << 9) +#define   BPC_LAST_LINE_MASK   BPC_LAST_LINE(~0) +#define BPC_FIRST_LINE(line) (((line) & 0x1ff) << 0) +#define   BPC_FIRST_LINE_MASK  BPC_FIRST_LINE(~0) + +#define buffer_pool_ctrl ((buffer_pool_ctrl_t *) BUFFER_POOL_CTRL_BASE) + +// --- misc outputs --- + +typedef struct { +  volatile uint32_t	clk_ctrl; +  volatile uint32_t	serdes_ctrl; +  volatile uint32_t	adc_ctrl; +  volatile uint32_t	leds; +  volatile uint32_t	phy_ctrl;	// LSB is reset line to eth phy +  volatile uint32_t	debug_mux_ctrl; +  volatile uint32_t     ram_page;       // FIXME should go somewhere else... +  volatile uint32_t     flush_icache;   // Flush the icache +  volatile uint32_t     led_src;        // HW or SW control for LEDs +} output_regs_t; + +#define CLK_RESET  (1<<4) +#define CLK_ENABLE (1<<3) | (1<<2) +#define CLK_SEL    (1<<1) | (1<<0) + +#define SERDES_ENABLE 8 +#define SERDES_PRBSEN 4 +#define SERDES_LOOPEN 2 +#define SERDES_RXEN   1 + +#define	ADC_CTRL_ON	0x0F +#define	ADC_CTRL_OFF	0x00 + +// crazy order that matches the labels on the case + +#define	LED_A		(1 << 4) +#define	LED_B		(1 << 1) +#define	LED_C		(1 << 3) +#define	LED_D		(1 << 0) +#define	LED_E		(1 << 2) +//      LED_F		// controlled by CPLD +#define	LED_RJ45	(1 << 5) + +#define output_regs ((output_regs_t *) MISC_OUTPUT_BASE) + +// --- udp tx regs --- + +typedef struct { +  // Bits 19:16 are control info; bits 15:0 are data (see below) +  // First two words are unused. +  volatile uint32_t _nope[2]; +  //--- ethernet header - 14 bytes--- +  volatile struct{ +    uint32_t mac_dst_0_1; //word 2 +    uint32_t mac_dst_2_3; +    uint32_t mac_dst_4_5; +    uint32_t mac_src_0_1; +    uint32_t mac_src_2_3; +    uint32_t mac_src_4_5; +    uint32_t ether_type; //word 8 +  } eth_hdr; +  //--- ip header - 20 bytes --- +  volatile struct{ +    uint32_t ver_ihl_tos; //word 9 +    uint32_t total_length; +    uint32_t identification; +    uint32_t flags_frag_off; +    uint32_t ttl_proto; +    uint32_t checksum; +    uint32_t src_addr_high; +    uint32_t src_addr_low; +    uint32_t dst_addr_high; +    uint32_t dst_addr_low; //word 18 +  } ip_hdr; +  //--- udp header - 8 bytes --- +  volatile struct{ +    uint32_t src_port; //word 19 +    uint32_t dst_port; +    uint32_t length; +    uint32_t checksum; //word 22 +  } udp_hdr; +  volatile uint32_t _pad[32-23]; +} sr_udp_sm_t; + +// control bits (all expect UDP_SM_LAST_WORD are mutually exclusive) + +// This is the last word of the header +#define	UDP_SM_LAST_WORD		(1 << 19) + +// Insert IP header checksum here.  Data is the xor of 16'hFFFF and +// the values written into regs 9-13 and 15-18. +#define	UDP_SM_INS_IP_HDR_CHKSUM	(1 << 18) + +// Insert IP Length here (data ignored) +#define	UDP_SM_INS_IP_LEN		(1 << 17) + +// Insert UDP Length here (data ignore) +#define	UDP_SM_INS_UDP_LEN		(1 << 16) + +#define sr_udp_sm ((sr_udp_sm_t *) _SR_ADDR(SR_UDP_SM)) + +// --- dsp tx regs --- + +#define MIN_CIC_INTERP	1 +#define	MAX_CIC_INTERP  128 + +typedef struct { +  volatile uint32_t     num_chan; +  volatile uint32_t     clear_state;	// clears out state machine, fifos, +  volatile uint32_t     report_sid; +  volatile uint32_t     policy; +  volatile uint32_t     cyc_per_up; +  volatile uint32_t     packets_per_up; +} sr_tx_ctrl_t; + +#define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL)) + +typedef struct { +  volatile int32_t	freq; +  volatile uint32_t	scale_iq;	// {scale_i,scale_q} +  volatile uint32_t     interp_rate; +  volatile uint32_t     _padding0;      // padding for the tx_mux +                                        //   NOT freq, scale, interp +  /*! +   * \brief output mux configuration. +   * +   * <pre> +   *     3                   2                   1                        +   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   *  +-------------------------------+-------+-------+-------+-------+ +   *  |                                               | DAC1  |  DAC0 | +   *  +-------------------------------+-------+-------+-------+-------+ +   *  +   *  There are N DUCs (1 now) with complex inputs and outputs. +   *  There are two DACs. +   *  +   *  Each 4-bit DACx field specifies the source for the DAC +   *  Each subfield is coded like this:  +   *  +   *     3 2 1 0 +   *    +-------+ +   *    |   N   | +   *    +-------+ +   *  +   *  N specifies which DUC output is connected to this DAC. +   *  +   *   N   which interp output +   *  ---  ------------------- +   *   0   DUC 0 I +   *   1   DUC 0 Q +   *   2   DUC 1 I +   *   3   DUC 1 Q +   *   F   All Zeros +   *    +   * The default value is 0x10 +   * </pre> +   */ +  volatile uint32_t	tx_mux; + +} dsp_tx_regs_t; +   +#define dsp_tx_regs ((dsp_tx_regs_t *) _SR_ADDR(SR_TX_DSP)) + +// --- VITA RX CTRL regs --- +typedef struct { +  // The following 3 are logically a single command register. +  // They are clocked into the underlying fifo when time_ticks is written. +  volatile uint32_t	cmd;		// {now, chain, num_samples(30) +  volatile uint32_t	time_secs; +  volatile uint32_t	time_ticks; + +  volatile uint32_t	clear_overrun;	// write anything to clear overrun +  volatile uint32_t	vrt_header;	// word 0 of packet.  FPGA fills in packet counter +  volatile uint32_t	vrt_stream_id;	// word 1 of packet.  +  volatile uint32_t	vrt_trailer; +  volatile uint32_t	nsamples_per_pkt; +  volatile uint32_t     nchannels;      // 1 in basic case, up to 4 for vector sources +  volatile uint32_t     pad[7];         // Make each structure 16 elements long +} sr_rx_ctrl_t; + +#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL)) + +// --- dsp rx regs --- +#define	MIN_CIC_DECIM	1 +#define	MAX_CIC_DECIM   128 + +typedef struct { +  volatile int32_t	freq; +  volatile uint32_t	scale_iq;	// {scale_i,scale_q} +  volatile uint32_t     decim_rate; +  volatile uint32_t     dcoffset_i;     // Bit 31 high sets fixed offset mode, using lower 14 bits, +                                        // otherwise it is automatic  +  volatile uint32_t     dcoffset_q;     // Bit 31 high sets fixed offset mode, using lower 14 bits + +  /*! +   * \brief input mux configuration. +   * +   * This determines which ADC (or constant zero) is connected to  +   * each DDC input.  There are N DDCs (1 now).  Each has two inputs. +   * +   * <pre> +   * Mux value: +   * +   *    3                   2                   1                        +   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * |                                                       |Q0 |I0 | +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * +   * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) +   * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) +   * +   * The default value is 0x4 +   * </pre> +   */ +  volatile uint32_t     rx_mux;        // called adc_mux in dsp_core_rx.v + +  /*! +   * \brief Streaming GPIO configuration +   * +   * This determines whether the LSBs of I and Q samples come from the DSP +   * pipeline or from the io_rx GPIO pins.  To stream GPIO, one must first +   * set the GPIO data direction register to have io_rx[15] and/or io_rx[14] +   * configured as inputs.  The GPIO pins will be sampled at the time the +   * remainder of the DSP sample is strobed into the RX sample FIFO.  There +   * will be a decimation-dependent fixed time offset between the GPIO +   * sample stream and the associated RF samples. +   * +   *    3                   2                   1                        +   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * |                           MBZ                             |Q|I| +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * +   * I         0=LSB comes from DSP pipeline (default) +   *           1=LSB comes from io_rx[15] +   *  +   * Q         0=LSB comes from DSP pipeline (default) +   *           1=LSB comes from io_rx[14] +   */ +  volatile uint32_t gpio_stream_enable; + +} dsp_rx_regs_t; +   +#define dsp_rx_regs ((dsp_rx_regs_t *) _SR_ADDR(SR_RX_DSP)) + +// ---------------------------------------------------------------- +// VITA49 64 bit time (write only) +  /*! +   * \brief Time 64 flags +   * +   * <pre> +   * +   *    3                   2                   1                        +   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   * +-----------------------------------------------------------+-+-+ +   * |                                                           |S|P| +   * +-----------------------------------------------------------+-+-+ +   * +   * P - PPS edge selection (0=negedge, 1=posedge, default=0) +   * S - Source (0=sma, 1=mimo, 0=default) +   * +   * </pre> +   */ +typedef struct { +  volatile uint32_t	secs;	// value to set absolute secs to on next PPS +  volatile uint32_t	ticks;	// value to set absolute ticks to on next PPS +  volatile uint32_t flags;  // flags - see chart above +  volatile uint32_t imm;    // set immediate (0=latch on next pps, 1=latch immediate, default=0) +} sr_time64_t; + +#define sr_time64 ((sr_time64_t *) _SR_ADDR(SR_TIME64)) + + +/*  + * --- ethernet tx protocol engine regs (write only) --- + * + * These registers control the transmit portion of the ethernet + * protocol engine (out of USRP2).  The protocol engine handles fifo + * status and sequence number insertion in outgoing packets, and + * automagically generates status packets when required to inform the + * host of changes in fifo availability. + * + * All outgoing packets have their fifo_status field set to the number + * of 32-bit lines of fifo available in the ethernet Rx fifo (see + * usrp2_eth_packet.h).  Seqno's are set if FIXME, else 0. + * + * FIXME clean this up once we know how it's supposed to behave. + */ + +typedef struct { +  volatile uint32_t  flags;	     // not yet fully defined (channel?) +  volatile uint32_t  mac_dst0123;    // 4 bytes of destination mac addr +  volatile uint32_t  mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr +  volatile uint32_t  mac_src2345;    // 4 bytes of destination mac addr +  volatile uint32_t  seqno;	     // Write to init seqno.  It autoincs on match +} tx_proto_engine_regs_t; + +#define tx_proto_engine ((tx_proto_engine_regs_t *) TX_PROTOCOL_ENGINE_BASE) + +/* + * --- ethernet rx protocol engine regs (write only) --- + * + * These registers control the receive portion of the ethernet + * protocol engine (into USRP2).  The protocol engine offloads common + * packet inspection operations so that firmware has less to do on + * "fast path" packets. + * + * The registers define conditions which must be matched for a packet + * to be considered a "fast path" packet.  If a received packet + * matches the src and dst mac address, ethertype, flags field, and + * expected seqno number it is considered a "fast path" packet, and + * the expected seqno is updated.  If the packet fails to satisfy any + * of the above conditions it's a "slow path" packet, and the + * corresponding SLOWPATH flag will be set buffer_status register. + */ + +typedef struct { +  volatile uint32_t  flags;	     // not yet fully defined (channel?) +  volatile uint32_t  mac_dst0123;    // 4 bytes of destination mac addr +  volatile uint32_t  mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr +  volatile uint32_t  mac_src2345;    // 4 bytes of destination mac addr +  volatile uint32_t  ethertype_pad;  // ethertype in high 16-bits +} rx_proto_engine_regs_t; + +#define rx_proto_engine ((rx_proto_engine_regs_t *) RX_PROTOCOL_ENGINE_BASE) + + + +/////////////////////////////////////////////////// +// Simple Programmable Interrupt Controller, Slave 8 + +#define PIC_BASE  0xD800 + +// Interrupt request lines +// Bit numbers (LSB == 0) that correpond to interrupts into PIC + +#define	IRQ_BUFFER	0	// buffer manager +#define	IRQ_ONETIME	1 +#define	IRQ_SPI		2 +#define	IRQ_I2C		3 +#define	IRQ_PHY		4	// ethernet PHY +#define	IRQ_UNDERRUN	5 +#define	IRQ_OVERRUN	6 +#define	IRQ_PPS		7	// pulse per second +#define	IRQ_UART_RX	8 +#define	IRQ_UART_TX	9 +#define	IRQ_SERDES	10 +#define	IRQ_CLKSTATUS	11 +#define IRQ_PERIODIC    12 + +#define IRQ_TO_MASK(x) (1 << (x)) + +#define PIC_BUFFER_INT    IRQ_TO_MASK(IRQ_BUFFER) +#define PIC_ONETIME_INT   IRQ_TO_MASK(IRQ_ONETIME) +#define PIC_SPI_INT       IRQ_TO_MASK(IRQ_SPI) +#define PIC_I2C_INT       IRQ_TO_MASK(IRQ_I2C) +#define PIC_PHY_INT       IRQ_TO_MASK(IRQ_PHY) +#define PIC_UNDERRUN_INT  IRQ_TO_MASK(IRQ_UNDERRUN) +#define PIC_OVERRUN_INT   IRQ_TO_MASK(IRQ_OVERRUN) +#define PIC_PPS_INT   	  IRQ_TO_MASK(IRQ_PPS) +#define PIC_UART_RX_INT   IRQ_TO_MASK(IRQ_UART_RX) +#define PIC_UART_TX_INT   IRQ_TO_MASK(IRQ_UART_TX) +#define PIC_SERDES        IRQ_TO_MASK(IRQ_SERDES) +#define PIC_CLKSTATUS     IRQ_TO_MASK(IRQ_CLKSTATUS) + +typedef struct { +  volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level +  volatile uint32_t polarity;	 // mask: 1 -> rising edge +  volatile uint32_t mask;	 // mask: 1 -> disabled +  volatile uint32_t pending;	 // mask: 1 -> pending; write 1's to clear pending ints +} pic_regs_t; + +#define pic_regs ((pic_regs_t *) PIC_BASE) + +// ---------------------------------------------------------------- +// WB_CLK_RATE is the time base for this +typedef struct { +  volatile uint32_t	onetime;   // Number of wb clk cycles till the onetime interrupt +  volatile uint32_t	periodic;  // Repeat rate of periodic interrupt +} sr_simple_timer_t; + +#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER)) + +/////////////////////////////////////////////////// +// UART, Slave 10 + +#define UART_BASE  0xE000 + +typedef struct { +  //  All elements are 8 bits except for clkdiv (16), but we use uint32 to make  +  //    the hardware for decoding easier +  volatile uint32_t clkdiv;  // Set to 50e6 divided by baud rate (no x16 factor) +  volatile uint32_t txlevel; // Number of spaces in the FIFO for writes +  volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads +  volatile uint32_t txchar;  // Write characters to be sent here +  volatile uint32_t rxchar;  // Read received characters here +} uart_regs_t; + +#define uart_regs ((uart_regs_t *) UART_BASE) + +/////////////////////////////////////////////////// +// ATR Controller, Slave 11 + +#define ATR_BASE  0xE400 + +typedef struct { +  volatile uint32_t	v[16]; +} atr_regs_t; + +#define	ATR_IDLE	0x0	// indicies into v +#define ATR_TX		0x1 +#define	ATR_RX		0x2 +#define	ATR_FULL	0x3 + +#define atr_regs ((atr_regs_t *) ATR_BASE) + +/////////////////////////////////////////////////// +// SD Card SPI interface, Slave 13 +//   All regs are 8 bits wide, but are accessed as if they are 32 bits + +#define SDSPI_BASE  0xEC00 + +typedef struct { +  volatile uint32_t status;  // Write a 1 or 0 for controlling CS +  volatile uint32_t clkdiv; +  volatile uint32_t send_dat; +  volatile uint32_t receive_dat; +} sdspi_regs_t; + +#define sdspi_regs ((sdspi_regs_t *) SDSPI_BASE) + +/////////////////////////////////////////////////// +// External RAM interface, Slave 14 +//   Pages are 1K.  Page is 10 bits, set by a control register +//    output_regs->ram_page + +#define EXTRAM_BASE 0xF000 +#define extram ((volatile uint32_t *) EXTRAM_BASE) + + +/////////////////////////////////////////////////// + +#endif + diff --git a/firmware/microblaze/usrp2/sd.c b/firmware/microblaze/usrp2/sd.c new file mode 100644 index 000000000..d000b28ae --- /dev/null +++ b/firmware/microblaze/usrp2/sd.c @@ -0,0 +1,197 @@ +/* -*- c -*- */ +/* + * Copyright 2008 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "sd.h" +#include "memory_map.h" +#include "stdint.h" +#include "stdio.h" + +static inline void +sd_packarg(unsigned char *argument,unsigned int value) +{ +  argument[3] = (unsigned char)(value >> 24); +  argument[2] = (unsigned char)(value >> 16); +  argument[1] = (unsigned char)(value >> 8); +  argument[0] = (unsigned char)(value); +} + +int +sd_init(void) +{ +  unsigned char response[5]; +  unsigned char argument[4]; +  int i,j; + +  for(i=0;i<4;i++) +    argument[i] = 0; + +  // Set clock to less than 400 kHz to start out +  sdspi_regs->clkdiv = 128; + +  // Delay at least 74 cycles +  sd_assert_cs(); +  for(i = 0; i < 100; i++) +    sd_send_byte(SD_IDLE); +  sd_deassert_cs(); +   +  // Initialization Sequence -- CMD0 CMD55 ACMD41 CMD58 +  // Put card in idle state +  if(sd_send_command(SD_CMD0,SD_CMD0_R,response,argument)==0) +    return 0;  // Something went wrong in command + +  j = 0; +  do { +    j++; +    if(sd_send_command(SD_CMD55,SD_CMD55_R,response,argument)==1) +      sd_send_command(SD_ACMD41,SD_ACMD41_R,response,argument); +    else +      j = SD_IDLE_WAIT_MAX; +  } +  while(((response[0] & SD_MSK_IDLE) == SD_MSK_IDLE) && (j < SD_IDLE_WAIT_MAX)); + +  if(j>= SD_IDLE_WAIT_MAX)  // IDLE timeout exceeded, card asleep +    return 0; +   +  // CMD58 reads the SD card capabilities +  if(sd_send_command(SD_CMD58,SD_CMD58_R,response,argument)==0) +    return 0;  // CMD58 FAIL + +  if((response[2] & SD_MSK_OCR_33) != SD_MSK_OCR_33) +    return 0;  // Card doesn't do 3.3V + +  //printf("OCR = %x %x %x %x\n",response[0],response[1],response[2],response[3]); + +  // Set blocklen here +  sd_packarg(argument,SD_BLOCKLEN); +  if(sd_send_command(SD_CMD16,SD_CMD16_R,response,argument)==0) +    return 0;    // Set Blocklen failed +   +  // Reset back to high speed +  sdspi_regs->clkdiv = 4; +  //puts("finished init\n"); +  return 1; +} + +int sd_send_command(unsigned char cmd,unsigned char response_type, +		    unsigned char *response,unsigned char *argument) +{ +  int i; +  char response_length; +  unsigned char tmp; + +  sd_assert_cs(); +  sd_send_byte((cmd & 0x3F) | 0x40); +  for(i=3;i>=0;i--) +    sd_send_byte(argument[i]); +  sd_send_byte(SD_CRC);   // Always the same + +  response_length = 0; +  switch(response_type) +    { +    case SD_R1: +    case SD_R1B: +      response_length = 1; +      break; +    case SD_R2: +      response_length = 2; +      break; +    case SD_R3: +      response_length = 5; +      break; +    default: +      break; +    } + +  // Wait for a response, which will have a 0 start bit +  i = 0; +  do +    { +      tmp = sd_rcv_byte(); +      i++; +    } +  while(((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT); + +  if(i>= SD_CMD_TIMEOUT) +    { +      sd_deassert_cs(); +      //puts("cmd send timeout\n"); +      return 0; +    } + +  for(i=response_length-1; i>=0; i--) +    { +      response[i] = tmp; +      tmp = sd_rcv_byte(); +    } +  i = 0; +  if(response_type == SD_R1B) +    { +      do +	{ +	  i++; +	  tmp = sd_rcv_byte(); +	} +      while(tmp != SD_IDLE); +      sd_send_byte(SD_IDLE); +    } +   +  //puts("send cmd success\n"); +  sd_deassert_cs(); +  return 1; +} + +int +sd_read_block (unsigned int blockaddr, unsigned char *buf) +{ +  unsigned char response[5]; +  unsigned char argument[4]; +  unsigned int i = 0; +  unsigned char tmp; + +  blockaddr <<= SD_BLOCKLEN_NBITS; +  sd_packarg(argument,blockaddr); +  if(sd_send_command(SD_CMD17,SD_CMD17_R,response,argument)==0) +    return 0;    //Failed READ; +  if(response[0] != 0) +    return 0;    //Misaligned READ + +  sd_assert_cs(); +  i = 0; +  do +    { +      tmp = sd_rcv_byte(); +      i++; +    } +  while((tmp == 0xFF) && (i < SD_RD_TIMEOUT)); +  if((i>= SD_RD_TIMEOUT) ||((tmp & SD_MSK_TOK_DATAERROR) == 0)) +    { +      sd_send_byte(SD_IDLE);  // Send a dummy before quitting +      return 0;   // Data ERROR +    } +  for(i=0;i<SD_BLOCKLEN;i++) +    buf[i] = sd_rcv_byte(); +  return 1; + +} + +int +sd_write_block(unsigned int blockaddr, const unsigned char *buf) +{ +  // FIXME not implemented yet +  return 0; +} diff --git a/firmware/microblaze/usrp2/sd.h b/firmware/microblaze/usrp2/sd.h new file mode 100644 index 000000000..e2d0ae38e --- /dev/null +++ b/firmware/microblaze/usrp2/sd.h @@ -0,0 +1,122 @@ +/* -*- c -*- */ +/* + * Copyright 2008 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_SD_H +#define INCLUDED_SD_H + +#include "memory_map.h" + +#define SD_READY 1 +#define SD_IDLE_WAIT_MAX 100 +#define SD_CMD_TIMEOUT 100 +#define SD_RD_TIMEOUT 1000 + +#define SD_CMD0 0 +#define SD_CMD1 1 +#define SD_CMD9 9 +#define SD_CMD10 10 +#define SD_CMD12 12 +#define SD_CMD13 13 +#define SD_CMD16 16 +#define SD_CMD17 17  +#define SD_CMD18 18 +#define SD_CMD24 24 +#define SD_CMD25 25 +#define SD_CMD27 27 +#define SD_CMD28 28 +#define SD_CMD29 29 +#define SD_CMD30 30 +#define SD_CMD32 32 +#define SD_CMD33 33 +#define SD_CMD38 38 +#define SD_CMD55 55 +#define SD_CMD58 58 +#define SD_CMD59 59 +#define SD_ACMD41 41 +#define SD_IDLE 0xFF +#define SD_CRC 0x95 + +#define SD_R1 1 +#define SD_R1B 2 +#define SD_R2 3 +#define SD_R3 4 + +#define SD_CMD0_R SD_R1 +#define SD_CMD16_R SD_R1 +#define SD_CMD17_R SD_R1 +#define SD_CMD55_R SD_R1 +#define SD_ACMD41_R SD_R1 +#define SD_CMD58_R SD_R3 + +#define SD_BLOCKLEN 512 +#define SD_BLOCKLEN_NBITS 9 + +#define SD_MSK_IDLE 0x01 +#define SD_MSK_OCR_33 0xC0 +#define SD_MSK_TOK_DATAERROR 0xE0 + + +int sd_init(void); + +static inline void +sd_assert_cs(void) +{ +  // Wait for idle before doing anything +  while(sdspi_regs->status != SD_READY) +    ; +  sdspi_regs->status = 1; +} + +static inline void +sd_deassert_cs(void) +{ +  // Wait for idle before doing anything +  while(sdspi_regs->status != SD_READY) +    ; +  sdspi_regs->status = 0; +} + +static inline char +sd_rcv_byte(void) +{ +  // Wait for idle before doing anything +  while(sdspi_regs->status != SD_READY) +    ; +  sdspi_regs->send_dat = SD_IDLE; +  while(sdspi_regs->status != SD_READY) +    ; +  return sdspi_regs-> receive_dat; +} + +static inline void +sd_send_byte(char dat) +{ +  // Wait for idle before doing anything +  while(sdspi_regs->status != SD_READY) +    ;      // Wait for status = 1 (ready) +  sdspi_regs->send_dat = dat; +} + + +int sd_send_command(unsigned char cmd,unsigned char response_type, +		    unsigned char *response,unsigned char *argument); + +int sd_read_block (unsigned int blockaddr, unsigned char *buf); +int sd_write_block(unsigned int blockaddr, const unsigned char *buf); + +#endif /* INCLUDED_SD_H */ diff --git a/firmware/microblaze/usrp2/udp_fw_update.c b/firmware/microblaze/usrp2/udp_fw_update.c new file mode 100644 index 000000000..14eb0b1ee --- /dev/null +++ b/firmware/microblaze/usrp2/udp_fw_update.c @@ -0,0 +1,34 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +//Routines to handle updating the SPI Flash firmware via UDP + +#include "net_common.h" +#include "usrp2/fw_common.h" +#include <nonstdio.h> +#include "udp_fw_update.h" + +//Firmware update packet handler +void handle_udp_fw_update_packet(struct socket_address src, struct socket_address dst, +                                 unsigned char *payload, int payload_len) { + +  usrp2_fw_update_data_t update_data_out; +  update_data_out.id = USRP2_FW_UPDATE_ID_WAT; + +  send_udp_pkt(USRP2_UDP_UPDATE_PORT, src, &update_data_out, sizeof(update_data_out)); +} diff --git a/firmware/microblaze/usrp2p/.gitignore b/firmware/microblaze/usrp2p/.gitignore new file mode 100644 index 000000000..18f715618 --- /dev/null +++ b/firmware/microblaze/usrp2p/.gitignore @@ -0,0 +1,9 @@ +/Makefile +/Makefile.in +/*.a +/*.bin +/*.dump +/*.ihx +/*.elf +/*.rom +/*.map diff --git a/firmware/microblaze/usrp2p/Makefile.am b/firmware/microblaze/usrp2p/Makefile.am new file mode 100644 index 000000000..40766b406 --- /dev/null +++ b/firmware/microblaze/usrp2p/Makefile.am @@ -0,0 +1,71 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +AM_CFLAGS = \ +	$(COMMON_CFLAGS) \ +	-DUSRP2P + +AM_LDFLAGS = \ +	$(COMMON_LFLAGS) \ +	-Wl,-defsym -Wl,_TEXT_START_ADDR=0x8050 \ +	-Wl,-defsym -Wl,_STACK_SIZE=3072 + +LDADD = libusrp2p.a + +#all of this here is to relocate the hardware vectors to somewhere normal. +RELOCATE_ARGS = \ +	--change-section-address .vectors.sw_exception+0x8000 \ +	--change-section-address .vectors.hw_exception+0x8000 \ +	--change-section-address .vectors.interrupt+0x8000 \ +	--change-section-address .vectors.reset+0x8000 + +#	$(MB_OBJCOPY) -O ihex $< $@ +# the below would work if objcopy weren't written by apes +#	$(MB_OBJCOPY) -O ihex -w --change-section-address .vectors*+0x8000 $< $@ +# using the below will throw away the interrupt vectors when they get relocated below 0x0000. +#	$(MB_OBJCOPY) -O ihex --change-addresses -0x8000 $< $@ + +######################################################################## +# USRP2P specific library and programs +######################################################################## +noinst_LIBRARIES = libusrp2p.a + +libusrp2p_a_SOURCES = \ +	$(COMMON_SRCS) \ +	spif.c \ +	spi_flash.c \ +	spi_flash_read.c \ +	bootloader_utils.c \ +	ethernet.c \ +	xilinx_s3_icap.c \ +  udp_fw_update.c + +noinst_PROGRAMS = \ +	usrp2p_txrx_uhd.elf \ +  usrp2p_blinkenlights.elf \ +  usrp2p_uart_flash_loader.elf + +usrp2p_txrx_uhd_elf_SOURCES = \ +	$(top_srcdir)/apps/txrx_uhd.c + +usrp2p_blinkenlights_elf_SOURCES = \ +  $(top_srcdir)/apps/blinkenlights.c + +usrp2p_uart_flash_loader_elf_SOURCES = \ +  $(top_srcdir)/apps/uart_flash_loader.c diff --git a/firmware/microblaze/usrp2p/bootconfig.h b/firmware/microblaze/usrp2p/bootconfig.h new file mode 100644 index 000000000..35c2726ed --- /dev/null +++ b/firmware/microblaze/usrp2p/bootconfig.h @@ -0,0 +1,61 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + *  + * This file is part of GNU Radio + *  + * GNU Radio 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 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_BOOTCONFIG_H +#define INCLUDED_BOOTCONFIG_H + +#include <stdbool.h> + +typedef struct { +  unsigned char	fpga_image_number; +  unsigned char	firmware_image_number; +} bootconfig_t; + +static inline bootconfig_t +make_bootconfig(unsigned char fpga_image_number, unsigned char firmware_image_number) +{ +  bootconfig_t r; +  r.fpga_image_number = fpga_image_number; +  r.firmware_image_number = firmware_image_number; +  return r; +} + +void bootconfig_init(void);	/* One time call to initialize */ + +/*! + * \return default boot configuration + */ +bootconfig_t bootconfig_get_default(void); + +/*! + * \brief Set the default boot configuration. + */ +bool bootconfig_set_default(bootconfig_t bc); + +/*! + * \brief attempt to boot the given fpga and software image. + * + * If successful, this routine does not return. + * If it fail for some reason, it returns. + */ +void bootconfig_boot(bootconfig_t bc); + +#endif /* INCLUDED_BOOTCONFIG_H */ diff --git a/firmware/microblaze/usrp2p/bootloader/.gitignore b/firmware/microblaze/usrp2p/bootloader/.gitignore new file mode 100644 index 000000000..17b0f82f3 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/.gitignore @@ -0,0 +1,11 @@ +/*.ihx +/*.rmi +/*_rom +/*.elf +/*.bin +/*.dump +/*.log +/*.rom +/*.map +/Makefile +/Makefile.in diff --git a/firmware/microblaze/usrp2p/bootloader/Makefile.am b/firmware/microblaze/usrp2p/bootloader/Makefile.am new file mode 100644 index 000000000..1fc5daf9c --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/Makefile.am @@ -0,0 +1,39 @@ +# +# Copyright 2007,2008,2009 Free Software Foundation, Inc. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +ROM_LINKER_SCRIPT = u2p2-rom.ld + +# loads into 8K boot ram located at 0x0000_0000 +AM_CFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)/usrp2p +AM_LDFLAGS = -Wl,-T,$(ROM_LINKER_SCRIPT) $(COMMON_LFLAGS) -Wl,-defsym -Wl,_STACK_SIZE=1024 + +EXTRA_DIST = $(ROM_LINKER_SCRIPT) + +LDADD = $(top_srcdir)/usrp2p/libusrp2p.a + +noinst_PROGRAMS = \ +	init_bootloader.elf + +init_bootloader_elf_SOURCES = init_bootloader.c + +.bin.rmi: +	$(top_srcdir)/bin/bin_to_ram_macro_init.py $< $@ + +_generated_from_elf += \ +	$(noinst_PROGRAMS:.elf=.rmi) diff --git a/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c b/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c new file mode 100644 index 000000000..9feff6ecd --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c @@ -0,0 +1,202 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This code is bootloader f/w for the slot 0 fpga image.  It's job is + * to figure out which fpga image should be loaded, and then to load + * that image from the SPI flash.  (FIXME handle retries, errors, + * etc.) + * + * If the center button is down during boot, it loads firwmare + * from 0:0 instead of its normal action. + */ + +#include <stdlib.h> +#include <hal_io.h> +#include <nonstdio.h> +#include <mdelay.h> +#include <quadradio/flashdir.h> +#include <xilinx_v5_icap.h> +#include <bootconfig.h> +#include <bootconfig_private.h> +#include <spi_flash.h> +#include <string.h> +#include <bootloader_utils.h> +#include <hal_interrupts.h> + +#define VERBOSE 1 + +#define	OUR_FPGA_IMAGE_NUMBER	0	// this code only runs in slot 0 + +void hal_uart_init(void); +void spif_init(void); +void i2c_init(void); +void bootconfig_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ +  // nop stub +} + +static int +flash_addr_of_fpga_slot(unsigned int fpga_slot) +{ +  const struct flashdir *fd = get_flashdir(); +  return fd->slot[fpga_slot + fd->fpga_slot0].start << spi_flash_log2_sector_size(); +} + + +/* + * If the first 256 bytes of the image contain the string of bytes, + * ff ff ff ff aa 99 55 66, we consider it a likely bitstream. + */ +static bool +looks_like_a_bitstream(unsigned int fpga_slot) +{ +  unsigned char buf[256]; +  static const unsigned char pattern[] = { +    0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 +  }; + +  // Read the first 256 bytes of the bitstream +  spi_flash_read(flash_addr_of_fpga_slot(fpga_slot), sizeof(buf), buf); + +  for (int i = 0; i <= sizeof(buf) - sizeof(pattern); i++) +    if (memcmp(pattern, &buf[i], sizeof(pattern)) == 0) +      return true; + +  return false; +} + +static bool +plausible_bootconfig(bootconfig_t bc) +{ +  // Are the fields in range? +  if (!validate_bootconfig(bc)) +    return false; + +  if (!looks_like_a_bitstream(map_fpga_image_number_to_fpga_slot(bc.fpga_image_number))) +    return false; + +  return true; +} + +// Attempt to boot the fpga image specified in next_boot +static void +initial_boot_attempt(eeprom_boot_info_t *ee) +{ +  if (ee->next_boot.fpga_image_number == OUR_FPGA_IMAGE_NUMBER){ +    load_firmware(); +    return; +  } + +  ee->nattempts = 1; +  _bc_write_eeprom_shadow(); + +  unsigned int target_slot = +    map_fpga_image_number_to_fpga_slot(ee->next_boot.fpga_image_number); +  int flash_addr = flash_addr_of_fpga_slot(target_slot); + +  putstr("fpga_bootloader: chaining to "); +  puthex4(ee->next_boot.fpga_image_number); +  putchar(':'); +  puthex4(ee->next_boot.firmware_image_number); +  newline(); +  mdelay(100); + +  while (1){ +    icap_reload_fpga(flash_addr); +  } +} + +int +main(int argc, char **argv) +{ +  hal_disable_ints();	// In case we got here via jmp 0x0 +  hal_uart_init(); +  i2c_init(); +  bootconfig_init();	// Must come after i2c_init. +  spif_init();		// Needed for get_flashdir. + +  sr_leds->leds =  0xAAAA; + +  putstr("\n\n>>> fpga_bootloader <<<\n"); + +  putstr("\nBOOTSTS "); +  int bootsts = icap_read_config_reg(rBOOTSTS); +  puthex32_nl(bootsts); +  putstr("STAT    "); +  int stat = icap_read_config_reg(rSTAT); +  puthex32_nl(stat); + +  bool fallback = +    ((bootsts & (BOOTSTS_VALID_0 | BOOTSTS_FALLBACK_0)) +     == (BOOTSTS_VALID_0 | BOOTSTS_FALLBACK_0)); + +  if (fallback){ +    puts("FALLBACK_0 is set"); +    // FIXME handle fallback condition. +  } + +  const struct flashdir *fd = get_flashdir(); +  if (fd == 0) +    abort(); + +  eeprom_boot_info_t *ee = _bc_get_eeprom_shadow(); + +  if (VERBOSE){ +    putstr("nattempts: "); +    puthex8_nl(ee->nattempts); +  } + +  mdelay(500);	// wait for low-pass on switches +  putstr("switches: "); puthex32_nl(readback->switches); + +  bool center_btn_down = (readback->switches & BTN_CENTER) != 0; +  if (center_btn_down){ +    putstr("Center button is down!\n"); +    // Force boot of image 0:0 +    ee->next_boot = make_bootconfig(0, 0); +  } + +  // if next_boot is valid, try it +  if (plausible_bootconfig(ee->next_boot)) +    initial_boot_attempt(ee);	// no return + +  // if default_boot is valid, try it +  if (plausible_bootconfig(ee->default_boot)){ +    ee->next_boot = ee->default_boot; +    initial_boot_attempt(ee);	// no return +  } + +  // If we're here, we're in trouble.  Try all of them... +  for (int i = 0; i < 4; i++){ +    bootconfig_t bc = make_bootconfig(i, 0); +    if (plausible_bootconfig(bc)){ +      ee->next_boot = bc; +      initial_boot_attempt(ee);	// no return +    } +  } + +  // FIXME, try to find something we can load +  puts("\n!!! Failed to find a valid FPGA bitstream!\n\n"); + +  return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c b/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c new file mode 100644 index 000000000..a2c32bf8e --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c @@ -0,0 +1,50 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <memory_map.h> +#include <nonstdio.h> +#include <stdlib.h> +#include <bootconfig.h> +#include <bootconfig_private.h> +#include <bootloader_utils.h> +#include <hal_interrupts.h> + + +void hal_uart_init(void); +void spif_init(void); +void i2c_init(void); +void bootconfig_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ +  // nop stub +} + +int +main(int argc, char **argv) +{ +  hal_disable_ints();	// In case we got here via jmp 0x0 +  hal_uart_init(); +  i2c_init(); +  bootconfig_init();	// Must come after i2c_init. +  spif_init();		// Needed for get_flashdir. + +  load_firmware(); +} diff --git a/firmware/microblaze/usrp2p/bootloader/icap_test.c b/firmware/microblaze/usrp2p/bootloader/icap_test.c new file mode 100644 index 000000000..5feb9d014 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/icap_test.c @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <hal_io.h> +#include <xilinx_s3_icap.h> +#include <nonstdio.h> + +void delay(uint32_t t) { +	while(t-- != 0) asm("NOP"); +} + + +int main(int argc, char *argv[]) { +	pic_init(); +	hal_uart_init(); +	puts("\nStarting delay...\n"); + +	output_regs->leds = 0xFF; +	delay(4000000); +	output_regs->leds = 0x00; +	delay(4000000); + +	puts("Rebooting FPGA to 0x00000000\n"); +	icap_reload_fpga((uint32_t)0x00000000); + +	return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c new file mode 100644 index 000000000..1d9d681d7 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c @@ -0,0 +1,114 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <memory_map.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <xilinx_s3_icap.h> +#include <spi_flash.h> +#include <spi_flash_private.h> +//#include <clocks.h> +#include <ihex.h> +#include <bootloader_utils.h> +#include <string.h> +#include <hal_uart.h> +#include <i2c.h> +#include "usrp2/fw_common.h" + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ +  // nop stub +} + +void load_ihex(void) { //simple IHEX parser to load proper records into RAM. loads program when it receives end of record. +	char buf[128]; //input data buffer +	uint8_t ihx[32]; //ihex data buffer + +	ihex_record_t ihex_record; +	ihex_record.data = ihx; + +	while(1) { +		gets(buf); + +		if(!ihex_parse(buf, &ihex_record)) { //RAM data record is valid +			if(ihex_record.addr >= RAM_BASE) { //it's expecting to see FULLY RELOCATED IHX RECORDS. every address referenced to 0x8000, including vectors. +				memcpy((void *) (ihex_record.addr), ihex_record.data, ihex_record.length); +				puts("OK"); +			} else if(ihex_record.type == 1) { //end of record +				puts("OK"); +				//load main firmware +				start_program(RAM_BASE); +				puts("ERROR: main image returned! Back in IHEX load mode."); +			} else puts("NOK"); //RAM loads do not support extended segment address records (04) -- upper 16 bits are always "0". +		} else puts("NOK"); +	} +} + +void delay(uint32_t t) { +	while(t-- != 0) asm("NOP"); +} + +int main(int argc, char *argv[]) { +  hal_disable_ints();	// In case we got here via jmp 0x0 +	output_regs->leds = 0xFF; +	delay(500000); +	output_regs->leds = 0x00; +	hal_uart_init(); +	spif_init(); +	i2c_init(); //for EEPROM +	puts("USRP2+ bootloader\n"); +	 +	bool production_image = find_safe_booted_flag(); +	set_safe_booted_flag(0); //haven't booted yet +	 +	if(BUTTON_PUSHED) { //see memory_map.h +		puts("Starting USRP2+ in safe mode."); +		if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { +				set_safe_booted_flag(1); //let the firmware know it's the safe image +				spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); +				start_program(RAM_BASE); +				puts("ERROR: return from main program! This should never happen!"); +				icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); +			} else { +				puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM."); +				load_ihex(); +			} +	} +	 +	if(!production_image) { +		puts("Checking for valid production FPGA image..."); +		if(is_valid_fpga_image(PROD_FPGA_IMAGE_LOCATION_ADDR)) { +			puts("Valid production FPGA image found. Attempting to boot."); +			set_safe_booted_flag(1); +			delay(30000); //so serial output can finish +			icap_reload_fpga(PROD_FPGA_IMAGE_LOCATION_ADDR); +		} +		puts("No valid production FPGA image found.\nAttempting to load production firmware..."); +	} +	if(is_valid_fw_image(PROD_FW_IMAGE_LOCATION_ADDR)) { +		puts("Valid production firmware found. Loading..."); +		spi_flash_read(PROD_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); +		start_program(RAM_BASE); +		puts("ERROR: Return from main program! This should never happen!"); +		//if this happens, though, the safest thing to do is reboot the whole FPGA and start over. +		icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); +		return 1; +	} +	puts("No valid production firmware found. Trying safe firmware..."); +	if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { +		spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE); +		start_program(RAM_BASE); +		puts("ERROR: return from main program! This should never happen!"); +		icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); +		return 1; +	} +	puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM."); +	load_ihex(); + +	return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c b/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c new file mode 100644 index 000000000..4ac4df454 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <hal_io.h> +#include <nonstdio.h> +#include <mdelay.h> +#include <gdbstub2.h> + +void hal_uart_init(void); +void spif_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ +  // nop stub +} + +int +main(int argc, char **argv) +{ +  hal_uart_init(); +  spif_init(); + +  sr_leds->leds =  0; +  mdelay(100); +  sr_leds->leds = ~0; +  mdelay(100); +  sr_leds->leds =  0; + +  puts("\n\n>>> stage1: serial_loader_burner <<<"); + +  gdbstub2_main_loop(); +} diff --git a/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c b/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c new file mode 100644 index 000000000..678e66cf7 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c @@ -0,0 +1,134 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <hal_io.h> +#include <nonstdio.h> +#include <mdelay.h> +#include <spi_flash.h> +#include <quadradio/flashdir.h> +#include <quadradio/simple_binary_format.h> +#include <stdlib.h> + + +void hal_uart_init(void); +void spif_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ +  // nop stub +} + +static void +error(int e) +{ +  putstr("ERR"); +  puthex8(e); +  newline(); +} + +static void +load(uint32_t flash_addr, uint32_t ram_addr, uint32_t size) +{ +  spi_flash_read(flash_addr, size, (void *) ram_addr); +} + +static bool +load_from_slot(const struct flashdir *fd, int fw_slot) +{ +    putstr("Loading f/w image "); +    putchar('0' + fw_slot); +    putstr("... "); + +    if (fw_slot >= fd->fw_nslots){ +      error(1); +      return false; +    } + +    int slot = fw_slot + fd->fw_slot0; +    if (fd->slot[slot].start == 0 || fd->slot[slot].start == 0xffff +	|| fd->slot[slot].len == 0 || fd->slot[slot].len == 0xffff){ +      error(2); +      return false; +    } +     +    uint32_t sbf_base = fd->slot[slot].start << spi_flash_log2_sector_size(); +    uint32_t sbf_len  = fd->slot[slot].len << spi_flash_log2_sector_size(); +    uint32_t sbf_offset = 0; + +    struct sbf_header sbf; +    spi_flash_read(sbf_base, sizeof(struct sbf_header), &sbf); +    if (sbf.magic != SBF_MAGIC || sbf.nsections > SBF_MAX_SECTIONS){ +      error(3); +      return false; +    } +    sbf_offset += sizeof(struct sbf_header); + +    unsigned int i; +    for (i = 0; i < sbf.nsections; i++){ +      if (sbf_offset + sbf.sec_desc[i].length > sbf_len){ +	error(4); +	return false; +      } +      load(sbf_offset + sbf_base, +	   sbf.sec_desc[i].target_addr, +	   sbf.sec_desc[i].length); +      sbf_offset += sbf.sec_desc[i].length; +    } +    putstr("Done!"); + +    typedef void (*fptr_t)(void); +    (*(fptr_t) sbf.entry)();		// almost certainly no return + +    return true; +} + +int +main(int argc, char **argv) +{ +  hal_uart_init(); +  spif_init(); + +  sr_leds->leds =  0; +  mdelay(100); +  sr_leds->leds = ~0; +  mdelay(100); +  sr_leds->leds =  0; + +  putstr("\n>>> spi_bootloader <<<\n"); + +  const struct flashdir *fd = get_flashdir(); +  if (fd == 0) +    abort(); + +  while(1){ +    int sw; +    int fw_slot; +     +    sw = readback->switches; +    fw_slot = sw & 0x7; + +    if (!load_from_slot(fd, fw_slot)){ +      if (fw_slot != 0){ +	putstr("Falling back to slot 0\n"); +	load_from_slot(fd, 0); +      } +    } +  } +} diff --git a/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld b/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld new file mode 100644 index 000000000..4c9eaa8e5 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld @@ -0,0 +1,190 @@ +/* + * Same as default, but with bss and stack moved to top 2K of main ram + * Copied from qr-rom.ld + */ + +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-microblaze", "", "") +/*SEARCH_DIR("/home/eb/build/Xilinx_EDK_GNU_10.1i/mb/release/lin/mb/microblaze-xilinx-elf/lib");*/ + + +ENTRY(_start) +_TEXT_START_ADDR = DEFINED(_TEXT_START_ADDR) ? _TEXT_START_ADDR : 0x50; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x0; +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x400; +_BSS_START_ADDR = DEFINED(_BSS_START_ADDR) ? _BSS_START_ADDR : 0xF800; +SECTIONS +{ +  .vectors.reset 0x0 : { KEEP (*(.vectors.reset)) } = 0 +  .vectors.sw_exception 0x8 : { KEEP (*(.vectors.sw_exception)) } = 0 +  .vectors.interrupt 0x10 : { KEEP (*(.vectors.interrupt)) } = 0 +  .vectors.debug_sw_break 0x18 : { KEEP (*(.vectors.debug_sw_break)) } = 0 +  .vectors.hw_exception 0x20 : { KEEP (*(.vectors.hw_exception)) } = 0 +  . = _TEXT_START_ADDR; +   _ftext  =  .; +  .text : { +    *(.text) +    *(.text.*) +    *(.gnu.linkonce.t.*) +  } +   _etext  =  .; +  .init : { KEEP (*(.init))	} =0 +  .fini : { KEEP (*(.fini))	} =0 +  PROVIDE (__CTOR_LIST__ = .); +  PROVIDE (___CTOR_LIST__ = .); +  .ctors   : +  { +    /* gcc uses crtbegin.o to find the start of +       the constructors, so we make sure it is +       first.  Because this is a wildcard, it +       doesn't matter if the user does not +       actually link against crtbegin.o; the +       linker won't look for a file to match a +       wildcard.  The wildcard also means that it +       doesn't matter which directory crtbegin.o +       is in.  */ +    KEEP (*crtbegin.o(.ctors)) +    /* We don't want to include the .ctor section from +       from the crtend.o file until after the sorted ctors. +       The .ctor section from the crtend file contains the +       end of ctors marker and it must be last */ +    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) +    KEEP (*(SORT(.ctors.*))) +    KEEP (*(.ctors)) +  } +  PROVIDE (__CTOR_END__ = .); +  PROVIDE (___CTOR_END__ = .); +  PROVIDE (__DTOR_LIST__ = .); +  PROVIDE (___DTOR_LIST__ = .); +   .dtors         : +  { +    KEEP (*crtbegin.o(.dtors)) +    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) +    KEEP (*(SORT(.dtors.*))) +    KEEP (*(.dtors)) +  } +  PROVIDE (__DTOR_END__ = .); +  PROVIDE (___DTOR_END__ = .); +   . = ALIGN(4); +    _frodata = . ; +  .rodata : { +    *(.rodata) +    *(.rodata.*) +    *(.gnu.linkonce.r.*) +    CONSTRUCTORS; /* Is this needed? */ +  } +   _erodata = .; +  /* Alignments by 8 to ensure that _SDA2_BASE_ on a word boundary */ +  /* Note that .sdata2 and .sbss2 must be contiguous */ +  . = ALIGN(8); +   _ssrw = .; +  .sdata2 : { +    *(.sdata2) +    *(.sdata2.*) +    *(.gnu.linkonce.s2.*) +  } +  . = ALIGN(4); +  .sbss2 : { +    PROVIDE (__sbss2_start = .); +    *(.sbss2) +    *(.sbss2.*) +    *(.gnu.linkonce.sb2.*) +    PROVIDE (__sbss2_end = .); +  } +  . = ALIGN(8); +   _essrw = .; +   _ssrw_size = _essrw - _ssrw; +   PROVIDE (_SDA2_BASE_ = _ssrw + (_ssrw_size / 2 )); +   . = ALIGN(4); +   _fdata = .; +  .data : { +    *(.data) +    *(.gnu.linkonce.d.*) +    CONSTRUCTORS; /* Is this needed? */ +  } +   _edata = . ; +   /* Added to handle pic code */ +  .got : { +    *(.got) +  } +  .got1 : { +    *(.got1) +  } +  .got2 : { +    *(.got2) +  } +  /* Added by Sathya to handle C++ exceptions */ +  .eh_frame : { +    *(.eh_frame) +  } +  .jcr : { +    *(.jcr) +  } +  .gcc_except_table : { +    *(.gcc_except_table) +  } +  /* Alignments by 8 to ensure that _SDA_BASE_ on a word boundary */ +  /* Note that .sdata and .sbss must be contiguous */ +  . = ALIGN(8); +   _ssro = .; +  .sdata : { +    *(.sdata) +    *(.sdata.*) +    *(.gnu.linkonce.s.*) +  } +  . = ALIGN(4); +  .sbss : { +    PROVIDE (__sbss_start = .); +    *(.sbss) +    *(.sbss.*) +    *(.gnu.linkonce.sb.*) +    PROVIDE (__sbss_end = .); +  } +  . = ALIGN(8); +   _essro = .; +   _ssro_size = _essro - _ssro; +  PROVIDE (_SDA_BASE_ = _ssro + (_ssro_size / 2 )); +   . = _BSS_START_ADDR; +   . = ALIGN(4); +   _fbss = .; +  .bss : { +    PROVIDE (__bss_start = .); +    *(.bss) +    *(.bss.*) +    *(.gnu.linkonce.b.*) +    *(COMMON) +    . = ALIGN(4); +    PROVIDE (__bss_end = .); +  } +   . = ALIGN(4); +  .heap : { +     _heap = .; +     _heap_start = .; +     . += _HEAP_SIZE; +     _heap_end = .; +  } +  _end = .; +   . = ALIGN(4); +   . = 0xFFF0; +  .stack : { +  /* +     _stack_end = .; +     . += _STACK_SIZE; +     . = ALIGN(8); +     _stack = .; +     _end = .; +   */ +   _stack_end = .; +   _stack = .; +  } +  .tdata : { +    *(.tdata) +    *(.tdata.*) +    *(.gnu.linkonce.td.*) +  } +  .tbss : { +    *(.tbss) +    *(.tbss.*) +    *(.gnu.linkonce.tb.*) +  } +} diff --git a/firmware/microblaze/usrp2p/bootloader_utils.c b/firmware/microblaze/usrp2p/bootloader_utils.c new file mode 100644 index 000000000..fadd225bb --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader_utils.c @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +//contains routines for loading programs from Flash. depends on Flash libraries. +//also contains routines for reading / writing EEPROM flags for the bootloader +#include <stdbool.h> +#include <string.h> +#include <bootloader_utils.h> +#include <spi_flash.h> + +int is_valid_fpga_image(uint32_t addr) { +	uint8_t imgbuf[64]; +	spi_flash_read(addr, 64, imgbuf); +	//we're just looking for leading 0xFF padding, followed by the sync bytes 0xAA 0x99 +	int i = 0; +	for(i; i<63; i++) { +		if(imgbuf[i] == 0xFF) continue; +		if(imgbuf[i] == 0xAA && imgbuf[i+1] == 0x99) return 1; +	} +	 +	return 0; +} + +int is_valid_fw_image(uint32_t addr) { +	static const uint8_t fwheader[] = {0xB0, 0x00, 0x00, 0x00, 0xB8, 0x08}; //just lookin for a jump to anywhere located at the reset vector +	uint8_t buf[12]; +	spi_flash_read(addr, 6, buf); +	return memcmp(buf, fwheader, 6) == 0; +} + +void start_program(uint32_t addr) +{ +	memcpy(0x00000000, addr+0x00000000, 36); //copy the whole vector table, with the reset vector, into boot RAM +	typedef void (*fptr_t)(void); +	(*(fptr_t) 0x00000000)();	// most likely no return +} diff --git a/firmware/microblaze/usrp2p/bootloader_utils.h b/firmware/microblaze/usrp2p/bootloader_utils.h new file mode 100644 index 000000000..f597c0113 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader_utils.h @@ -0,0 +1,22 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include <stdint.h> + +//we're working in bytes and byte addresses so we can run the same code with Flash chips of different sector sizes. +//it's really 1463736, but rounded up to 1.5MB +#define FPGA_IMAGE_SIZE_BYTES 1572864 +//instead of 32K, we write 31K because we're using the top 1K for stack space! +#define FW_IMAGE_SIZE_BYTES 31744 + +#define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000 +#define SAFE_FW_IMAGE_LOCATION_ADDR 0x003F0000 +#define PROD_FPGA_IMAGE_LOCATION_ADDR 0x00180000 +#define PROD_FW_IMAGE_LOCATION_ADDR 0x00300000 + +int is_valid_fpga_image(uint32_t addr); +int is_valid_fw_image(uint32_t addr); +void start_program(uint32_t addr); diff --git a/firmware/microblaze/usrp2p/eth_phy.h b/firmware/microblaze/usrp2p/eth_phy.h new file mode 100644 index 000000000..d233e96e8 --- /dev/null +++ b/firmware/microblaze/usrp2p/eth_phy.h @@ -0,0 +1,235 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* Much of this was extracted from the Linux e1000_hw.h file */ + +#ifndef INCLUDED_ETH_PHY_H +#define INCLUDED_ETH_PHY_H + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ + +#define PHY_CTRL         0x00 /* Control Register */ +#define PHY_STATUS       0x01 /* Status Regiser */ +#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */ + +/* PHY 1000 MII Register additions in ET1011C */ +#define PHY_INT_MASK     24 +#define PHY_INT_STATUS   25 +#define PHY_PHY_STATUS   26 +#define PHY_LED2         28 + +/* Bit definitions for some of the registers above */ + +/* PHY Control Register (PHY_CTRL) */ +#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */ +#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */ +#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN       0x0800  /* Power down */ +#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */ + +/* PHY Status Register (PHY_STATUS) */ +#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */ +#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register (PHY_AUTONEG_ADV) */ +#define NWAY_AR_SELECTOR_FIELD 0x0001   /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS    0x0020   /* 10T   Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS    0x0040   /* 10T   Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS  0x0080   /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS  0x0100   /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS     0x0200   /* 100T4 Capable */ +#define NWAY_AR_PAUSE          0x0400   /* Pause operation desired */ +#define NWAY_AR_ASM_DIR        0x0800   /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT   0x2000   /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE      0x8000   /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) (PHY_LP_ABILITY) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register (PHY_AUTONEG_EXP) */ +#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */ + +/* Next Page TX Register (PHY_NEXT_PAGE_TX) */ +#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define NPTX_TOGGLE         0x0800 /* Toggles between exchanges +                                    * of different NP +                                    */ +#define NPTX_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg +                                    * 0 = cannot comply with msg +                                    */ +#define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */ +#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow +                                    * 0 = sending last NP +                                    */ + +/* Link Partner Next Page Register (PHY_LP_NEXT_PAGE) */ +#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges +                                       * of different NP +                                       */ +#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg +                                       * 0 = cannot comply with msg +                                       */ +#define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */ +#define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */ +#define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow +                                        * 0 = sending last NP +                                        */ + +/* 1000BASE-T Control Register (PHY_1000T_CTRL) */ +#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */ +#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */ +                                        /* 0=DTE device */ +#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */ +                                        /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */ +                                        /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register (PHY_1000T_STATUS) */ +#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local TX is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */ +#define SR_1000T_REMOTE_RX_STATUS_SHIFT          12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT           13 +#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT    5 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_20            20 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_100           100 + +/* Extended Status Register (PHY_EXT_STATUS) */ +#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +#define PHY_TX_POLARITY_MASK   0x0100 /* register 10h bit 8 (polarity bit) */ +#define PHY_TX_NORMAL_POLARITY 0      /* register 10h bit 8 (normal polarity) */ + +#define AUTO_POLARITY_DISABLE  0x0010 /* register 11h bit 4 */ +                                      /* (0=enable, 1=disable) */ + +/* PHY Status Register (PHY_PHY_STATUS) */ +#define PHYSTAT_ASYMMETRIC   (1 << 0) +#define PHYSTAT_PAUSE        (1 << 1) +#define PHYSTAT_AUTONEG_EN   (1 << 2) +#define PHYSTAT_COLLISION    (1 << 3) +#define PHYSTAT_RXSTAT       (1 << 4) +#define PHYSTAT_TXSTAT       (1 << 5) +#define PHYSTAT_LINK         (1 << 6) +#define PHYSTAT_DUPLEX       (1 << 7) +#define PHYSTAT_SPEED_MASK   ((1 << 8) | (1 << 9)) +#define PHYSTAT_SPEED_1000   (1 << 9) +#define PHYSTAT_SPEED_100    (1 << 8) +#define PHYSTAT_SPEED_10     0 +#define PHYSTAT_POLARITY     (1 << 10) +#define PHYSTAT_MDIX         (1 << 11) +#define PHYSTAT_AUTONEG_STAT (1 << 12) +#define PHYSTAT_STANDBY      (1 << 13) + +/* Interrupt status, mask and clear regs (PHY_INT_{STATUS,MASK,CLEAR}) */ +#define PHY_INT_ENABLE         (1 << 0) +#define PHY_INT_DOWNSHIFT      (1 << 1) +#define PHY_INT_LINK_STATUS_CHANGE  (1 << 2) +#define PHY_INT_RX_STATUS_CHANGE (1 << 3) +#define PHY_INT_FIFO_ERROR     (1 << 4) +#define PHY_INT_ERR_CTR_FULL   (1 << 5) +#define PHY_INT_NEXT_PAGE_RX   (1 << 6) +#define PHY_INT_CRC_ERROR      (1 << 7) +#define PHY_INT_AUTONEG_STATUS_CHANGE (1 << 8) +#define PHY_INT_MDIO_SYNC_LOST (1 << 9) +#define PHY_INT_TDR_IP_PHONE   (1 << 10) + +/* PHY LED status register 2 (used for controlling link LED for activity light) */ +#define PHY_LED_TXRX_LSB           12 +#define PHY_LED_LINK_LSB           8 +#define PHY_LED_100_LSB            4 +#define PHY_LED_1000_LSB           0 + +#define LED_1000                   0 +#define LED_100_TX                 1 +#define LED_10                     2 +#define LED_1000_ON_100_BLINK      3 +#define LED_LINK                   4 +#define LED_TX                     5 +#define LED_RX                     6 +#define LED_ACTIVITY               7 +#define LED_FULLDUPLEX             8 +#define LED_COLLISION              9 +#define LED_LINK_ON_ACTIVITY_BLINK 10 +#define LED_LINK_ON_RX_BLINK       11 +#define LED_FULL_DUPLEX_ON_COLLISION_BLINK 12 +#define LED_BLINK                  13 +#define LED_ON                     14 +#define LED_OFF                    15 + + +#endif /* INCLUDED_ETH_PHY_H */ diff --git a/firmware/microblaze/usrp2p/ethernet.c b/firmware/microblaze/usrp2p/ethernet.c new file mode 100644 index 000000000..36d6a17ca --- /dev/null +++ b/firmware/microblaze/usrp2p/ethernet.c @@ -0,0 +1,399 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +//Changes for USRP2P: status registers different (ethernet.h) + +#include "ethernet.h" +#include "memory_map.h" +#include "eth_phy.h" +#include <eth_mac.h> +#include <eth_mac_regs.h> +#include <pic.h> +#include <hal_io.h> +#include <nonstdio.h> +#include <stdbool.h> +#include <i2c.h> +#include "usrp2/fw_common.h" + +#define VERBOSE 0 + +static ethernet_t ed_state; +static ethernet_link_changed_callback_t ed_callback = 0; + +void  +ethernet_register_link_changed_callback(ethernet_link_changed_callback_t new_callback) +{ +  ed_callback = new_callback; +} + + +static void +ed_set_mac_speed(int speed) +{ +  printf("Speed set to %d\n",speed); +  /* +  switch(speed){ +  case 10: +    eth_mac->speed = 1; +    break; +  case 100: +    eth_mac->speed = 2; +    break; +  case 1000: +    eth_mac->speed = 4; +    break; +  default: +    break; +  } +  */ +} + +static void +ed_link_up(int speed) +{ +  // putstr("ed_link_up: "); puthex16_nl(speed); + +  ed_set_mac_speed(speed); + +	//turn on link LED for USRP2P +	hal_set_leds(LED_RJ45, LED_RJ45); + + +  if (ed_callback)		// fire link changed callback +    (*ed_callback)(speed); +} + +static void +ed_link_down(void) +{ +  // putstr("ed_link_down\n"); + +	//turn off link LED for USRP2P +	hal_set_leds(0, LED_RJ45); + +  if (ed_callback)		// fire link changed callback +    (*ed_callback)(0); +} + + +static void +ed_link_speed_change(int speed) +{ +  ed_link_down(); +  ed_link_up(speed); +} + +static void +print_flow_control(int flow_control) +{ +  static const char *flow_control_msg[4] = { +    "NONE", "WE_TX", "WE_RX", "SYMMETRIC" +  }; +  putstr("ethernet flow control: "); +  puts(flow_control_msg[flow_control & 0x3]); +} + +static void +check_flow_control_resolution(void) +{ +  static const unsigned char table[16] = { +    // index = {local_asm, local_pause, partner_asm, partner_pause} +    FC_NONE,  FC_NONE,  FC_NONE,  FC_NONE, +    FC_NONE,  FC_SYMM,  FC_NONE,  FC_SYMM, +    FC_NONE,  FC_NONE,  FC_NONE,  FC_WE_TX, +    FC_NONE,  FC_SYMM,  FC_WE_RX, FC_SYMM +  }; + +  int us = eth_mac_miim_read(PHY_AUTONEG_ADV); +  int lp = eth_mac_miim_read(PHY_LP_ABILITY); +  int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3); +  ed_state.flow_control = table[index]; + +  if (1) +    print_flow_control(ed_state.flow_control); +} + +/* + * Read the PHY state register to determine link state and speed + */ +static void +ed_check_phy_state(void) +{ +  int phystat = eth_mac_miim_read(PHY_PHY_STATUS); +  eth_link_state_t new_state = LS_UNKNOWN; +  int new_speed = S_UNKNOWN; + +  if (VERBOSE){ +    putstr("PHYSTAT: "); +    puthex16_nl(phystat); +  } + +  if (phystat & PHYSTAT_LINK){		// link's up +    if (VERBOSE) +      puts("  LINK_GOOD"); + +    new_state = LS_UP; +    switch (phystat & PHYSTAT_SPEED_MASK){ +    case PHYSTAT_SPEED_10: +      new_speed = 10; +      break; +       +    case PHYSTAT_SPEED_100: +      new_speed = 100; +      break; +       +    case PHYSTAT_SPEED_1000: +      new_speed = 1000; +      break; + +    default: +      new_speed = S_UNKNOWN; +      break; +    } + +    check_flow_control_resolution(); +  } +  else {				// link's down +    if (VERBOSE) +      puts("  NOT LINK_GOOD"); +     +    new_state = LS_DOWN; +    new_speed = S_UNKNOWN; +  } + +  if (new_state != ed_state.link_state){ +    ed_state.link_state = new_state;		// remember new state +    if (new_state == LS_UP) +      ed_link_up(new_speed); +    else if (new_state == LS_DOWN) +      ed_link_down(); +  } +  else if (new_state == LS_UP && new_speed != ed_state.link_speed){ +    ed_state.link_speed = new_speed;		// remember new speed +    ed_link_speed_change(new_speed); +  } +} + +/* + * This is fired when the ethernet PHY state changes + */ +static void +eth_phy_irq_handler(unsigned irq) +{ +  ed_check_phy_state(); +  eth_mac_miim_read(PHY_INT_STATUS); +//  eth_mac_miim_write(PHY_INT_CLEAR, ~0);	// clear all ints +} + +void +ethernet_init(void) +{ +  eth_mac_init(ethernet_mac_addr()); + +  ed_state.link_state = LS_UNKNOWN; +  ed_state.link_speed = S_UNKNOWN; + +  // initialize MAC registers +  //  eth_mac->tx_hwmark = 0x1e; +  //eth_mac->tx_lwmark = 0x19; + +  //eth_mac->crc_chk_en = 1; +  //eth_mac->rx_max_length = 2048; + +  // configure PAUSE frame stuff +  //eth_mac->tx_pause_en = 1;		// pay attn to pause frames sent to us + +  //eth_mac->pause_quanta_set = 38;	// a bit more than 1 max frame 16kb/512 + fudge +  //eth_mac->pause_frame_send_en = 1;	// enable sending pause frames + + +  // setup PHY to interrupt on changes + +  unsigned mask = +    (PHY_INT_ENABLE       //master interrupt enable +     | PHY_INT_LINK_STATUS_CHANGE +     | PHY_INT_RX_STATUS_CHANGE +     ); + +  eth_mac_miim_read(PHY_INT_STATUS); //clear interrupts +  eth_mac_miim_write(PHY_INT_MASK, mask);	// enable the ones we want + +	//set the LED behavior to activity instead of link +	unsigned led = (LED_ACTIVITY << PHY_LED_LINK_LSB) | (LED_TX << PHY_LED_TXRX_LSB); +	eth_mac_miim_write(PHY_LED2, led); + +  pic_register_handler(IRQ_PHY, eth_phy_irq_handler); + +  // Advertise our flow control configuation. +  // +  // We and the link partner each specify two bits in the base page +  // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR. +  // The bits say what a device is "willing" to do, not what may actually +  // happen as a result of the negotiation.  There are 4 cases: +  // +  // PAUSE  ASM_DIR +  // +  //  0        0        I have no flow control capability. +  // +  //  1        0        I both assert and respond to flow control. +  // +  //  0        1        I assert flow control, but cannot respond.  That is, +  //                    I want to be able to send PAUSE frames, but will ignore any +  //		 	you send to me.  (This is our configuration.) +  // +  //  1        1        I can both assert and respond to flow control AND I am willing +  //                    to operate symmetrically OR asymmetrically in EITHER direction. +  //                    (We hope the link partner advertises this, otherwise we don't +  //			get what we want.) + +  int t = eth_mac_miim_read(PHY_AUTONEG_ADV); +  t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR); +  t |= NWAY_AR_ASM_DIR; + +  // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex +  t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS); + +  eth_mac_miim_write(PHY_AUTONEG_ADV, t); +  int r = eth_mac_miim_read(PHY_AUTONEG_ADV);  		// DEBUG, read back +  if (t != r){ +    printf("PHY_AUTONEG_ADV: wrote 0x%x, got 0x%x\n", t, r); +  } + +  // Restart autonegotation.   +  // We want to ensure that we're advertising our PAUSE capabilities. +  t = eth_mac_miim_read(PHY_CTRL); +  eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG); +} + +static bool  +unprogrammed(const void *t, size_t len) +{ +  int i; +  uint8_t *p = (uint8_t *)t; +  bool all_zeros = true; +  bool all_ones =  true; +  for (i = 0; i < len; i++){ +    all_zeros &= p[i] == 0x00; +    all_ones  &= p[i] == 0xff; +  } +  return all_ones | all_zeros; +} + +//////////////////// MAC Addr Stuff /////////////////////// +/* +static int8_t src_mac_addr_initialized = false; +static eth_mac_addr_t src_mac_addr = {{ +    0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff +  }}; + +const eth_mac_addr_t * +ethernet_mac_addr(void) +{ +  if (!src_mac_addr_initialized){    // fetch from eeprom +    src_mac_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_mac_addr; +     +    eth_mac_addr_t tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_mac_addr = tmp; +  } + +  return &src_mac_addr; +} + +bool +ethernet_set_mac_addr(const eth_mac_addr_t *t) +{ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); +  if (ok){ +    src_mac_addr = *t; +    src_mac_addr_initialized = true; +    //eth_mac_set_addr(t); //this breaks the link +  } + +  return ok; +} + +//////////////////// IP Addr Stuff /////////////////////// + +static int8_t src_ip_addr_initialized = false; +static struct ip_addr src_ip_addr = { +    (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + + +const struct ip_addr *get_ip_addr(void) +{ +  if (!src_ip_addr_initialized){    // fetch from eeprom +    src_ip_addr_initialized = true; + +    // if we're simulating, don't read the EEPROM model, it's REALLY slow +    if (hwconfig_simulation_p()) +      return &src_ip_addr; +     +    struct ip_addr tmp; +    bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp)); +    if (!ok || unprogrammed(&tmp, sizeof(tmp))){ +      // use the default +    } +    else +      src_ip_addr = tmp; +  } + +  return &src_ip_addr; +} + +bool set_ip_addr(const struct ip_addr *t){ +  bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); +  if (ok){ +    src_ip_addr = *t; +    src_ip_addr_initialized = true; +  } + +  return ok; +} +*/ +int +ethernet_check_errors(void) +{ +  // these registers are reset when read +   +  int	r = 0; +  /* +  if (eth_mac_read_rmon(0x05) != 0) +    r |= RME_RX_CRC; +  if (eth_mac_read_rmon(0x06) != 0) +    r |= RME_RX_FIFO_FULL; +  if (eth_mac_read_rmon(0x07) != 0) +    r |= RME_RX_2SHORT_2LONG; +   +  if (eth_mac_read_rmon(0x25) != 0) +    r |= RME_TX_JAM_DROP; +  if (eth_mac_read_rmon(0x26) != 0) +    r |= RME_TX_FIFO_UNDER; +  if (eth_mac_read_rmon(0x27) != 0) +    r |= RME_TX_FIFO_OVER; +  */ +  return r; +} diff --git a/firmware/microblaze/usrp2p/memory_map.h b/firmware/microblaze/usrp2p/memory_map.h new file mode 100644 index 000000000..3b2dc0057 --- /dev/null +++ b/firmware/microblaze/usrp2p/memory_map.h @@ -0,0 +1,847 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* Overall Memory Map + *   0000-FFFF  64K    RAM space + * + *   0000-1FFF  8K     Boot RAM + *   2000-5FFF  16K    Buffer pool + *   6000-7FFF  8K     Peripherals + *   8000-FFFF  32K    Main System RAM + + +From u2plus_core.v: +wb_1master #(.decode_w(8), +.s0_addr(8'b0000_0000),.s0_mask(8'b1110_0000),  // 0-8K, Boot RAM +.s1_addr(8'b0100_0000),.s1_mask(8'b1100_0000),  // 16K-32K, Buffer Pool +.s2_addr(8'b0011_0000),.s2_mask(8'b1111_1111),  // SPI 0x3000 +.s3_addr(8'b0011_0001),.s3_mask(8'b1111_1111),  // I2C 0x3100 +.s4_addr(8'b0011_0010),.s4_mask(8'b1111_1111),  // GPIO 0x3200 +.s5_addr(8'b0011_0011),.s5_mask(8'b1111_1111),  // Readback 0x3300 +.s6_addr(8'b0011_0100),.s6_mask(8'b1111_1111),  // Ethernet MAC 0x3400 +.s7_addr(8'b0010_0000),.s7_mask(8'b1111_0000),  // 8-12K, Settings Bus (only uses 1K) 0x2000-0x2FFF +.s8_addr(8'b0011_0101),.s8_mask(8'b1111_1111),  // PIC 0x3500 +.s9_addr(8'b0011_0110),.s9_mask(8'b1111_1111),  // Unused 0x3600 +.sa_addr(8'b0011_0111),.sa_mask(8'b1111_1111),  // UART 0x3700 +.sb_addr(8'b0011_1000),.sb_mask(8'b1111_1111),  // ATR 0x3800 +.sc_addr(8'b0011_1001),.sc_mask(8'b1111_1111),  // Unused 0x3900 +.sd_addr(8'b0011_1010),.sd_mask(8'b1111_1111),  // ICAP 0x3A00 +.se_addr(8'b0011_1011),.se_mask(8'b1111_1111),  // SPI Flash 0x3B00 +.sf_addr(8'b1000_0000),.sf_mask(8'b1000_0000),  // 32-64K, Main RAM 0x8000-0xFFFF +               .dw(dw),.aw(aw),.sw(sw)) wb_1master + + */ + + +#ifndef INCLUDED_MEMORY_MAP_H +#define INCLUDED_MEMORY_MAP_H + +#include <stdint.h> + + +#define MASTER_CLK_RATE        100000000		// 100 MHz + + +//////////////////////////////////////////////////////////////// +// +//         Memory map for embedded wishbone bus +// +//////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////// +// Boot RAM, Slave 0 + +#define BOOTRAM_BASE 0x0000 + + +//////////////////////////////////////////////////////////////// +// Buffer Pool RAM, Slave 1 +// +// The buffers themselves are located in Slave 1, Buffer Pool RAM. +// The status registers are in Slave 5, Buffer Pool Status. +// The control register is in Slave 7, Settings Bus. + +#define BUFFER_POOL_RAM_BASE 0x4000 + +#define	NBUFFERS                8 +#define BP_NLINES	   0x0200	// number of 32-bit lines in a buffer +#define BP_LAST_LINE	(BP_NLINES - 1)	// last line in a buffer + +#define buffer_pool_ram \ +  ((uint32_t *) BUFFER_POOL_RAM_BASE) + +#define buffer_ram(n) (&buffer_pool_ram[(n) * BP_NLINES]) + + +///////////////////////////////////////////////////// +// SPI Core, Slave 2.  See core docs for more info +#define SPI_BASE 0x3000   // Base address (16-bit) is base peripheral addr + +typedef struct { +  volatile uint32_t	txrx0; +  volatile uint32_t	txrx1; +  volatile uint32_t	txrx2; +  volatile uint32_t	txrx3; +  volatile uint32_t	ctrl; +  volatile uint32_t	div; +  volatile uint32_t	ss; +} spi_regs_t; + +#define spi_regs ((spi_regs_t *) SPI_BASE) + + +// Masks for controlling different peripherals +#define SPI_SS_AD9510    1 +#define SPI_SS_AD9777    2 +#define SPI_SS_RX_DAC    4 +#define SPI_SS_RX_ADC    8 +#define SPI_SS_RX_DB    16 +#define SPI_SS_TX_DAC   32 +#define SPI_SS_TX_ADC   64 +#define SPI_SS_TX_DB   128 +#define SPI_SS_ADS62P44 256 + +// Masks for different parts of CTRL reg +#define SPI_CTRL_ASS      (1<<13) +#define SPI_CTRL_IE       (1<<12) +#define SPI_CTRL_LSB      (1<<11) +#define SPI_CTRL_TXNEG    (1<<10) +#define SPI_CTRL_RXNEG    (1<< 9) +#define SPI_CTRL_GO_BSY   (1<< 8) +#define SPI_CTRL_CHAR_LEN_MASK 0x7F + +//////////////////////////////////////////////// +// I2C, Slave 3 +// See Wishbone I2C-Master Core Specification. + +#define I2C_BASE 0x3100 + +typedef struct { +  volatile uint32_t  prescaler_lo;	// r/w +  volatile uint32_t  prescaler_hi;	// r/w +  volatile uint32_t  ctrl;		// r/w +  volatile uint32_t  data;		// wr = transmit reg; rd = receive reg +  volatile uint32_t  cmd_status;	// wr = command reg;  rd = status reg +} i2c_regs_t; + +#define i2c_regs ((i2c_regs_t *) I2C_BASE) + +#define	I2C_CTRL_EN	(1 << 7)	// core enable +#define	I2C_CTRL_IE	(1 << 6)	// interrupt enable + +// +// STA, STO, RD, WR, and IACK bits are cleared automatically +// +#define	I2C_CMD_START	(1 << 7)	// generate (repeated) start condition +#define I2C_CMD_STOP	(1 << 6)	// generate stop condition +#define	I2C_CMD_RD	(1 << 5)	// read from slave +#define I2C_CMD_WR	(1 << 4)	// write to slave +#define	I2C_CMD_NACK	(1 << 3)	// when a rcvr, send ACK (ACK=0) or NACK (ACK=1) +#define I2C_CMD_RSVD_2	(1 << 2)	// reserved +#define	I2C_CMD_RSVD_1	(1 << 1)	// reserved +#define I2C_CMD_IACK	(1 << 0)	// set to clear pending interrupt + +#define I2C_ST_RXACK	(1 << 7)	// Received acknowledgement from slave (1 = NAK, 0 = ACK) +#define	I2C_ST_BUSY	(1 << 6)	// 1 after START signal detected; 0 after STOP signal detected +#define	I2C_ST_AL	(1 << 5)	// Arbitration lost.  1 when core lost arbitration +#define	I2C_ST_RSVD_4	(1 << 4)	// reserved +#define	I2C_ST_RSVD_3	(1 << 3)	// reserved +#define	I2C_ST_RSVD_2	(1 << 2)	// reserved +#define I2C_ST_TIP	(1 << 1)	// Transfer-in-progress +#define	I2C_ST_IP	(1 << 0)	// Interrupt pending + + +//////////////////////////////////////////////// +// GPIO, Slave 4 +// +// These go to the daughterboard i/o pins + +#define GPIO_BASE 0x3200 + +typedef struct { +  volatile uint32_t	io;	  // tx data in high 16, rx in low 16 +  volatile uint32_t     ddr;      // 32 bits, 1 means output. tx in high 16, rx in low 16 +  volatile uint32_t	tx_sel;   // 16 2-bit fields select which source goes to TX DB +  volatile uint32_t	rx_sel;   // 16 2-bit fields select which source goes to RX DB +} gpio_regs_t; + +// each 2-bit sel field is layed out this way +#define GPIO_SEL_SW	   0 // if pin is an output, set by software in the io reg +#define	GPIO_SEL_ATR	   1 // if pin is an output, set by ATR logic +#define	GPIO_SEL_DEBUG_0   2 // if pin is an output, debug lines from FPGA fabric +#define	GPIO_SEL_DEBUG_1   3 // if pin is an output, debug lines from FPGA fabric + +#define gpio_base ((gpio_regs_t *) GPIO_BASE) + +/////////////////////////////////////////////////// +// Buffer Pool Status, Slave 5 +// +// The buffers themselves are located in Slave 1, Buffer Pool RAM. +// The status registers are in Slave 5, Buffer Pool Status. +// The control register is in Slave 7, Settings Bus. + +#define BUFFER_POOL_STATUS_BASE 0x3300 + +typedef struct { +  volatile uint32_t last_line[NBUFFERS]; // last line xfer'd in buffer +  volatile uint32_t status;	         // error and done flags +  volatile uint32_t hw_config;	         // see below +  volatile uint32_t dummy[3]; +  volatile uint32_t irqs; +  volatile uint32_t pri_enc_bp_status; +  volatile uint32_t cycle_count; +} buffer_pool_status_t; + +#define buffer_pool_status ((buffer_pool_status_t *) BUFFER_POOL_STATUS_BASE) + +#define BUTTON_PUSHED ((buffer_pool_status->irqs & PIC_BUTTON) ? 0 : 1) + +/* + * Buffer n's xfer is done. + * Clear this bit by issuing bp_clear_buf(n) + */ +#define BPS_DONE(n)     (0x00000001 << (n)) +#define BPS_DONE_0	BPS_DONE(0) +#define BPS_DONE_1	BPS_DONE(1) +#define BPS_DONE_2	BPS_DONE(2) +#define BPS_DONE_3	BPS_DONE(3) +#define BPS_DONE_4	BPS_DONE(4) +#define BPS_DONE_5	BPS_DONE(5) +#define BPS_DONE_6	BPS_DONE(6) +#define BPS_DONE_7	BPS_DONE(7) + +/* + * Buffer n's xfer had an error. + * Clear this bit by issuing bp_clear_buf(n) + */ +#define BPS_ERROR(n)	(0x00000100 << (n)) +#define BPS_ERROR_0	BPS_ERROR(0) +#define BPS_ERROR_1	BPS_ERROR(1) +#define BPS_ERROR_2	BPS_ERROR(2) +#define BPS_ERROR_3	BPS_ERROR(3) +#define BPS_ERROR_4	BPS_ERROR(4) +#define BPS_ERROR_5	BPS_ERROR(5) +#define BPS_ERROR_6	BPS_ERROR(6) +#define BPS_ERROR_7	BPS_ERROR(7) + +/* + * Buffer n is idle.  A buffer is idle if it's not + * DONE, ERROR, or processing a transaction.  If it's + * IDLE, it's safe to start a new transaction. + * + * Clear this bit by starting a xfer with + * bp_send_from_buf or bp_receive_to_buf. + */ +#define BPS_IDLE(n)     (0x00010000 << (n)) +#define BPS_IDLE_0	BPS_IDLE(0) +#define BPS_IDLE_1	BPS_IDLE(1) +#define BPS_IDLE_2	BPS_IDLE(2) +#define BPS_IDLE_3	BPS_IDLE(3) +#define BPS_IDLE_4	BPS_IDLE(4) +#define BPS_IDLE_5	BPS_IDLE(5) +#define BPS_IDLE_6	BPS_IDLE(6) +#define BPS_IDLE_7	BPS_IDLE(7) + +/* + * Buffer n has a "slow path" packet in it. + * This bit is orthogonal to the bits above and indicates that + * the FPGA ethernet rx protocol engine has identified this packet + * as one requiring firmware intervention. + */ +#define BPS_SLOWPATH(n) (0x01000000 << (n)) +#define BPS_SLOWPATH_0	BPS_SLOWPATH(0) +#define BPS_SLOWPATH_1	BPS_SLOWPATH(1) +#define BPS_SLOWPATH_2	BPS_SLOWPATH(2) +#define BPS_SLOWPATH_3	BPS_SLOWPATH(3) +#define BPS_SLOWPATH_4	BPS_SLOWPATH(4) +#define BPS_SLOWPATH_5	BPS_SLOWPATH(5) +#define BPS_SLOWPATH_6	BPS_SLOWPATH(6) +#define BPS_SLOWPATH_7	BPS_SLOWPATH(7) + + +#define BPS_DONE_ALL	  0x000000ff	// mask of all dones +#define BPS_ERROR_ALL	  0x0000ff00	// mask of all errors +#define BPS_IDLE_ALL      0x00ff0000	// mask of all idles +#define BPS_SLOWPATH_ALL  0xff000000	// mask of all slowpaths + +// The hw_config register + +#define	HWC_SIMULATION		0x80000000 +#define	HWC_WB_CLK_DIV_MASK	0x0000000f + +/*! + * \brief return non-zero if we're running under the simulator + */ +inline static int +hwconfig_simulation_p(void) +{ +  return buffer_pool_status->hw_config & HWC_SIMULATION; +} + +/*! + * \brief Return Wishbone Clock divisor. + * The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor. + */ +inline static int +hwconfig_wishbone_divisor(void) +{ +  return buffer_pool_status->hw_config & HWC_WB_CLK_DIV_MASK; +} + +/////////////////////////////////////////////////// +// Ethernet Core, Slave 6 + +#define ETH_BASE 0x3400 + +#include "eth_mac_regs.h" + +#define eth_mac ((eth_mac_regs_t *) ETH_BASE) + +//////////////////////////////////////////////////// +// Settings Bus, Slave #7, Not Byte Addressable! +// +// Output-only from processor point-of-view. +// 1KB of address space (== 256 32-bit write-only regs) + + +#define MISC_OUTPUT_BASE        0x2000 +#define	TX_PROTOCOL_ENGINE_BASE 0x2080 +#define	RX_PROTOCOL_ENGINE_BASE 0x20C0 +#define BUFFER_POOL_CTRL_BASE   0x2100 +#define LAST_SETTING_REG        0x23FC	// last valid setting register + +#define SR_MISC 0 +#define SR_TX_PROT_ENG 32 +#define SR_RX_PROT_ENG 48 +#define SR_BUFFER_POOL_CTRL 64 +#define SR_UDP_SM 96 +#define SR_TX_DSP 208 +#define SR_TX_CTRL 224 +#define SR_RX_DSP 160 +#define SR_RX_CTRL 176 +#define SR_TIME64 192 +#define SR_SIMTIMER 198 +#define SR_LAST 255 + +#define	_SR_ADDR(sr)	(MISC_OUTPUT_BASE + (sr) * sizeof(uint32_t)) + +// --- buffer pool control regs --- + +typedef struct { +  volatile uint32_t ctrl; +} buffer_pool_ctrl_t; + +// buffer pool ports + +#define	PORT_SERDES	0	// serial/deserializer +#define	PORT_DSP	1	// DSP tx or rx pipeline +#define	PORT_ETH	2	// ethernet tx or rx +#define	PORT_RAM	3	// RAM tx or rx + +// the buffer pool ctrl register fields + +#define BPC_BUFFER(n) (((n) & 0xf) << 28) +#define   BPC_BUFFER_MASK      BPC_BUFFER(~0) +#define   BPC_BUFFER_0	       BPC_BUFFER(0) +#define   BPC_BUFFER_1	       BPC_BUFFER(1) +#define   BPC_BUFFER_2	       BPC_BUFFER(2) +#define   BPC_BUFFER_3	       BPC_BUFFER(3) +#define   BPC_BUFFER_4	       BPC_BUFFER(4) +#define   BPC_BUFFER_5	       BPC_BUFFER(5) +#define   BPC_BUFFER_6	       BPC_BUFFER(6) +#define   BPC_BUFFER_7	       BPC_BUFFER(7) +#define	  BPC_BUFFER_NIL       BPC_BUFFER(0x8)	// disable + +#define BPC_PORT(n) (((n) & 0x7) << 25) +#define   BPC_PORT_MASK        BPC_PORT(~0) +#define   BPC_PORT_SERDES      BPC_PORT(PORT_SERDES) +#define   BPC_PORT_DSP	       BPC_PORT(PORT_DSP) +#define   BPC_PORT_ETH         BPC_PORT(PORT_ETH) +#define   BPC_PORT_RAM         BPC_PORT(PORT_RAM) +#define   BPC_PORT_NIL	       BPC_PORT(0x4)   	// disable + +#define	BPC_CLR	       	       (1 << 24)  // mutually excl commands +#define	BPC_READ	       (1 << 23) +#define BPC_WRITE              (1 << 22) + +#define BPC_STEP(step) (((step) & 0xf) << 18) +#define   BPC_STEP_MASK	       BPC_STEP(~0) +#define BPC_LAST_LINE(line) (((line) & 0x1ff) << 9) +#define   BPC_LAST_LINE_MASK   BPC_LAST_LINE(~0) +#define BPC_FIRST_LINE(line) (((line) & 0x1ff) << 0) +#define   BPC_FIRST_LINE_MASK  BPC_FIRST_LINE(~0) + +#define buffer_pool_ctrl ((buffer_pool_ctrl_t *) BUFFER_POOL_CTRL_BASE) + +// --- misc outputs --- + +typedef struct { +  volatile uint32_t	clk_ctrl; +  volatile uint32_t	serdes_ctrl; +  volatile uint32_t	adc_ctrl; +  volatile uint32_t	leds; +  volatile uint32_t	phy_ctrl;	// LSB is reset line to eth phy +  volatile uint32_t	debug_mux_ctrl; +  volatile uint32_t     ram_page;       // FIXME should go somewhere else... +  volatile uint32_t     flush_icache;   // Flush the icache +  volatile uint32_t     led_src;        // HW or SW control for LEDs +} output_regs_t; + +#define CLK_RESET  (1<<4) +#define CLK_ENABLE (1<<3) | (1<<2) +#define CLK_SEL    (1<<1) | (1<<0) + +#define SERDES_ENABLE 8 +#define SERDES_PRBSEN 4 +#define SERDES_LOOPEN 2 +#define SERDES_RXEN   1 + +#define	ADC_CTRL_ON	0x0F +#define	ADC_CTRL_OFF	0x00 + +// crazy order that matches the labels on the case + +#define	LED_A		(1 << 2) +#define	LED_B		(1 << 0) +#define	LED_E		(1 << 3) +#define	LED_D		(1 << 1) +#define	LED_C		(1 << 4) +//      LED_F		// controlled by CPLD +#define	LED_RJ45	(1 << 5) + +#define output_regs ((output_regs_t *) MISC_OUTPUT_BASE) + +// --- udp tx regs --- + +typedef struct { +  // Bits 19:16 are control info; bits 15:0 are data (see below) +  // First two words are unused. +  volatile uint32_t _nope[2]; +  //--- ethernet header - 14 bytes--- +  volatile struct{ +    uint32_t mac_dst_0_1; //word 2 +    uint32_t mac_dst_2_3; +    uint32_t mac_dst_4_5; +    uint32_t mac_src_0_1; +    uint32_t mac_src_2_3; +    uint32_t mac_src_4_5; +    uint32_t ether_type; //word 8 +  } eth_hdr; +  //--- ip header - 20 bytes --- +  volatile struct{ +    uint32_t ver_ihl_tos; //word 9 +    uint32_t total_length; +    uint32_t identification; +    uint32_t flags_frag_off; +    uint32_t ttl_proto; +    uint32_t checksum; +    uint32_t src_addr_high; +    uint32_t src_addr_low; +    uint32_t dst_addr_high; +    uint32_t dst_addr_low; //word 18 +  } ip_hdr; +  //--- udp header - 8 bytes --- +  volatile struct{ +    uint32_t src_port; //word 19 +    uint32_t dst_port; +    uint32_t length; +    uint32_t checksum; //word 22 +  } udp_hdr; +  volatile uint32_t _pad[32-23]; +} sr_udp_sm_t; + +// control bits (all expect UDP_SM_LAST_WORD are mutually exclusive) + +// This is the last word of the header +#define	UDP_SM_LAST_WORD		(1 << 19) + +// Insert IP header checksum here.  Data is the xor of 16'hFFFF and +// the values written into regs 9-13 and 15-18. +#define	UDP_SM_INS_IP_HDR_CHKSUM	(1 << 18) + +// Insert IP Length here (data ignored) +#define	UDP_SM_INS_IP_LEN		(1 << 17) + +// Insert UDP Length here (data ignore) +#define	UDP_SM_INS_UDP_LEN		(1 << 16) + +#define sr_udp_sm ((sr_udp_sm_t *) _SR_ADDR(SR_UDP_SM)) + +// --- dsp tx regs --- + +#define MIN_CIC_INTERP	1 +#define	MAX_CIC_INTERP  128 + +typedef struct { +  volatile uint32_t     num_chan; +  volatile uint32_t     clear_state;	// clears out state machine, fifos, +  volatile uint32_t     report_sid; +  volatile uint32_t     policy; +  volatile uint32_t     cyc_per_up; +  volatile uint32_t     packets_per_up; +} sr_tx_ctrl_t; + +#define sr_tx_ctrl ((sr_tx_ctrl_t *) _SR_ADDR(SR_TX_CTRL)) + +typedef struct { +  volatile int32_t	freq; +  volatile uint32_t	scale_iq;	// {scale_i,scale_q} +  volatile uint32_t     interp_rate; +  volatile uint32_t     _padding0;      // padding for the tx_mux +                                        //   NOT freq, scale, interp +  /*! +   * \brief output mux configuration. +   * +   * <pre> +   *     3                   2                   1                        +   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   *  +-------------------------------+-------+-------+-------+-------+ +   *  |                                               | DAC1  |  DAC0 | +   *  +-------------------------------+-------+-------+-------+-------+ +   *  +   *  There are N DUCs (1 now) with complex inputs and outputs. +   *  There are two DACs. +   *  +   *  Each 4-bit DACx field specifies the source for the DAC +   *  Each subfield is coded like this:  +   *  +   *     3 2 1 0 +   *    +-------+ +   *    |   N   | +   *    +-------+ +   *  +   *  N specifies which DUC output is connected to this DAC. +   *  +   *   N   which interp output +   *  ---  ------------------- +   *   0   DUC 0 I +   *   1   DUC 0 Q +   *   2   DUC 1 I +   *   3   DUC 1 Q +   *   F   All Zeros +   *    +   * The default value is 0x10 +   * </pre> +   */ +  volatile uint32_t	tx_mux; + +} dsp_tx_regs_t; +   +#define dsp_tx_regs ((dsp_tx_regs_t *) _SR_ADDR(SR_TX_DSP)) + +// --- VITA RX CTRL regs --- +typedef struct { +  // The following 3 are logically a single command register. +  // They are clocked into the underlying fifo when time_ticks is written. +  volatile uint32_t	cmd;		// {now, chain, num_samples(30) +  volatile uint32_t	time_secs; +  volatile uint32_t	time_ticks; + +  volatile uint32_t	clear_overrun;	// write anything to clear overrun +  volatile uint32_t	vrt_header;	// word 0 of packet.  FPGA fills in packet counter +  volatile uint32_t	vrt_stream_id;	// word 1 of packet.  +  volatile uint32_t	vrt_trailer; +  volatile uint32_t	nsamples_per_pkt; +  volatile uint32_t     nchannels;      // 1 in basic case, up to 4 for vector sources +  volatile uint32_t     pad[7];         // Make each structure 16 elements long +} sr_rx_ctrl_t; + +#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL)) + +// --- dsp rx regs --- +#define	MIN_CIC_DECIM	1 +#define	MAX_CIC_DECIM   128 + +typedef struct { +  volatile int32_t	freq; +  volatile uint32_t	scale_iq;	// {scale_i,scale_q} +  volatile uint32_t     decim_rate; +  volatile uint32_t     dcoffset_i;     // Bit 31 high sets fixed offset mode, using lower 14 bits, +                                        // otherwise it is automatic  +  volatile uint32_t     dcoffset_q;     // Bit 31 high sets fixed offset mode, using lower 14 bits + +  /*! +   * \brief input mux configuration. +   * +   * This determines which ADC (or constant zero) is connected to  +   * each DDC input.  There are N DDCs (1 now).  Each has two inputs. +   * +   * <pre> +   * Mux value: +   * +   *    3                   2                   1                        +   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * |                                                       |Q0 |I0 | +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * +   * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) +   * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero) +   * +   * The default value is 0x4 +   * </pre> +   */ +  volatile uint32_t     rx_mux;        // called adc_mux in dsp_core_rx.v + +  /*! +   * \brief Streaming GPIO configuration +   * +   * This determines whether the LSBs of I and Q samples come from the DSP +   * pipeline or from the io_rx GPIO pins.  To stream GPIO, one must first +   * set the GPIO data direction register to have io_rx[15] and/or io_rx[14] +   * configured as inputs.  The GPIO pins will be sampled at the time the +   * remainder of the DSP sample is strobed into the RX sample FIFO.  There +   * will be a decimation-dependent fixed time offset between the GPIO +   * sample stream and the associated RF samples. +   * +   *    3                   2                   1                        +   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * |                           MBZ                             |Q|I| +   * +-------+-------+-------+-------+-------+-------+-------+-------+ +   * +   * I         0=LSB comes from DSP pipeline (default) +   *           1=LSB comes from io_rx[15] +   *  +   * Q         0=LSB comes from DSP pipeline (default) +   *           1=LSB comes from io_rx[14] +   */ +  volatile uint32_t gpio_stream_enable; + +} dsp_rx_regs_t; +   +#define dsp_rx_regs ((dsp_rx_regs_t *) _SR_ADDR(SR_RX_DSP)) + +// ---------------------------------------------------------------- +// VITA49 64 bit time (write only) +  /*! +   * \brief Time 64 flags +   * +   * <pre> +   * +   *    3                   2                   1                        +   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +   * +-----------------------------------------------------------+-+-+ +   * |                                                           |S|P| +   * +-----------------------------------------------------------+-+-+ +   * +   * P - PPS edge selection (0=negedge, 1=posedge, default=0) +   * S - Source (0=sma, 1=mimo, 0=default) +   * +   * </pre> +   */ +typedef struct { +  volatile uint32_t	secs;	// value to set absolute secs to on next PPS +  volatile uint32_t	ticks;	// value to set absolute ticks to on next PPS +  volatile uint32_t flags;  // flags - see chart above +  volatile uint32_t imm;    // set immediate (0=latch on next pps, 1=latch immediate, default=0) +} sr_time64_t; + +#define sr_time64 ((sr_time64_t *) _SR_ADDR(SR_TIME64)) + + +/*  + * --- ethernet tx protocol engine regs (write only) --- + * + * These registers control the transmit portion of the ethernet + * protocol engine (out of USRP2).  The protocol engine handles fifo + * status and sequence number insertion in outgoing packets, and + * automagically generates status packets when required to inform the + * host of changes in fifo availability. + * + * All outgoing packets have their fifo_status field set to the number + * of 32-bit lines of fifo available in the ethernet Rx fifo (see + * usrp2_eth_packet.h).  Seqno's are set if FIXME, else 0. + * + * FIXME clean this up once we know how it's supposed to behave. + */ + +typedef struct { +  volatile uint32_t  flags;	     // not yet fully defined (channel?) +  volatile uint32_t  mac_dst0123;    // 4 bytes of destination mac addr +  volatile uint32_t  mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr +  volatile uint32_t  mac_src2345;    // 4 bytes of destination mac addr +  volatile uint32_t  seqno;	     // Write to init seqno.  It autoincs on match +} tx_proto_engine_regs_t; + +#define tx_proto_engine ((tx_proto_engine_regs_t *) TX_PROTOCOL_ENGINE_BASE) + +/* + * --- ethernet rx protocol engine regs (write only) --- + * + * These registers control the receive portion of the ethernet + * protocol engine (into USRP2).  The protocol engine offloads common + * packet inspection operations so that firmware has less to do on + * "fast path" packets. + * + * The registers define conditions which must be matched for a packet + * to be considered a "fast path" packet.  If a received packet + * matches the src and dst mac address, ethertype, flags field, and + * expected seqno number it is considered a "fast path" packet, and + * the expected seqno is updated.  If the packet fails to satisfy any + * of the above conditions it's a "slow path" packet, and the + * corresponding SLOWPATH flag will be set buffer_status register. + */ + +typedef struct { +  volatile uint32_t  flags;	     // not yet fully defined (channel?) +  volatile uint32_t  mac_dst0123;    // 4 bytes of destination mac addr +  volatile uint32_t  mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr +  volatile uint32_t  mac_src2345;    // 4 bytes of destination mac addr +  volatile uint32_t  ethertype_pad;  // ethertype in high 16-bits +} rx_proto_engine_regs_t; + +#define rx_proto_engine ((rx_proto_engine_regs_t *) RX_PROTOCOL_ENGINE_BASE) + + + +/////////////////////////////////////////////////// +// Simple Programmable Interrupt Controller, Slave 8 + +#define PIC_BASE  0x3500 + +// Interrupt request lines +// Bit numbers (LSB == 0) that correpond to interrupts into PIC + +#define	IRQ_BUFFER	0	// buffer manager +#define	IRQ_ONETIME	1 +#define	IRQ_SPI		2 +#define	IRQ_I2C		3 +#define	IRQ_PHY		4	// ethernet PHY +#define	IRQ_UNDERRUN	5 +#define	IRQ_OVERRUN	6 +#define	IRQ_PPS		7	// pulse per second +#define	IRQ_UART_RX	8 +#define	IRQ_UART_TX	9 +#define	IRQ_SERDES	10 +#define	IRQ_CLKSTATUS	11 +#define IRQ_PERIODIC    12 +#define IRQ_BUTTON	13 + +#define IRQ_TO_MASK(x) (1 << (x)) + +#define PIC_BUFFER_INT    IRQ_TO_MASK(IRQ_BUFFER) +#define PIC_ONETIME_INT   IRQ_TO_MASK(IRQ_ONETIME) +#define PIC_SPI_INT       IRQ_TO_MASK(IRQ_SPI) +#define PIC_I2C_INT       IRQ_TO_MASK(IRQ_I2C) +#define PIC_PHY_INT       IRQ_TO_MASK(IRQ_PHY) +#define PIC_UNDERRUN_INT  IRQ_TO_MASK(IRQ_UNDERRUN) +#define PIC_OVERRUN_INT   IRQ_TO_MASK(IRQ_OVERRUN) +#define PIC_PPS_INT   	  IRQ_TO_MASK(IRQ_PPS) +#define PIC_UART_RX_INT   IRQ_TO_MASK(IRQ_UART_RX) +#define PIC_UART_TX_INT   IRQ_TO_MASK(IRQ_UART_TX) +#define PIC_SERDES        IRQ_TO_MASK(IRQ_SERDES) +#define PIC_CLKSTATUS     IRQ_TO_MASK(IRQ_CLKSTATUS) +#define PIC_BUTTON				IRQ_TO_MASK(IRQ_BUTTON) + +typedef struct { +  volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level +  volatile uint32_t polarity;	 // mask: 1 -> rising edge +  volatile uint32_t mask;	 // mask: 1 -> disabled +  volatile uint32_t pending;	 // mask: 1 -> pending; write 1's to clear pending ints +} pic_regs_t; + +#define pic_regs ((pic_regs_t *) PIC_BASE) + +// ---------------------------------------------------------------- +// WB_CLK_RATE is the time base for this +typedef struct { +  volatile uint32_t	onetime;   // Number of wb clk cycles till the onetime interrupt +  volatile uint32_t	periodic;  // Repeat rate of periodic interrupt +} sr_simple_timer_t; + +#define sr_simple_timer ((sr_simple_timer_t *) _SR_ADDR(SR_SIMTIMER)) + +/////////////////////////////////////////////////// +// UNUSED, Slave 9 + +/////////////////////////////////////////////////// +// UART, Slave 10 + +#define UART_BASE  0x3700 + +typedef struct { +  //  All elements are 8 bits except for clkdiv (16), but we use uint32 to make  +  //    the hardware for decoding easier +  volatile uint32_t clkdiv;  // Set to 50e6 divided by baud rate (no x16 factor) +  volatile uint32_t txlevel; // Number of spaces in the FIFO for writes +  volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads +  volatile uint32_t txchar;  // Write characters to be sent here +  volatile uint32_t rxchar;  // Read received characters here +  volatile uint32_t x[3]; //padding to reach 32B +} uart_regs_t; + +#define uart_regs ((uart_regs_t *) UART_BASE) + +/////////////////////////////////////////////////// +// ATR Controller, Slave 11 + +#define ATR_BASE  0x3800 + +typedef struct { +  volatile uint32_t	v[16]; +} atr_regs_t; + +#define	ATR_IDLE	0x0	// indicies into v +#define ATR_TX		0x1 +#define	ATR_RX		0x2 +#define	ATR_FULL	0x3 + +#define atr_regs ((atr_regs_t *) ATR_BASE) + +/////////////////////////////////////////////////// +// UNUSED, Slave 12 + +/////////////////////////////////////////////////// +// ICAP, Slave 13 + +#define ICAP_BASE 0x3A00 +typedef struct { +  uint32_t icap; //only the lower 8 bits matter +} icap_regs_t; + +#define icap_regs ((icap_regs_t *) ICAP_BASE) + +/////////////////////////////////////////////////// +// SPI Flash interface, Slave 14 +// Control register definitions are the same as SPI, so use SPI_CTRL_ASS, etc. +// Peripheral mask not needed since bus is dedicated (CE held low) + +#define SPIF_BASE 0x3B00 +typedef struct { +  volatile uint32_t	txrx0; +  volatile uint32_t	txrx1; +  volatile uint32_t	txrx2; +  volatile uint32_t	txrx3; +  volatile uint32_t	ctrl; +  volatile uint32_t	div; +  volatile uint32_t	ss; +} spif_regs_t; + +#define spif_regs ((spif_regs_t *) SPIF_BASE) + +//////////////////////////////////////////////////////////////// +// Main RAM, Slave 15 + +#define RAM_BASE 0x8000 + + + +/////////////////////////////////////////////////// +#endif + diff --git a/firmware/microblaze/usrp2p/spi_flash.c b/firmware/microblaze/usrp2p/spi_flash.c new file mode 100644 index 000000000..09b74a513 --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash.c @@ -0,0 +1,194 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "spi_flash_private.h" +//#include <stdlib.h> +#include <nonstdio.h> + +uint32_t +spi_flash_rdsr(void) +{ +  return spif_transact(SPI_TXRX, SPI_SS_FLASH, RDSR_CMD << 8, 16, FLAGS) & 0xff; +} + +static void +spi_flash_write_enable(void) +{ +//	spif_transact(SPI_TXONLY, SPI_SS_FLASH, (WRSR_CMD << 8) | 0x00, 16, FLAGS); //disable write protection bits +  spif_transact(SPI_TXONLY, SPI_SS_FLASH, WREN_CMD, 8, FLAGS); +} + +bool +spi_flash_done_p(void) +{ +  return (spi_flash_rdsr() & SR_WIP) == 0; +} + +void +spi_flash_wait(void) +{ +  while (!spi_flash_done_p()) +    ; +} + +void +spi_flash_erase_sector_start(uint32_t flash_addr) +{ +  //uprintf(UART_DEBUG, "spi_flash_erase_sector_start: addr = 0x%x\n", flash_addr); + +  spi_flash_wait(); +  spi_flash_write_enable(); +  spif_transact(SPI_TXONLY, SPI_SS_FLASH, +		(SE_CMD << 24) | (flash_addr & 0x00ffffff), +		32, FLAGS); +} + +bool +spi_flash_page_program_start(uint32_t flash_addr, size_t nbytes, const void *buf) +{ +  if (nbytes == 0 || nbytes > SPI_FLASH_PAGE_SIZE) +    return false; + +  uint32_t local_buf[SPI_FLASH_PAGE_SIZE / sizeof(uint32_t)]; +  memset(local_buf, 0xff, sizeof(local_buf));	// init to 0xff (nops when programming) +  memcpy(local_buf, buf, nbytes); + +  spi_flash_wait(); +  spi_flash_write_enable(); +   +  /* +   * We explicitly control the slave select here (/S), so that we can +   * do the entire write operation as a single transaction from +   * device's point of view.  (The most our SPI peripheral can transfer +   * in a single shot is 16 bytes.) +   */ +  spif_wait(); + +  spif_regs->ss = 0; +  spif_regs->ctrl = FLAGS;	// ASS is now clear and no chip select is enabled. +   +  /* write PP_CMD, ADDR2, ADDR1, ADDR0 */ + +  spif_regs->txrx0 = (PP_CMD << 24) | (flash_addr & 0x00ffffff); +  spif_regs->ss = SPI_SS_FLASH;		// assert chip select +  spif_regs->ctrl = FLAGS | LEN(4 * 8);		 +  spif_regs->ctrl = FLAGS | LEN(4 * 8) | SPI_CTRL_GO_BSY; +  spif_wait(); + +  /*  send 256 bytes total, 16 at a time */ +  for (size_t i = 0; i < 16; i++){ +    spif_regs->txrx3 = local_buf[i * 4 + 0]; +    spif_regs->txrx2 = local_buf[i * 4 + 1]; +    spif_regs->txrx1 = local_buf[i * 4 + 2]; +    spif_regs->txrx0 = local_buf[i * 4 + 3]; +     +    spif_regs->ctrl = FLAGS | LEN(16 * 8);	// xfer 16 bytes +    spif_regs->ctrl = FLAGS | LEN(16 * 8) | SPI_CTRL_GO_BSY; +    spif_wait(); +  } +  spif_regs->ss = 0;		// desassert chip select + +  return true; +} + +void +spi_flash_erase(uint32_t flash_addr, size_t nbytes) +{ +  if (nbytes == 0) +    return; + +  uint32_t first = round_down(flash_addr, spi_flash_sector_size()); +  uint32_t last  = round_down(flash_addr + nbytes - 1, spi_flash_sector_size()); +   +  for (uint32_t s = first; s <= last; s += spi_flash_sector_size()){ +    spi_flash_erase_sector_start(s); +  } +  spi_flash_wait(); +} + +bool +spi_flash_program(uint32_t flash_addr, size_t nbytes, const void *buf) +{ +  //uprintf(UART_DEBUG, "\nspi_flash_program: addr = 0x%x, nbytes = %d\n", flash_addr, nbytes); + +  const unsigned char *p = (const unsigned char *) buf; +  size_t n; + +  if (nbytes == 0) +    return true; + +  uint32_t r = flash_addr % SPI_FLASH_PAGE_SIZE; +  if (r){	/* do initial non-aligned page */ +    n = min(SPI_FLASH_PAGE_SIZE - r, nbytes); +    spi_flash_page_program_start(flash_addr, n, p); +    flash_addr += n; +    p += n; +    nbytes -= n; +  } + +  while (nbytes > 0){ +    n = min(SPI_FLASH_PAGE_SIZE, nbytes); +    spi_flash_page_program_start(flash_addr, n, p); +    flash_addr += n; +    p += n; +    nbytes -= n; +  } + +  spi_flash_wait(); +  return true; +} + +void +spi_flash_async_erase_start(spi_flash_async_state_t *s, +			    uint32_t flash_addr, size_t nbytes) +{ +  if (nbytes == 0){ +    s->first = s->last = s->current = 0; +    return; +  } + +  uint32_t first = round_down(flash_addr, spi_flash_sector_size()); +  uint32_t last  = round_down(flash_addr + nbytes - 1, spi_flash_sector_size()); + +  s->first = first; +  s->last = last; +  s->current = first; + +  spi_flash_erase_sector_start(s->current); +} + +bool +spi_flash_async_erase_poll(spi_flash_async_state_t *s) +{ +  if (!spi_flash_done_p()) +    return false; + +  //printf("%d/%d\n", s->current, s->last); + +  // The current sector erase has completed.  See if we're finished or +  // if there's more to do. + +  if (s->current == s->last)	// we're done! +    return true; + +  s->current += spi_flash_sector_size(); +  spi_flash_erase_sector_start(s->current); +  return false; +} + diff --git a/firmware/microblaze/usrp2p/spi_flash.h b/firmware/microblaze/usrp2p/spi_flash.h new file mode 100644 index 000000000..bbe7b650d --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash.h @@ -0,0 +1,119 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_SPI_FLASH_H +#define INCLUDED_SPI_FLASH_H + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + + +#define SPI_FLASH_PAGE_SIZE	256 +#define SPI_SS_FLASH 1 + + +uint32_t spi_flash_rdid(void);	/* Read ID */ +uint32_t spi_flash_rdsr(void);	/* Read Status Register */ +size_t spi_flash_log2_sector_size(void) __attribute__((pure));  /* either 16 or 18 */ +size_t spi_flash_log2_memory_size(void); + +static inline size_t +spi_flash_sector_size(void) +{ +  return ((size_t) 1) << spi_flash_log2_sector_size(); +} + +static inline size_t +spi_flash_memory_size(void) +{ +  return ((size_t) 1) << spi_flash_log2_memory_size(); +} + +void spi_flash_read(uint32_t flash_addr,  size_t nbytes, void *buf); + +/* + * Erase all sectors that fall within the interval [flash_addr, flash_addr + nbytes). + * Erasing sets the memory to ones. + */ +void spi_flash_erase(uint32_t flash_addr, size_t nbytes); + +/* + * Program the flash. + * The area must have been erased prior to programming. + */ +bool spi_flash_program(uint32_t flash_addr, size_t nbytes, const void *buf); + +/* + * --- asynchronous routines --- + */ + +/* + * Is the erasing or programming done? + */ +bool spi_flash_done_p(void); + +/* + * Wait for erasing or programming to complete + */ +void spi_flash_wait(void); + +/* + * Start the erase process on a single sector. + * (It takes between 1 and 3 seconds to erase a 64KB sector) + */ +void spi_flash_erase_sector_start(uint32_t flash_addr); + +/* + * Start the programming process within a single page. + * nbytes must be between 1 and 256. + * (It takes between 1.4 and 5 ms to program a page -> 640 ms for 64KB) + */ +bool spi_flash_page_program_start(uint32_t flash_addr, size_t nbytes, const void *buf); + + +/* + * --- high-level async erase --- + */ + +typedef struct { +  uint32_t	first; +  uint32_t	last; +  uint32_t	current; +} spi_flash_async_state_t; + +/* + * Start to erase all sectors that fall within the interval [flash_addr, flash_addr + nbytes). + * Erasing sets the memory to ones. + * + * Initializes s and begins the process.  Call spi_flash_async_erase_poll + * to test for completion and advance state machine. + */ +void spi_flash_async_erase_start(spi_flash_async_state_t *s, +				 uint32_t flash_addr, size_t nbytes); + +/* + * Poll for aysnc flash erase completion. + * Returns true when the erase has completed. + * (This should be called at something >= 4 Hz.  It takes 1 to 3 seconds to + * erase each 64KB sector). + */ +bool spi_flash_async_erase_poll(spi_flash_async_state_t *s); + + +#endif /* INCLUDED_SPI_FLASH_H */ diff --git a/firmware/microblaze/usrp2p/spi_flash_private.h b/firmware/microblaze/usrp2p/spi_flash_private.h new file mode 100644 index 000000000..9a1b8d3e3 --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash_private.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_SPI_FLASH_PRIVATE_H +#define INCLUDED_SPI_FLASH_PRIVATE_H + +#include "spi_flash.h" +#include "spi.h" +#include "memory_map.h" +#include <string.h> + + +/* M25P64 et al. */ + +#define	WREN_CMD	0x06	// write enable +#define	WRDI_CMD	0x04	// write disable +#define	RDID_CMD	0x9f	// read identification +#define	RDSR_CMD	0x05	// read status register +#define WRSR_CMD	0x01	// write status register +#define	READ_CMD	0x03 +#define	FAST_READ_CMD	0x0b +#define	PP_CMD		0x02	// page program (256 bytes) +#define	SE_CMD		0xd8	// sector erase (64KB) +#define	BE_CMD		0xc7	// bulk erase (all) +#define	RES_CMD		0xab	// read electronic sig (deprecated) + +/* Status register bits */ + +#define	SR_SRWD		0x80 +#define	SR_BP2		0x10	// block protect bit 2 +#define	SR_BP1		0x08	// block protect bit 1 +#define	SR_BP0		0x04	// block protect bit 0 +#define	SR_WEL		0x02	// Write Enable Latch +#define	SR_WIP		0x01	// Write in Progress.  Set if busy w/ program or erase cycle. + + +#define	FLAGS (SPIF_PUSH_FALL | SPIF_LATCH_RISE) + +#define LEN(x) ((x) & SPI_CTRL_CHAR_LEN_MASK) + + +static inline uint32_t +min(uint32_t a, uint32_t b) +{ +  return a < b ? a : b; +} + +static inline uint32_t +round_down(uint32_t x, uint32_t power_of_2) +{ +  return x & -power_of_2; +} + +#endif /* INCLUDED_SPI_FLASH_PRIVATE_H */ diff --git a/firmware/microblaze/usrp2p/spi_flash_read.c b/firmware/microblaze/usrp2p/spi_flash_read.c new file mode 100644 index 000000000..4682c5fe6 --- /dev/null +++ b/firmware/microblaze/usrp2p/spi_flash_read.c @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "spi_flash_private.h" +#include <stdlib.h>		// abort + +static size_t _spi_flash_log2_memory_size; + +uint32_t  +spi_flash_rdid(void) +{ +  return spif_transact(SPI_TXRX, SPI_SS_FLASH, RDID_CMD << 24, 32, FLAGS) & 0xffffff; +} + +size_t  +spi_flash_log2_sector_size(void) +{ +  static size_t _spi_flash_log2_sector_size; + +  if (_spi_flash_log2_sector_size != 0) +    return _spi_flash_log2_sector_size; + +   +  uint32_t id = spi_flash_rdid(); +  int type = (id >> 8) & 0xff; +  int size = id & 0xff; +  if (type != 0x20 || size < 22 || size > 24) +    abort(); + +  static unsigned char log2_sector_size[3] = { +    16,	/* M25P32  */ +    16, /* M25P64  */ +    18, /* M25P128 */ +  }; + +  _spi_flash_log2_sector_size = log2_sector_size[size - 22]; +  _spi_flash_log2_memory_size = size; //while we're at it +  return _spi_flash_log2_sector_size; +} + +size_t +spi_flash_log2_memory_size(void) +{ +  if (_spi_flash_log2_memory_size != 0) +    return _spi_flash_log2_memory_size; + +  uint32_t id = spi_flash_rdid(); +  int type = (id >> 8) & 0xff; +  int size = id & 0xff; +  if (type != 0x20 || size < 22 || size > 24) +    abort(); + +  _spi_flash_log2_memory_size = size; +  return _spi_flash_log2_memory_size; +} + +void  +spi_flash_read(uint32_t flash_addr,  size_t nbytes, void *buf) +{ +  /* +   * We explicitly control the slave select here (/S), so that we can +   * do the entire read operation as a single transaction from +   * device's point of view.  (The most our SPI peripheral can transfer +   * in a single shot is 16 bytes.) +   */ +  spif_wait(); + +  spif_regs->ss = 0; +  spif_regs->ctrl = FLAGS;	// ASS is now clear and no chip select is enabled. +   +  /* +   * Do the 5 byte instruction tranfer: +   *   FAST_READ_CMD, ADDR2, ADDR1, ADDR0, DUMMY +   */ +  spif_regs->txrx1 = FAST_READ_CMD; +  spif_regs->txrx0 = ((flash_addr & 0x00ffffff) << 8); +  spif_regs->ss = SPI_SS_FLASH;		// assert chip select +  spif_regs->ctrl = FLAGS | LEN(5 * 8);		 +  spif_regs->ctrl = FLAGS | LEN(5 * 8) | SPI_CTRL_GO_BSY; +  spif_wait(); + +  /* +   * Read up to 16 bytes at a time until done +   */ +  unsigned char *dst = (unsigned char *) buf; +  size_t m; +  for (size_t n = 0; n < nbytes; n += m, dst += m){ +    spif_regs->ctrl = FLAGS | LEN(16 * 8);	// xfer 16 bytes +    spif_regs->ctrl = FLAGS | LEN(16 * 8) | SPI_CTRL_GO_BSY; +    spif_wait(); + +    uint32_t w[4]; +    w[0] = spif_regs->txrx3;	// txrx3 has first bits in it +    w[1] = spif_regs->txrx2; +    w[2] = spif_regs->txrx1; +    w[3] = spif_regs->txrx0; +    unsigned char *src = (unsigned char *) &w[0]; +    m = min(nbytes - n, 16); +    for (size_t i = 0; i < m; i++) +      dst[i] = src[i]; +  } +  spif_regs->ss = 0;			// deassert chip select +} diff --git a/firmware/microblaze/usrp2p/spif.c b/firmware/microblaze/usrp2p/spif.c new file mode 100644 index 000000000..1c1a348f4 --- /dev/null +++ b/firmware/microblaze/usrp2p/spif.c @@ -0,0 +1,68 @@ +/* + * Copyright 2007,2008,2009 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Code for the Flash SPI bus + */ + +#include "spi.h" +#include "memory_map.h" + +void +spif_init(void)  +{ +  /* +   * f_sclk = f_wb / ((div + 1) * 2) +   */ +  spif_regs->div = 1;  // 0 = Div by 2 (31.25 MHz); 1 = Div-by-4 (15.625 MHz) + +  // run dummy transaction to work around invalid initial clock state +  spif_transact(SPI_TXONLY, 0, 0, 8, SPIF_PUSH_FALL | SPIF_LATCH_RISE); +} + +inline void +spif_wait(void)  +{ +  while (spif_regs->ctrl & SPI_CTRL_GO_BSY) +    ; +} + +uint32_t +spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags)  +{ +  flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); +  int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; + +  spif_wait(); + +  // Data we will send +  spif_regs->txrx0 = data; + +  // Run it -- write once and rewrite with GO set +  spif_regs->ctrl = ctrl; +  // Tell it which SPI slave device to access +  spif_regs->ss = slave & 0xff; +  spif_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; + +  if(readback_) { +    spif_wait(); +    return spif_regs->txrx0; +  } +  else +    return 0; +} diff --git a/firmware/microblaze/usrp2p/udp_fw_update.c b/firmware/microblaze/usrp2p/udp_fw_update.c new file mode 100644 index 000000000..ead08ad2c --- /dev/null +++ b/firmware/microblaze/usrp2p/udp_fw_update.c @@ -0,0 +1,108 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +//Routines to handle updating the SPI Flash firmware via UDP + +#include <net_common.h> +#include "usrp2/fw_common.h" +#include "spi.h" +#include "spi_flash.h" +#include <nonstdio.h> +#include <string.h> +#include "ethernet.h" +#include "udp_fw_update.h" +#include "xilinx_s3_icap.h" + +//Firmware update packet handler +void handle_udp_fw_update_packet(struct socket_address src, struct socket_address dst, +                                 unsigned char *payload, int payload_len) { + +  const usrp2_fw_update_data_t *update_data_in = (usrp2_fw_update_data_t *) payload; + +  usrp2_fw_update_data_t update_data_out; +  usrp2_fw_update_id_t update_data_in_id = update_data_in->id; + +  //ensure that the protocol versions match +/*  if (payload_len >= sizeof(uint32_t) && update_data_in->proto_ver != USRP2_FW_COMPAT_NUM){ +    printf("!Error in update packet handler: Expected compatibility number %d, but got %d\n", +        USRP2_FW_COMPAT_NUM, update_data_in->proto_ver +      ); +      update_data_in_id = USRP2_FW_UPDATE_ID_OHAI_LOL; //so we can respond +  } +*/ +  //ensure that this is not a short packet +  if (payload_len < sizeof(usrp2_fw_update_data_t)){ +      printf("!Error in update packet handler: Expected payload length %d, but got %d\n", +          (int)sizeof(usrp2_fw_update_data_t), payload_len +      ); +      update_data_in_id = USRP2_FW_UPDATE_ID_WAT; +  } + +  spi_flash_async_state_t spi_flash_async_state; + +  switch(update_data_in_id) { +  case USRP2_FW_UPDATE_ID_OHAI_LOL: //why hello there you handsome devil +    update_data_out.id = USRP2_FW_UPDATE_ID_OHAI_OMG; +    memcpy(&update_data_out.data.ip_addr, (void *)get_ip_addr(), sizeof(struct ip_addr)); +    break; + +  case USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL: //query sector size, memory size so the host can mind the boundaries +    update_data_out.data.flash_info_args.sector_size_bytes = spi_flash_sector_size(); +    update_data_out.data.flash_info_args.memory_size_bytes = spi_flash_memory_size(); +    update_data_out.id = USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG; +    break; + +  case USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL: //out with the old +    spi_flash_async_erase_start(&spi_flash_async_state, update_data_in->data.flash_args.flash_addr, update_data_in->data.flash_args.length); +    update_data_out.id = USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG; +    break; + +  case USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL: +    //poll for done, set something in the reply packet +    //spi_flash_async_erase_poll() also advances the state machine, so you should call it reasonably often to get things done quicker +    if(spi_flash_async_erase_poll(&spi_flash_async_state)) update_data_out.id = USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG; +    else update_data_out.id = USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG; +    break; + +  case USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL: //and in with the new +    //spi_flash_program() goes pretty quick compared to page erases, so we don't bother polling -- it'll come back in some milliseconds +    //if it doesn't come back fast enough, we'll just write smaller packets at a time until it does +    spi_flash_program(update_data_in->data.flash_args.flash_addr, update_data_in->data.flash_args.length, update_data_in->data.flash_args.data); +    update_data_out.id = USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG; +    break; + +  case USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL: //for verify +    spi_flash_read(update_data_in->data.flash_args.flash_addr,  update_data_in->data.flash_args.length, update_data_out.data.flash_args.data); +    update_data_out.id = USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG; +    break; + +  case USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL: //for if we ever get the ICAP working +    //should reset via icap_reload_fpga(uint32_t flash_address); +    update_data_out.id = USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG; +    //you should note that if you get a reply packet to this the reset has obviously failed +    icap_reload_fpga(0); +    break; + +//  case USRP2_FW_UPDATE_ID_KTHXBAI: //see ya +//    break; + +  default: //uhhhh +    update_data_out.id = USRP2_FW_UPDATE_ID_WAT; +  } +  send_udp_pkt(USRP2_UDP_UPDATE_PORT, src, &update_data_out, sizeof(update_data_out)); +} diff --git a/firmware/microblaze/usrp2p/xilinx_s3_icap.c b/firmware/microblaze/usrp2p/xilinx_s3_icap.c new file mode 100644 index 000000000..50c85231c --- /dev/null +++ b/firmware/microblaze/usrp2p/xilinx_s3_icap.c @@ -0,0 +1,99 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + + +/* Changes required to work for the Spartan-3A series: + * The ICAP interface on the 3A is 8 bits wide, instead of 32. + * Everything is Xilinx standard LSBit-first. + * The operations are all different. + * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time. +*/ + +#include <xilinx_s3_icap.h> +#include <memory_map.h> +#include <spi_flash_private.h> //for READ_CMD + + +/* bit swap end-for-end */ +static inline unsigned char +swap8(unsigned char x) +{ +  unsigned char r = 0; +  r |= (x >> 7) & 0x01; +  r |= (x >> 5) & 0x02; +  r |= (x >> 3) & 0x04; +  r |= (x >> 1) & 0x08; + +  r |= (x << 1) & 0x10; +  r |= (x << 3) & 0x20; +  r |= (x << 5) & 0x40; +  r |= (x << 7) & 0x80; + +  return r; +} + +void +wr_icap(uint8_t x) +{ +    icap_regs->icap = swap8(x); +} + +uint8_t +rd_icap(void) +{ +    return swap8(icap_regs->icap); +} + + +void +icap_reload_fpga(uint32_t flash_address) +{ +    union { +        uint32_t i; +        uint8_t c[4]; +    } t; +    t.i = flash_address; + +    //note! t.c[0] MUST contain the byte-wide read command for the flash device used. +    //for the 25P64, and most other flash devices, this is 0x03. +    t.c[0] = FAST_READ_CMD; + +    //TODO: look up the watchdog timer, ensure it won't fire too soon + +    //UG332 p279 +    wr_icap(0xff); +    wr_icap(0xff); //dummy word, probably unnecessary +    wr_icap(0xAA); +    wr_icap(0x99); //sync word +    wr_icap(0x32); +    wr_icap(0x61); //Type 1 write General 1 (1 word) +    wr_icap(t.c[2]); //bits 15-8 +    wr_icap(t.c[3]); //bits 7-0 +    wr_icap(0x32); +    wr_icap(0x81); //Type 1 write General 2 (1 word) +    wr_icap(t.c[0]); //C0-C8, the byte-wide read command +    wr_icap(t.c[1]); //Upper 8 bits of 24-bit address +    wr_icap(0x30); +    wr_icap(0xA1); //Type 1 write CMD (1 word) +    wr_icap(0x00); +    wr_icap(0x0E); //REBOOT command +    wr_icap(0x20); +    wr_icap(0x00); //Type 1 NOP +    wr_icap(0x20); +    wr_icap(0x00); +} diff --git a/firmware/microblaze/usrp2p/xilinx_s3_icap.h b/firmware/microblaze/usrp2p/xilinx_s3_icap.h new file mode 100644 index 000000000..7b7e9eccc --- /dev/null +++ b/firmware/microblaze/usrp2p/xilinx_s3_icap.h @@ -0,0 +1,37 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_XILINX_S3_ICAP_H +#define INCLUDED_XILINX_S3_ICAP_H + +#include <stdint.h> + + +void wr_icap(uint8_t x); +uint8_t rd_icap(void); + +//int icap_read_config_reg(int regno); + +/* + * Attempt to reload the fpga from \p flash_address. + * Shouldn't return, but might. + */ +void icap_reload_fpga(uint32_t flash_address); + + +#endif /* INCLUDED_XILINX_S3_ICAP_H */  | 
